fix(api): align dart/js APIs
This commit is contained in:
parent
577ee3744a
commit
af2cd4d6f3
|
@ -5,4 +5,10 @@ library angular2;
|
|||
*
|
||||
* This library does not include `bootstrap`. Import `bootstrap.dart` instead.
|
||||
*/
|
||||
export 'package:angular2/core.dart';
|
||||
export 'package:angular2/core.dart' hide forwardRef, resolveForwardRef, ForwardRefFn;
|
||||
export 'package:angular2/profile.dart';
|
||||
export 'package:angular2/lifecycle_hooks.dart';
|
||||
export 'package:angular2/src/core/application_ref.dart';
|
||||
export 'package:angular2/src/core/application_tokens.dart' hide APP_COMPONENT_REF_PROMISE;
|
||||
export 'package:angular2/src/core/render/dom/dom_tokens.dart' hide APP_ID_RANDOM_BINDING;
|
||||
export 'package:angular2/src/core/render/dom/dom_tokens.dart' hide APP_ID_RANDOM_BINDING;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
library angular2.core;
|
||||
|
||||
// Public Core API
|
||||
export 'package:angular2/src/core/metadata.dart';
|
||||
export 'package:angular2/src/core/util.dart';
|
||||
export 'package:angular2/src/core/di.dart';
|
||||
export 'package:angular2/src/core/pipes.dart';
|
||||
|
@ -12,11 +13,8 @@ export 'package:angular2/src/core/services.dart';
|
|||
export 'package:angular2/src/core/compiler.dart';
|
||||
export 'package:angular2/src/core/lifecycle.dart';
|
||||
export 'package:angular2/src/core/zone.dart';
|
||||
//Do not export render for dart. Must import from angular2/render
|
||||
//export 'package:angular2/src/core/render.dart';
|
||||
export 'package:angular2/src/core/render.dart';
|
||||
export 'package:angular2/src/core/directives.dart';
|
||||
export 'package:angular2/src/core/forms.dart';
|
||||
//Do not export debug for dart.
|
||||
//export 'package:angular2/src/core/debug.dart';
|
||||
export 'package:angular2/src/core/metadata.dart';
|
||||
export 'package:angular2/src/core/debug.dart';
|
||||
export 'package:angular2/src/core/change_detection.dart';
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
// Public API for Application
|
||||
export {APP_COMPONENT} from './application_tokens';
|
||||
export {platform, commonBootstrap as bootstrap} from './application_common';
|
||||
export {PlatformRef, ApplicationRef} from './application_ref';
|
||||
export {
|
||||
PlatformRef,
|
||||
ApplicationRef,
|
||||
applicationCommonBindings,
|
||||
createNgZone,
|
||||
platformCommon,
|
||||
platformBindings
|
||||
} from './application_ref';
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
library angular2.src.core.directives;
|
||||
|
||||
export './directives/ng_class.dart';
|
||||
export './directives/ng_for.dart';
|
||||
export './directives/ng_if.dart';
|
||||
export './directives/ng_non_bindable.dart';
|
||||
export './directives/ng_style.dart';
|
||||
export './directives/ng_switch.dart';
|
||||
|
||||
//Dart Only
|
||||
export './directives/observable_list_diff.dart';
|
|
@ -12,12 +12,14 @@ import {NgNonBindable} from './directives/ng_non_bindable';
|
|||
import {NgStyle} from './directives/ng_style';
|
||||
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
|
||||
|
||||
export * from './directives/ng_class';
|
||||
export * from './directives/ng_for';
|
||||
export * from './directives/ng_if';
|
||||
export * from './directives/ng_non_bindable';
|
||||
export * from './directives/ng_style';
|
||||
export * from './directives/ng_switch';
|
||||
export {NgClass} from './directives/ng_class';
|
||||
export {NgFor} from './directives/ng_for';
|
||||
export {NgIf} from './directives/ng_if';
|
||||
export {NgNonBindable} from './directives/ng_non_bindable';
|
||||
export {NgStyle} from './directives/ng_style';
|
||||
export {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
|
||||
export * from './directives/observable_list_diff';
|
||||
|
||||
|
||||
/**
|
||||
* A collection of the Angular core directives that are likely to be used in each and every Angular
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
// TS does not have Observables
|
||||
|
||||
// I need to be here to make TypeScript think this is a module.
|
||||
import {} from 'angular2/src/core/facade/lang';
|
|
@ -9,7 +9,7 @@ export const DOCUMENT: OpaqueToken = CONST_EXPR(new OpaqueToken('DocumentToken')
|
|||
export const APP_ID: OpaqueToken = CONST_EXPR(new OpaqueToken('AppId'));
|
||||
|
||||
function _appIdRandomBindingFactory() {
|
||||
return `${randomChar()}${randomChar()}${randomChar()}`;
|
||||
return `${_randomChar()}${_randomChar()}${_randomChar()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,6 +25,6 @@ export const APP_ID_RANDOM_BINDING: Binding =
|
|||
export const MAX_IN_MEMORY_ELEMENTS_PER_TEMPLATE: OpaqueToken =
|
||||
CONST_EXPR(new OpaqueToken('MaxInMemoryElementsPerTemplate'));
|
||||
|
||||
function randomChar(): string {
|
||||
function _randomChar(): string {
|
||||
return StringWrapper.fromCharCode(97 + Math.floor(Math.random() * 25));
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
// ignore in dart
|
||||
main() {}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
|||
// A library for the symbol inspector test
|
||||
|
||||
export class A {
|
||||
constructor(b: ConsParamType) {}
|
||||
|
||||
field: FieldType;
|
||||
get getter(): GetterType { return null; }
|
||||
|
||||
method(p: ParamType): MethodReturnType { return null; }
|
||||
|
||||
methodWithFunc(closure: ClosureReturn) {}
|
||||
|
||||
static staticField: StaticFieldType = null;
|
||||
static staticMethod() {}
|
||||
}
|
||||
|
||||
export class ConsParamType {}
|
||||
export class FieldType {}
|
||||
export class GetterType {}
|
||||
export class MethodReturnType {}
|
||||
export class ParamType {}
|
||||
export class StaticFieldType {}
|
||||
|
||||
export class ClosureReturn {}
|
||||
export class ClosureParam {}
|
||||
|
||||
export class TypedefReturnType {}
|
||||
export class TypedefParam {}
|
||||
|
||||
|
||||
export class Generic<K> { // Generic should be exported, but not K.
|
||||
get getter(): K { return null; }
|
||||
}
|
||||
|
||||
export interface SomeInterface { someMethod(); }
|
|
@ -0,0 +1,68 @@
|
|||
import {StringWrapper, RegExpWrapper, isJsObject} from 'angular2/src/core/facade/lang';
|
||||
|
||||
var IS_FIELD = RegExpWrapper.create('^\\w+[\\.|\\#]\\w+=?$');
|
||||
var IS_INTERFACE = RegExpWrapper.create('^\\{\\w+\\}');
|
||||
var IS_DART = RegExpWrapper.create('\\:dart$');
|
||||
var IS_JS = RegExpWrapper.create('\\:js$');
|
||||
var IS_OPTIONAL = RegExpWrapper.create('\\:optional$');
|
||||
var JS = 'JS';
|
||||
var DART = 'Dart';
|
||||
var MODE = isJsObject({}) ? JS : DART;
|
||||
|
||||
export class SymbolsDiff {
|
||||
missing: string[] = [];
|
||||
extra: string[] = [];
|
||||
errors: string[] = [];
|
||||
|
||||
constructor(public actual: string[], public expected: string[]) {
|
||||
this.actual.sort(compareIgnoreLang);
|
||||
this.expected.sort(compareIgnoreLang);
|
||||
this.computeDiff();
|
||||
}
|
||||
|
||||
computeDiff(): void {
|
||||
for (var i = 0, j = 0, length = this.expected.length + this.actual.length; i + j < length;) {
|
||||
var expectedName: string = i < this.expected.length ? this.expected[i] : '~';
|
||||
var actualName: string = j < this.actual.length ? this.actual[j] : '~';
|
||||
if (stripLang(expectedName) == stripLang(actualName)) {
|
||||
i++;
|
||||
j++;
|
||||
} else if (StringWrapper.compare(stripLang(expectedName), stripLang(actualName)) > 0) {
|
||||
// JS does not see fields so ignore none method symbols
|
||||
if (!this.shouldIgnore(expectedName)) {
|
||||
this.extra.push(actualName);
|
||||
this.errors.push('+ ' + actualName);
|
||||
}
|
||||
j++;
|
||||
} else {
|
||||
if (!this.shouldIgnore(expectedName)) {
|
||||
this.missing.push(expectedName);
|
||||
this.errors.push('- ' + expectedName);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shouldIgnore(expected: string): boolean {
|
||||
var ignore = false;
|
||||
if (MODE == JS) {
|
||||
ignore = RegExpWrapper.test(IS_FIELD, expected) ||
|
||||
RegExpWrapper.test(IS_INTERFACE, expected) ||
|
||||
RegExpWrapper.test(IS_DART, expected) || RegExpWrapper.test(IS_OPTIONAL, expected)
|
||||
} else {
|
||||
ignore = RegExpWrapper.test(IS_JS, expected) || RegExpWrapper.test(IS_OPTIONAL, expected)
|
||||
}
|
||||
return ignore;
|
||||
}
|
||||
}
|
||||
|
||||
function stripLang(text: string): string {
|
||||
var index = text.indexOf(':');
|
||||
if (index >= 0) text = text.substring(0, index);
|
||||
return text;
|
||||
}
|
||||
|
||||
function compareIgnoreLang(a: string, b: string): number {
|
||||
return StringWrapper.compare(stripLang(a), stripLang(b));
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
library angular.symbol_inspector.symbol_inspector;
|
||||
|
||||
import 'dart:mirrors';
|
||||
import './simple_library.dart' as simple_library;
|
||||
import 'package:angular2/angular2.dart' as angular2;
|
||||
|
||||
const IGNORE = const {
|
||||
'runtimeType': true,
|
||||
'toString': true,
|
||||
'noSuchMethod': true,
|
||||
'hashCode': true,
|
||||
'originalException': true,
|
||||
'originalStack': true
|
||||
};
|
||||
|
||||
const LIB_MAP = const {
|
||||
'simple_library': 'angular2.test.symbol_inspector.simple_library',
|
||||
'ng': 'angular2'
|
||||
};
|
||||
|
||||
// Have this list here to trick dart to force import.
|
||||
var libs = [simple_library.A, angular2.Component];
|
||||
|
||||
List<String> getSymbolsFromLibrary(String name) {
|
||||
var libraryName = LIB_MAP[name];
|
||||
if (libs.isEmpty) throw "No libriries loaded.";
|
||||
if (libraryName == null) throw "Don't know how to load '$name' library.";
|
||||
var lib = currentMirrorSystem().findLibrary(new Symbol(libraryName));
|
||||
var names = [];
|
||||
extractSymbols(lib).addTo(names);
|
||||
names.sort();
|
||||
// remove duplicates;
|
||||
var lastValue;
|
||||
names = names.where((v) {
|
||||
var duplicate = v == lastValue;
|
||||
lastValue = v;
|
||||
return !duplicate;
|
||||
}).toList();
|
||||
return names;
|
||||
}
|
||||
|
||||
class ExportedSymbol {
|
||||
Symbol symbol;
|
||||
DeclarationMirror declaration;
|
||||
LibraryMirror library;
|
||||
|
||||
ExportedSymbol(this.symbol, this.declaration, this.library);
|
||||
|
||||
addTo(List<String> names) {
|
||||
var name = unwrapSymbol(symbol);
|
||||
if (declaration is MethodMirror) {
|
||||
names.add('$name()');
|
||||
} else if (declaration is ClassMirror) {
|
||||
var classMirror = declaration as ClassMirror;
|
||||
if (classMirror.isAbstract) name = '{$name}';
|
||||
names.add(name);
|
||||
classMirror.staticMembers.forEach(members('$name#', names));
|
||||
classMirror.instanceMembers.forEach(members('$name.', names));
|
||||
} else if (declaration is TypedefMirror) {
|
||||
names.add(name);
|
||||
} else if (declaration is VariableMirror) {
|
||||
names.add(name);
|
||||
} else {
|
||||
throw 'UNEXPECTED: $declaration';
|
||||
}
|
||||
}
|
||||
|
||||
toString() => unwrapSymbol(symbol);
|
||||
}
|
||||
|
||||
members(String prefix, List<String> names) {
|
||||
return (Symbol symbol, MethodMirror method) {
|
||||
var name = unwrapSymbol(symbol);
|
||||
if (method.isOperator || method.isPrivate || IGNORE[name] == true) return;
|
||||
var suffix = (method.isSetter || method.isGetter) ? '' : '()';
|
||||
names.add('$prefix$name$suffix');
|
||||
};
|
||||
}
|
||||
|
||||
class LibraryInfo {
|
||||
List<ExportedSymbol> names;
|
||||
Map<Symbol, List<Symbol>> symbolsUsedForName;
|
||||
|
||||
LibraryInfo(this.names, this.symbolsUsedForName);
|
||||
|
||||
addTo(List<String> names) {
|
||||
this.names.forEach((ExportedSymbol es) => es.addTo(names));
|
||||
//this.names.addAll(symbolsUsedForName.keys.map(unwrapSymbol));
|
||||
}
|
||||
}
|
||||
|
||||
Iterable<Symbol> _getUsedSymbols(DeclarationMirror decl, seenDecls, path, onlyType) {
|
||||
|
||||
if (seenDecls.containsKey(decl.qualifiedName)) return [];
|
||||
seenDecls[decl.qualifiedName] = true;
|
||||
|
||||
if (decl.isPrivate) return [];
|
||||
|
||||
path = "$path -> $decl";
|
||||
|
||||
var used = [];
|
||||
|
||||
if (decl is TypedefMirror) {
|
||||
TypedefMirror tddecl = decl;
|
||||
used.addAll(_getUsedSymbols(tddecl.referent, seenDecls, path, onlyType));
|
||||
}
|
||||
if (decl is FunctionTypeMirror) {
|
||||
FunctionTypeMirror ftdecl = decl;
|
||||
|
||||
ftdecl.parameters.forEach((ParameterMirror p) {
|
||||
used.addAll(_getUsedSymbols(p.type, seenDecls, path, onlyType));
|
||||
});
|
||||
used.addAll(_getUsedSymbols(ftdecl.returnType, seenDecls, path, onlyType));
|
||||
}
|
||||
else if (decl is TypeMirror) {
|
||||
var tdecl = decl;
|
||||
used.add(tdecl.qualifiedName);
|
||||
}
|
||||
|
||||
|
||||
if (!onlyType) {
|
||||
if (decl is ClassMirror) {
|
||||
ClassMirror cdecl = decl;
|
||||
cdecl.declarations.forEach((s, d) {
|
||||
try {
|
||||
used.addAll(_getUsedSymbols(d, seenDecls, path, false));
|
||||
} catch (e, s) {
|
||||
print("Got error [$e] when visiting $d\n$s");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (decl is MethodMirror) {
|
||||
MethodMirror mdecl = decl;
|
||||
if (mdecl.parameters != null)
|
||||
mdecl.parameters.forEach((p) {
|
||||
used.addAll(_getUsedSymbols(p.type, seenDecls, path, true));
|
||||
});
|
||||
used.addAll(_getUsedSymbols(mdecl.returnType, seenDecls, path, true));
|
||||
}
|
||||
|
||||
if (decl is VariableMirror) {
|
||||
VariableMirror vdecl = decl;
|
||||
used.addAll(_getUsedSymbols(vdecl.type, seenDecls, path, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Strip out type variables.
|
||||
if (decl is TypeMirror) {
|
||||
TypeMirror tdecl = decl;
|
||||
var typeVariables = tdecl.typeVariables.map((tv) => tv.qualifiedName);
|
||||
used = used.where((x) => !typeVariables.contains(x));
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
LibraryInfo extractSymbols(LibraryMirror lib, [String printPrefix = ""]) {
|
||||
List<ExportedSymbol> exportedSymbols = [];
|
||||
Map<Symbol, List<Symbol>> used = {};
|
||||
|
||||
printPrefix += " ";
|
||||
lib.declarations.forEach((Symbol symbol, DeclarationMirror decl) {
|
||||
if (decl.isPrivate) return;
|
||||
|
||||
// Work-around for dartbug.com/18271
|
||||
if (decl is TypedefMirror && unwrapSymbol(symbol).startsWith('_')) return;
|
||||
|
||||
exportedSymbols.add(new ExportedSymbol(symbol, decl, lib));
|
||||
used[decl.qualifiedName] = _getUsedSymbols(decl, {}, "", false);
|
||||
});
|
||||
|
||||
lib.libraryDependencies.forEach((LibraryDependencyMirror libDep) {
|
||||
LibraryMirror target = libDep.targetLibrary;
|
||||
if (!libDep.isExport) return;
|
||||
|
||||
var childInfo = extractSymbols(target, printPrefix);
|
||||
var childNames = childInfo.names;
|
||||
|
||||
// If there was a "show" or "hide" on the exported library, filter the results.
|
||||
// This API needs love :-(
|
||||
var showSymbols = [], hideSymbols = [];
|
||||
libDep.combinators.forEach((CombinatorMirror c) {
|
||||
if (c.isShow) {
|
||||
showSymbols.addAll(c.identifiers);
|
||||
}
|
||||
if (c.isHide) {
|
||||
hideSymbols.addAll(c.identifiers);
|
||||
}
|
||||
});
|
||||
|
||||
// I don't think you can show and hide from the same library
|
||||
assert(showSymbols.isEmpty || hideSymbols.isEmpty);
|
||||
if (!showSymbols.isEmpty) {
|
||||
childNames = childNames.where((symAndLib) {
|
||||
return showSymbols.contains(symAndLib.symbol);
|
||||
});
|
||||
}
|
||||
if (!hideSymbols.isEmpty) {
|
||||
childNames = childNames.where((symAndLib) {
|
||||
return !hideSymbols.contains(symAndLib.symbol);
|
||||
});
|
||||
}
|
||||
|
||||
exportedSymbols.addAll(childNames);
|
||||
used.addAll(childInfo.symbolsUsedForName);
|
||||
});
|
||||
return new LibraryInfo(exportedSymbols, used);
|
||||
}
|
||||
|
||||
|
||||
var _SYMBOL_NAME = new RegExp('"(.*)"');
|
||||
unwrapSymbol(sym) => _SYMBOL_NAME.firstMatch(sym.toString()).group(1);
|
|
@ -0,0 +1,69 @@
|
|||
import * as simple_library from './simple_library';
|
||||
import * as ng from 'angular2/angular2';
|
||||
|
||||
const LIB_MAP = {
|
||||
'simple_library': simple_library,
|
||||
'ng': ng
|
||||
};
|
||||
|
||||
const IGNORE =
|
||||
{
|
||||
captureStackTrace: true,
|
||||
stackTraceLimit: true,
|
||||
toString: true,
|
||||
originalException: true,
|
||||
originalStack: true,
|
||||
wrapperMessage: true,
|
||||
wrapperStack: true
|
||||
}
|
||||
|
||||
function collectClassSymbols(symbols: string[], prefix: String, type: Function):
|
||||
void {
|
||||
// static
|
||||
for (var name in type) {
|
||||
if (IGNORE[name] || name.charAt(0) == '_') continue;
|
||||
var suf = type[name] instanceof Function ? '()' : '';
|
||||
var symbol = `${prefix}#${name}${suf}`;
|
||||
symbols.push(symbol);
|
||||
}
|
||||
|
||||
// instance
|
||||
for (var name in type.prototype) {
|
||||
if (IGNORE[name] || name.charAt(0) == '_') continue;
|
||||
if (name == 'constructor') continue;
|
||||
var suf = '';
|
||||
try {
|
||||
if (type.prototype[name] instanceof Function) suf = '()';
|
||||
} catch (e) {
|
||||
}
|
||||
var symbol = `${prefix}.${name}${suf}`;
|
||||
symbols.push(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
function collectTopLevelSymbols(prefix: string, lib: any):
|
||||
string[] {
|
||||
var symbols: string[] = [];
|
||||
for (var name in lib) {
|
||||
var symbol = `${name}`;
|
||||
var ref = lib[name];
|
||||
if (ref instanceof Function) {
|
||||
if (symbol.charAt(0) == symbol.charAt(0).toLowerCase()) {
|
||||
// assume it is top level function
|
||||
symbols.push(symbol + '()');
|
||||
} else {
|
||||
symbols.push(symbol);
|
||||
collectClassSymbols(symbols, symbol, ref);
|
||||
}
|
||||
} else {
|
||||
symbols.push(symbol);
|
||||
}
|
||||
}
|
||||
return symbols;
|
||||
}
|
||||
|
||||
export function getSymbolsFromLibrary(name: string): string[] {
|
||||
var symbols = collectTopLevelSymbols(name, LIB_MAP[name]);
|
||||
symbols.sort();
|
||||
return symbols;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
ddescribe,
|
||||
describe,
|
||||
expect,
|
||||
iit,
|
||||
inject,
|
||||
it,
|
||||
xdescribe,
|
||||
xit
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {getSymbolsFromLibrary} from './symbol_inspector';
|
||||
import {SymbolsDiff} from './symbol_differ';
|
||||
|
||||
export function main() {
|
||||
describe('symbol inspector', () => {
|
||||
it('should extract symbols', () => {
|
||||
var symbols = getSymbolsFromLibrary("simple_library");
|
||||
|
||||
expect(new SymbolsDiff(symbols,
|
||||
[
|
||||
'A',
|
||||
'A#staticField',
|
||||
'A#staticField=',
|
||||
'A#staticMethod()',
|
||||
'A.field',
|
||||
'A.field=',
|
||||
'A.getter',
|
||||
'A.method()',
|
||||
'A.methodWithFunc()',
|
||||
'ClosureParam',
|
||||
'ClosureReturn',
|
||||
'ConsParamType',
|
||||
'FieldType',
|
||||
'Generic',
|
||||
'Generic.getter',
|
||||
'GetterType',
|
||||
'MethodReturnType',
|
||||
'ParamType',
|
||||
'StaticFieldType',
|
||||
'TypedefParam',
|
||||
'TypedefReturnType',
|
||||
'{SomeInterface}',
|
||||
])
|
||||
.errors)
|
||||
.toEqual([]);
|
||||
});
|
||||
|
||||
|
||||
describe('assert', () => {
|
||||
it('should assert symbol names are correct', () => {
|
||||
var diffs = new SymbolsDiff(['a()', 'c()', 'd()'], ['a()', 'b()', 'd()']);
|
||||
expect(diffs.errors).toEqual(['- b()', '+ c()']);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue