fix(api): align dart/js APIs

This commit is contained in:
Misko Hevery 2015-09-21 16:48:16 -07:00
parent 577ee3744a
commit af2cd4d6f3
14 changed files with 1264 additions and 672 deletions

View File

@ -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;

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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

View File

@ -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';

View File

@ -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));
}

View File

@ -1,2 +0,0 @@
// ignore in dart
main() {}

File diff suppressed because it is too large Load Diff

View File

@ -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(); }

View File

@ -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));
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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()']);
});
});
});
}