feat(transformers): collect information about di dependencies and providers

This commit is contained in:
vsavkin 2016-02-04 11:56:39 -08:00 committed by Victor Savkin
parent 16b521794c
commit 86c40f8474
34 changed files with 1002 additions and 179 deletions

View File

@ -2,8 +2,10 @@ import {
isPresent, isPresent,
isBlank, isBlank,
normalizeBool, normalizeBool,
normalizeBlank,
serializeEnum, serializeEnum,
Type, Type,
isString,
RegExpWrapper, RegExpWrapper,
StringWrapper StringWrapper
} from 'angular2/src/facade/lang'; } from 'angular2/src/facade/lang';
@ -22,7 +24,17 @@ import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/linker/i
// group 2: "event" from "(event)" // group 2: "event" from "(event)"
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g; var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
export abstract class CompileMetadataWithType { export abstract class CompileMetadataWithIdentifier {
static fromJson(data: {[key: string]: any}): CompileMetadataWithIdentifier {
return _COMPILE_METADATA_FROM_JSON[data['class']](data);
}
abstract toJson(): {[key: string]: any};
get identifier(): CompileIdentifierMetadata { return unimplemented(); }
}
export abstract class CompileMetadataWithType extends CompileMetadataWithIdentifier {
static fromJson(data: {[key: string]: any}): CompileMetadataWithType { static fromJson(data: {[key: string]: any}): CompileMetadataWithType {
return _COMPILE_METADATA_FROM_JSON[data['class']](data); return _COMPILE_METADATA_FROM_JSON[data['class']](data);
} }
@ -30,37 +42,221 @@ export abstract class CompileMetadataWithType {
abstract toJson(): {[key: string]: any}; abstract toJson(): {[key: string]: any};
get type(): CompileTypeMetadata { return unimplemented(); } get type(): CompileTypeMetadata { return unimplemented(); }
get identifier(): CompileIdentifierMetadata { return unimplemented(); }
} }
/** export class CompileIdentifierMetadata implements CompileMetadataWithIdentifier {
* Metadata regarding compilation of a type. runtime: any;
*/
export class CompileTypeMetadata {
runtime: Type;
name: string; name: string;
prefix: string;
moduleUrl: string; moduleUrl: string;
isHost: boolean; constructor({runtime, name, moduleUrl,
constructor({runtime, name, moduleUrl, isHost}: prefix}: {runtime?: any, name?: string, moduleUrl?: string, prefix?: string} = {}) {
{runtime?: Type, name?: string, moduleUrl?: string, isHost?: boolean} = {}) {
this.runtime = runtime; this.runtime = runtime;
this.name = name; this.name = name;
this.prefix = prefix;
this.moduleUrl = moduleUrl; this.moduleUrl = moduleUrl;
this.isHost = normalizeBool(isHost);
} }
static fromJson(data: {[key: string]: any}): CompileTypeMetadata { static fromJson(data: {[key: string]: any}): CompileIdentifierMetadata {
return new CompileTypeMetadata( return new CompileIdentifierMetadata(
{name: data['name'], moduleUrl: data['moduleUrl'], isHost: data['isHost']}); {name: data['name'], prefix: data['prefix'], moduleUrl: data['moduleUrl']});
} }
toJson(): {[key: string]: any} { toJson(): {[key: string]: any} {
return { return {
// Note: Runtime type can't be serialized... // Note: Runtime type can't be serialized...
'class': 'Identifier',
'name': this.name, 'name': this.name,
'moduleUrl': this.moduleUrl, 'moduleUrl': this.moduleUrl,
'isHost': this.isHost 'prefix': this.prefix
}; };
} }
get identifier(): CompileIdentifierMetadata { return this; }
}
export class CompileDiDependencyMetadata {
isAttribute: boolean;
isSelf: boolean;
isHost: boolean;
isSkipSelf: boolean;
isOptional: boolean;
query: CompileQueryMetadata;
viewQuery: CompileQueryMetadata;
token: CompileIdentifierMetadata | string;
constructor({isAttribute, isSelf, isHost, isSkipSelf, isOptional, query, viewQuery, token}: {
isAttribute?: boolean,
isSelf?: boolean,
isHost?: boolean,
isSkipSelf?: boolean,
isOptional?: boolean,
query?: CompileQueryMetadata,
viewQuery?: CompileQueryMetadata,
token?: CompileIdentifierMetadata | string
} = {}) {
this.isAttribute = normalizeBool(isAttribute);
this.isSelf = normalizeBool(isSelf);
this.isHost = normalizeBool(isHost);
this.isSkipSelf = normalizeBool(isSkipSelf);
this.isOptional = normalizeBool(isOptional);
this.query = query;
this.viewQuery = viewQuery;
this.token = token;
}
static fromJson(data: {[key: string]: any}): CompileDiDependencyMetadata {
return new CompileDiDependencyMetadata(
{token: objFromJson(data['token'], CompileIdentifierMetadata.fromJson)});
}
toJson(): {[key: string]: any} {
return {
// Note: Runtime type can't be serialized...
'token': objToJson(this.token)
};
}
}
export class CompileProviderMetadata {
token: CompileIdentifierMetadata | string;
useClass: CompileTypeMetadata;
useValue: any;
useExisting: CompileIdentifierMetadata | string;
useFactory: CompileFactoryMetadata;
deps: CompileDiDependencyMetadata[];
multi: boolean;
constructor({token, useClass, useValue, useExisting, useFactory, deps, multi}: {
token?: CompileIdentifierMetadata | string,
useClass?: CompileTypeMetadata,
useValue?: any,
useExisting?: CompileIdentifierMetadata | string,
useFactory?: CompileFactoryMetadata,
deps?: CompileDiDependencyMetadata[],
multi?: boolean
}) {
this.token = token;
this.useClass = useClass;
this.useValue = useValue;
this.useExisting = useExisting;
this.useFactory = useFactory;
this.deps = deps;
this.multi = multi;
}
static fromJson(data: {[key: string]: any}): CompileProviderMetadata {
return new CompileProviderMetadata({
token: objFromJson(data['token'], CompileIdentifierMetadata.fromJson),
useClass: objFromJson(data['useClass'], CompileTypeMetadata.fromJson)
});
}
toJson(): {[key: string]: any} {
return {
// Note: Runtime type can't be serialized...
'token': objToJson(this.token),
'useClass': objToJson(this.useClass)
};
}
}
export class CompileFactoryMetadata implements CompileIdentifierMetadata {
runtime: Function;
name: string;
prefix: string;
moduleUrl: string;
diDeps: CompileDiDependencyMetadata[];
constructor({runtime, name, moduleUrl, diDeps}: {
runtime?: Function,
name?: string,
moduleUrl?: string,
diDeps?: CompileDiDependencyMetadata[]
}) {
this.runtime = runtime;
this.name = name;
this.moduleUrl = moduleUrl;
this.diDeps = diDeps;
}
get identifier(): CompileIdentifierMetadata { return this; }
toJson() { return null; }
}
/**
* Metadata regarding compilation of a type.
*/
export class CompileTypeMetadata implements CompileIdentifierMetadata, CompileMetadataWithType {
runtime: Type;
name: string;
prefix: string;
moduleUrl: string;
isHost: boolean;
diDeps: CompileDiDependencyMetadata[];
constructor({runtime, name, moduleUrl, prefix, isHost, diDeps}: {
runtime?: Type,
name?: string,
moduleUrl?: string,
prefix?: string,
isHost?: boolean,
diDeps?: CompileDiDependencyMetadata[]
} = {}) {
this.runtime = runtime;
this.name = name;
this.moduleUrl = moduleUrl;
this.prefix = prefix;
this.isHost = normalizeBool(isHost);
this.diDeps = normalizeBlank(diDeps);
}
static fromJson(data: {[key: string]: any}): CompileTypeMetadata {
return new CompileTypeMetadata({
name: data['name'],
moduleUrl: data['moduleUrl'],
prefix: data['prefix'],
isHost: data['isHost'],
diDeps: arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
});
}
get identifier(): CompileIdentifierMetadata { return this; }
get type(): CompileTypeMetadata { return this; }
toJson(): {[key: string]: any} {
return {
// Note: Runtime type can't be serialized...
'class': 'Type',
'name': this.name,
'moduleUrl': this.moduleUrl,
'prefix': this.prefix,
'isHost': this.isHost,
'diDeps': arrayToJson(this.diDeps)
};
}
}
export class CompileQueryMetadata {
selectors: Array<CompileIdentifierMetadata | string>;
descendants: boolean;
first: boolean;
propertyName: string;
constructor({selectors, descendants, first, propertyName}: {
selectors?: Array<CompileIdentifierMetadata | string>,
descendants?: boolean,
first?: boolean,
propertyName?: string
} = {}) {
this.selectors = selectors;
this.descendants = descendants;
this.first = first;
this.propertyName = propertyName;
}
} }
/** /**
@ -120,7 +316,8 @@ export class CompileTemplateMetadata {
*/ */
export class CompileDirectiveMetadata implements CompileMetadataWithType { export class CompileDirectiveMetadata implements CompileMetadataWithType {
static create({type, isComponent, dynamicLoadable, selector, exportAs, changeDetection, inputs, static create({type, isComponent, dynamicLoadable, selector, exportAs, changeDetection, inputs,
outputs, host, lifecycleHooks, template}: { outputs, host, lifecycleHooks, providers, viewProviders, queries, viewQueries,
template}: {
type?: CompileTypeMetadata, type?: CompileTypeMetadata,
isComponent?: boolean, isComponent?: boolean,
dynamicLoadable?: boolean, dynamicLoadable?: boolean,
@ -131,6 +328,10 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
outputs?: string[], outputs?: string[],
host?: {[key: string]: string}, host?: {[key: string]: string},
lifecycleHooks?: LifecycleHooks[], lifecycleHooks?: LifecycleHooks[],
providers?: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>,
viewProviders?: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>,
queries?: CompileQueryMetadata[],
viewQueries?: CompileQueryMetadata[],
template?: CompileTemplateMetadata template?: CompileTemplateMetadata
} = {}): CompileDirectiveMetadata { } = {}): CompileDirectiveMetadata {
var hostListeners: {[key: string]: string} = {}; var hostListeners: {[key: string]: string} = {};
@ -180,10 +381,13 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
hostProperties: hostProperties, hostProperties: hostProperties,
hostAttributes: hostAttributes, hostAttributes: hostAttributes,
lifecycleHooks: isPresent(lifecycleHooks) ? lifecycleHooks : [], lifecycleHooks: isPresent(lifecycleHooks) ? lifecycleHooks : [],
providers: providers,
viewProviders: viewProviders,
queries: queries,
viewQueries: viewQueries,
template: template template: template
}); });
} }
type: CompileTypeMetadata; type: CompileTypeMetadata;
isComponent: boolean; isComponent: boolean;
dynamicLoadable: boolean; dynamicLoadable: boolean;
@ -196,9 +400,14 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
hostProperties: {[key: string]: string}; hostProperties: {[key: string]: string};
hostAttributes: {[key: string]: string}; hostAttributes: {[key: string]: string};
lifecycleHooks: LifecycleHooks[]; lifecycleHooks: LifecycleHooks[];
providers: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>;
viewProviders: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>;
queries: CompileQueryMetadata[];
viewQueries: CompileQueryMetadata[];
template: CompileTemplateMetadata; template: CompileTemplateMetadata;
constructor({type, isComponent, dynamicLoadable, selector, exportAs, changeDetection, inputs, constructor({type, isComponent, dynamicLoadable, selector, exportAs, changeDetection, inputs,
outputs, hostListeners, hostProperties, hostAttributes, lifecycleHooks, template}: { outputs, hostListeners, hostProperties, hostAttributes, lifecycleHooks, providers,
viewProviders, queries, viewQueries, template}: {
type?: CompileTypeMetadata, type?: CompileTypeMetadata,
isComponent?: boolean, isComponent?: boolean,
dynamicLoadable?: boolean, dynamicLoadable?: boolean,
@ -211,6 +420,10 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
hostProperties?: {[key: string]: string}, hostProperties?: {[key: string]: string},
hostAttributes?: {[key: string]: string}, hostAttributes?: {[key: string]: string},
lifecycleHooks?: LifecycleHooks[], lifecycleHooks?: LifecycleHooks[],
providers?: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>,
viewProviders?: Array<CompileProviderMetadata | CompileTypeMetadata | any[]>,
queries?: CompileQueryMetadata[],
viewQueries?: CompileQueryMetadata[],
template?: CompileTemplateMetadata template?: CompileTemplateMetadata
} = {}) { } = {}) {
this.type = type; this.type = type;
@ -225,9 +438,15 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
this.hostProperties = hostProperties; this.hostProperties = hostProperties;
this.hostAttributes = hostAttributes; this.hostAttributes = hostAttributes;
this.lifecycleHooks = lifecycleHooks; this.lifecycleHooks = lifecycleHooks;
this.providers = normalizeBlank(providers);
this.viewProviders = normalizeBlank(viewProviders);
this.queries = queries;
this.viewQueries = viewQueries;
this.template = template; this.template = template;
} }
get identifier(): CompileIdentifierMetadata { return this.type; }
static fromJson(data: {[key: string]: any}): CompileDirectiveMetadata { static fromJson(data: {[key: string]: any}): CompileDirectiveMetadata {
return new CompileDirectiveMetadata({ return new CompileDirectiveMetadata({
isComponent: data['isComponent'], isComponent: data['isComponent'],
@ -246,7 +465,8 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
lifecycleHooks: lifecycleHooks:
(<any[]>data['lifecycleHooks']).map(hookValue => LIFECYCLE_HOOKS_VALUES[hookValue]), (<any[]>data['lifecycleHooks']).map(hookValue => LIFECYCLE_HOOKS_VALUES[hookValue]),
template: isPresent(data['template']) ? CompileTemplateMetadata.fromJson(data['template']) : template: isPresent(data['template']) ? CompileTemplateMetadata.fromJson(data['template']) :
data['template'] data['template'],
providers: arrayFromJson(data['providers'], CompileProviderMetadata.fromJson)
}); });
} }
@ -266,7 +486,8 @@ export class CompileDirectiveMetadata implements CompileMetadataWithType {
'hostProperties': this.hostProperties, 'hostProperties': this.hostProperties,
'hostAttributes': this.hostAttributes, 'hostAttributes': this.hostAttributes,
'lifecycleHooks': this.lifecycleHooks.map(hook => serializeEnum(hook)), 'lifecycleHooks': this.lifecycleHooks.map(hook => serializeEnum(hook)),
'template': isPresent(this.template) ? this.template.toJson() : this.template 'template': isPresent(this.template) ? this.template.toJson() : this.template,
'providers': arrayToJson(this.providers)
}; };
} }
} }
@ -293,7 +514,11 @@ export function createHostComponentMeta(componentType: CompileTypeMetadata,
lifecycleHooks: [], lifecycleHooks: [],
isComponent: true, isComponent: true,
dynamicLoadable: false, dynamicLoadable: false,
selector: '*' selector: '*',
providers: [],
viewProviders: [],
queries: [],
viewQueries: []
}); });
} }
@ -308,6 +533,7 @@ export class CompilePipeMetadata implements CompileMetadataWithType {
this.name = name; this.name = name;
this.pure = normalizeBool(pure); this.pure = normalizeBool(pure);
} }
get identifier(): CompileIdentifierMetadata { return this.type; }
static fromJson(data: {[key: string]: any}): CompilePipeMetadata { static fromJson(data: {[key: string]: any}): CompilePipeMetadata {
return new CompilePipeMetadata({ return new CompilePipeMetadata({
@ -329,5 +555,23 @@ export class CompilePipeMetadata implements CompileMetadataWithType {
var _COMPILE_METADATA_FROM_JSON = { var _COMPILE_METADATA_FROM_JSON = {
'Directive': CompileDirectiveMetadata.fromJson, 'Directive': CompileDirectiveMetadata.fromJson,
'Pipe': CompilePipeMetadata.fromJson 'Pipe': CompilePipeMetadata.fromJson,
'Type': CompileTypeMetadata.fromJson,
'Identifier': CompileIdentifierMetadata.fromJson
}; };
function arrayFromJson(obj: any[], fn: (a: {[key: string]: any}) => any): any {
return isBlank(obj) ? null : obj.map(fn);
}
function arrayToJson(obj: any[]): string | {[key: string]: any} {
return isBlank(obj) ? null : obj.map(o => o.toJson());
}
function objFromJson(obj: any, fn: (a: {[key: string]: any}) => any): any {
return (isString(obj) || isBlank(obj)) ? obj : fn(obj);
}
function objToJson(obj: any): string | {[key: string]: any} {
return (isString(obj) || isBlank(obj)) ? obj : obj.toJson();
}

View File

@ -109,6 +109,7 @@ export class TemplateCompiler {
hostProperties: directive.hostProperties, hostProperties: directive.hostProperties,
hostAttributes: directive.hostAttributes, hostAttributes: directive.hostAttributes,
lifecycleHooks: directive.lifecycleHooks, lifecycleHooks: directive.lifecycleHooks,
providers: directive.providers,
template: normalizedTemplate template: normalizedTemplate
})); }));
} }

View File

@ -1,6 +1,8 @@
import {ChangeDetector} from './interfaces'; import {ChangeDetector} from './interfaces';
import {ChangeDetectionStrategy} from './constants'; import {ChangeDetectionStrategy} from './constants';
import {Injectable} from 'angular2/src/core/di';
@Injectable()
export abstract class ChangeDetectorRef { export abstract class ChangeDetectorRef {
/** /**
* Marks all {@link ChangeDetectionStrategy#OnPush} ancestors as to be checked. * Marks all {@link ChangeDetectionStrategy#OnPush} ancestors as to be checked.

View File

@ -1,4 +1,5 @@
import {unimplemented} from 'angular2/src/facade/exceptions'; import {unimplemented} from 'angular2/src/facade/exceptions';
import {Injectable} from 'angular2/src/core/di';
import {AppElement} from './element'; import {AppElement} from './element';
/** /**
@ -11,6 +12,7 @@ import {AppElement} from './element';
* An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
* element. * element.
*/ */
@Injectable()
export abstract class ElementRef { export abstract class ElementRef {
/** /**
* The underlying native element or `null` if direct access to native elements is not supported * The underlying native element or `null` if direct access to native elements is not supported

View File

@ -1,4 +1,5 @@
import {ElementRef, ElementRef_} from './element_ref'; import {ElementRef, ElementRef_} from './element_ref';
import {Injectable} from 'angular2/src/core/di';
/** /**
* Represents an Embedded Template that can be used to instantiate Embedded Views. * Represents an Embedded Template that can be used to instantiate Embedded Views.
@ -12,6 +13,7 @@ import {ElementRef, ElementRef_} from './element_ref';
* {@link ViewContainerRef#createEmbeddedView}, which will create the View and attach it to the * {@link ViewContainerRef#createEmbeddedView}, which will create the View and attach it to the
* View Container. * View Container.
*/ */
@Injectable()
export abstract class TemplateRef { export abstract class TemplateRef {
/** /**
* The location in the View where the Embedded View logically belongs to. * The location in the View where the Embedded View logically belongs to.

View File

@ -1,6 +1,6 @@
import {ListWrapper} from 'angular2/src/facade/collection'; import {ListWrapper} from 'angular2/src/facade/collection';
import {unimplemented} from 'angular2/src/facade/exceptions'; import {unimplemented} from 'angular2/src/facade/exceptions';
import {ResolvedProvider} from 'angular2/src/core/di'; import {ResolvedProvider, Injectable} from 'angular2/src/core/di';
import {isPresent, isBlank} from 'angular2/src/facade/lang'; import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {AppElement} from './element'; import {AppElement} from './element';
@ -36,6 +36,7 @@ import {
* *
* <!-- TODO(i): we are also considering ElementRef#viewContainer api --> * <!-- TODO(i): we are also considering ElementRef#viewContainer api -->
*/ */
@Injectable()
export abstract class ViewContainerRef { export abstract class ViewContainerRef {
/** /**
* Anchor element that specifies the location of this container in the containing View. * Anchor element that specifies the location of this container in the containing View.

View File

@ -1,5 +1,5 @@
import {ViewEncapsulation} from 'angular2/src/core/metadata/view'; import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
import {Injector} from 'angular2/src/core/di/injector'; import {Injector, Injectable} from 'angular2/src/core/di';
export class RenderComponentType { export class RenderComponentType {
constructor(public id: string, public encapsulation: ViewEncapsulation, constructor(public id: string, public encapsulation: ViewEncapsulation,
@ -13,6 +13,7 @@ export class RenderDebugInfo {
export interface ParentRenderer { renderComponent(componentType: RenderComponentType): Renderer; } export interface ParentRenderer { renderComponent(componentType: RenderComponentType): Renderer; }
@Injectable()
export abstract class Renderer implements ParentRenderer { export abstract class Renderer implements ParentRenderer {
abstract renderComponent(componentType: RenderComponentType): Renderer; abstract renderComponent(componentType: RenderComponentType): Renderer;

View File

@ -1,6 +1,7 @@
import {Map, MapWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection'; import {Map, MapWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {isPresent, isBlank, normalizeBlank, Type, CONST_EXPR} from 'angular2/src/facade/lang'; import {isPresent, isBlank, normalizeBlank, Type, CONST_EXPR} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {Injectable} from 'angular2/core';
/** /**
@ -33,6 +34,7 @@ import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
* bootstrap(AppCmp, ROUTER_PROVIDERS); * bootstrap(AppCmp, ROUTER_PROVIDERS);
* ``` * ```
*/ */
@Injectable()
export class RouteParams { export class RouteParams {
constructor(public params: {[key: string]: string}) {} constructor(public params: {[key: string]: string}) {}

View File

@ -34,6 +34,7 @@ let _resolveToFalse = PromiseWrapper.resolve(false);
* `Instruction`. * `Instruction`.
* The router uses the `RouteRegistry` to get an `Instruction`. * The router uses the `RouteRegistry` to get an `Instruction`.
*/ */
@Injectable()
export class Router { export class Router {
navigating: boolean = false; navigating: boolean = false;
lastNavigationAttempt: string; lastNavigationAttempt: string;

View File

@ -15,7 +15,8 @@ import {
import { import {
CompileDirectiveMetadata, CompileDirectiveMetadata,
CompileTypeMetadata, CompileTypeMetadata,
CompileTemplateMetadata CompileTemplateMetadata,
CompileProviderMetadata
} from 'angular2/src/compiler/directive_metadata'; } from 'angular2/src/compiler/directive_metadata';
import {ViewEncapsulation} from 'angular2/src/core/metadata/view'; import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
import {ChangeDetectionStrategy} from 'angular2/src/core/change_detection'; import {ChangeDetectionStrategy} from 'angular2/src/core/change_detection';
@ -28,8 +29,8 @@ export function main() {
var fullDirectiveMeta: CompileDirectiveMetadata; var fullDirectiveMeta: CompileDirectiveMetadata;
beforeEach(() => { beforeEach(() => {
fullTypeMeta = fullTypeMeta = new CompileTypeMetadata(
new CompileTypeMetadata({name: 'SomeType', moduleUrl: 'someUrl', isHost: true}); {name: 'SomeType', moduleUrl: 'someUrl', isHost: true, diDeps: []});
fullTemplateMeta = new CompileTemplateMetadata({ fullTemplateMeta = new CompileTemplateMetadata({
encapsulation: ViewEncapsulation.Emulated, encapsulation: ViewEncapsulation.Emulated,
template: '<a></a>', template: '<a></a>',
@ -48,7 +49,8 @@ export function main() {
inputs: ['someProp'], inputs: ['someProp'],
outputs: ['someEvent'], outputs: ['someEvent'],
host: {'(event1)': 'handler1', '[prop1]': 'expr1', 'attr1': 'attrValue2'}, host: {'(event1)': 'handler1', '[prop1]': 'expr1', 'attr1': 'attrValue2'},
lifecycleHooks: [LifecycleHooks.OnChanges] lifecycleHooks: [LifecycleHooks.OnChanges],
providers: [new CompileProviderMetadata({token: 'token', useClass: fullTypeMeta})]
}); });
}); });

View File

@ -515,6 +515,15 @@ var NG_COMPILER = [
"CompileDirectiveMetadata.template=", "CompileDirectiveMetadata.template=",
"CompileDirectiveMetadata.type", "CompileDirectiveMetadata.type",
"CompileDirectiveMetadata.type=", "CompileDirectiveMetadata.type=",
"CompileDirectiveMetadata.identifier",
"CompileDirectiveMetadata.providers",
"CompileDirectiveMetadata.providers=",
"CompileDirectiveMetadata.queries",
"CompileDirectiveMetadata.queries=",
"CompileDirectiveMetadata.viewProviders",
"CompileDirectiveMetadata.viewProviders=",
"CompileDirectiveMetadata.viewQueries",
"CompileDirectiveMetadata.viewQueries=",
"CompileTemplateMetadata.encapsulation", "CompileTemplateMetadata.encapsulation",
"CompileTemplateMetadata.encapsulation=", "CompileTemplateMetadata.encapsulation=",
"CompileTemplateMetadata.ngContentSelectors", "CompileTemplateMetadata.ngContentSelectors",
@ -535,6 +544,12 @@ var NG_COMPILER = [
"CompileTypeMetadata.name=", "CompileTypeMetadata.name=",
"CompileTypeMetadata.runtime", "CompileTypeMetadata.runtime",
"CompileTypeMetadata.runtime=", "CompileTypeMetadata.runtime=",
"CompileTypeMetadata.diDeps",
"CompileTypeMetadata.diDeps=",
"CompileTypeMetadata.type",
"CompileTypeMetadata.identifier",
"CompileTypeMetadata.prefix",
"CompileTypeMetadata.prefix=",
"DirectiveAst.directive", "DirectiveAst.directive",
"DirectiveAst.directive=", "DirectiveAst.directive=",
"DirectiveAst.exportAsVars", "DirectiveAst.exportAsVars",

View File

@ -127,6 +127,7 @@ export class MdDialog {
/** /**
* Reference to an opened dialog. * Reference to an opened dialog.
*/ */
@Injectable()
export class MdDialogRef { export class MdDialogRef {
// Reference to the MdDialogContainer component. // Reference to the MdDialogContainer component.
containerRef: ComponentRef; containerRef: ComponentRef;

View File

@ -67,6 +67,7 @@ class ReflectionInfoVisitor extends RecursiveAstVisitor<ReflectionInfoModel> {
@override @override
ReflectionInfoModel visitClassDeclaration(ClassDeclaration node) { ReflectionInfoModel visitClassDeclaration(ClassDeclaration node) {
if (node.isAbstract) return null;
if (!node.metadata if (!node.metadata
.any((a) => _annotationMatcher.hasMatch(a.name, assetId))) { .any((a) => _annotationMatcher.hasMatch(a.name, assetId))) {
return null; return null;

View File

@ -33,9 +33,9 @@ class NgMeta {
static const _TYPE_VALUE = 'type'; static const _TYPE_VALUE = 'type';
static const _VALUE_KEY = 'value'; static const _VALUE_KEY = 'value';
/// Metadata for each type annotated as a directive/pipe. /// Metadata for each identifier
/// Type: [CompileDirectiveMetadata]/[CompilePipeMetadata] /// Type: [CompileDirectiveMetadata]|[CompilePipeMetadata]|[CompileTypeMetadata]|[CompileIdentifierMetadata]
final Map<String, dynamic> types; final Map<String, dynamic> identifiers;
/// List of other types and names associated with a given name. /// List of other types and names associated with a given name.
final Map<String, List<String>> aliases; final Map<String, List<String>> aliases;
@ -43,12 +43,11 @@ class NgMeta {
// The NgDeps generated from // The NgDeps generated from
final NgDepsModel ngDeps; final NgDepsModel ngDeps;
NgMeta( NgMeta({Map<String, List<String>> aliases,
{Map<String, dynamic> types, Map<String, dynamic> identifiers,
Map<String, List<String>> aliases,
this.ngDeps: null}) this.ngDeps: null})
: this.types = types != null ? types : {}, :this.aliases = aliases != null ? aliases : {},
this.aliases = aliases != null ? aliases : {}; this.identifiers = identifiers != null ? identifiers : {};
NgMeta.empty() : this(); NgMeta.empty() : this();
@ -69,13 +68,13 @@ class NgMeta {
return false; return false;
} }
bool get isEmpty => types.isEmpty && aliases.isEmpty && isNgDepsEmpty; bool get isEmpty => identifiers.isEmpty && aliases.isEmpty && isNgDepsEmpty;
/// Parse from the serialized form produced by [toJson]. /// Parse from the serialized form produced by [toJson].
factory NgMeta.fromJson(Map json) { factory NgMeta.fromJson(Map json) {
var ngDeps = null; var ngDeps = null;
final types = {};
final aliases = {}; final aliases = {};
final identifiers = {};
for (var key in json.keys) { for (var key in json.keys) {
if (key == _NG_DEPS_KEY) { if (key == _NG_DEPS_KEY) {
var ngDepsJsonMap = json[key]; var ngDepsJsonMap = json[key];
@ -85,7 +84,9 @@ class NgMeta {
'Unexpected value $ngDepsJsonMap for key "$key" in NgMeta.'); 'Unexpected value $ngDepsJsonMap for key "$key" in NgMeta.');
continue; continue;
} }
ngDeps = new NgDepsModel()..mergeFromJsonMap(ngDepsJsonMap); ngDeps = new NgDepsModel()
..mergeFromJsonMap(ngDepsJsonMap);
} else { } else {
var entry = json[key]; var entry = json[key];
if (entry is! Map) { if (entry is! Map) {
@ -93,13 +94,13 @@ class NgMeta {
continue; continue;
} }
if (entry[_KIND_KEY] == _TYPE_VALUE) { if (entry[_KIND_KEY] == _TYPE_VALUE) {
types[key] = CompileMetadataWithType.fromJson(entry[_VALUE_KEY]); identifiers[key] = CompileMetadataWithIdentifier.fromJson(entry[_VALUE_KEY]);
} else if (entry[_KIND_KEY] == _ALIAS_VALUE) { } else if (entry[_KIND_KEY] == _ALIAS_VALUE) {
aliases[key] = entry[_VALUE_KEY]; aliases[key] = entry[_VALUE_KEY];
} }
} }
} }
return new NgMeta(types: types, aliases: aliases, ngDeps: ngDeps); return new NgMeta(identifiers: identifiers, aliases: aliases, ngDeps: ngDeps);
} }
/// Serialized representation of this instance. /// Serialized representation of this instance.
@ -107,7 +108,7 @@ class NgMeta {
var result = {}; var result = {};
result[_NG_DEPS_KEY] = isNgDepsEmpty ? null : ngDeps.writeToJsonMap(); result[_NG_DEPS_KEY] = isNgDepsEmpty ? null : ngDeps.writeToJsonMap();
types.forEach((k, v) { identifiers.forEach((k, v) {
result[k] = {_KIND_KEY: _TYPE_VALUE, _VALUE_KEY: v.toJson()}; result[k] = {_KIND_KEY: _TYPE_VALUE, _VALUE_KEY: v.toJson()};
}); });
@ -120,8 +121,8 @@ class NgMeta {
/// Merge into this instance all information from [other]. /// Merge into this instance all information from [other].
/// This does not include `ngDeps`. /// This does not include `ngDeps`.
void addAll(NgMeta other) { void addAll(NgMeta other) {
types.addAll(other.types);
aliases.addAll(other.aliases); aliases.addAll(other.aliases);
identifiers.addAll(other.identifiers);
} }
/// Returns the metadata for every type associated with the given [alias]. /// Returns the metadata for every type associated with the given [alias].
@ -133,8 +134,8 @@ class NgMeta {
log.warning('Circular alias dependency for "$name".'); log.warning('Circular alias dependency for "$name".');
return; return;
} }
if (types.containsKey(name)) { if (identifiers.containsKey(name)) {
result.add(types[name]); result.add(identifiers[name]);
} else if (aliases.containsKey(name)) { } else if (aliases.containsKey(name)) {
aliases[name].forEach(helper); aliases[name].forEach(helper);
} else { } else {

View File

@ -21,22 +21,24 @@ import 'url_resolver.dart';
class TypeMetadataReader { class TypeMetadataReader {
final _DirectiveMetadataVisitor _directiveVisitor; final _DirectiveMetadataVisitor _directiveVisitor;
final _PipeMetadataVisitor _pipeVisitor; final _PipeMetadataVisitor _pipeVisitor;
final _CompileTypeMetadataVisitor _typeVisitor;
final TemplateCompiler _templateCompiler; final TemplateCompiler _templateCompiler;
TypeMetadataReader._( TypeMetadataReader._(
this._directiveVisitor, this._pipeVisitor, this._templateCompiler); this._directiveVisitor, this._pipeVisitor, this._templateCompiler, this._typeVisitor);
/// Accepts an [AnnotationMatcher] which tests that an [Annotation] /// Accepts an [AnnotationMatcher] which tests that an [Annotation]
/// is a [Directive], [Component], or [View]. /// is a [Directive], [Component], or [View].
factory TypeMetadataReader(AnnotationMatcher annotationMatcher, factory TypeMetadataReader(AnnotationMatcher annotationMatcher,
InterfaceMatcher interfaceMatcher, TemplateCompiler templateCompiler) { InterfaceMatcher interfaceMatcher, TemplateCompiler templateCompiler) {
var lifecycleVisitor = new _LifecycleHookVisitor(interfaceMatcher); var lifecycleVisitor = new _LifecycleHookVisitor(interfaceMatcher);
var typeVisitor = new _CompileTypeMetadataVisitor(annotationMatcher);
var directiveVisitor = var directiveVisitor =
new _DirectiveMetadataVisitor(annotationMatcher, lifecycleVisitor); new _DirectiveMetadataVisitor(annotationMatcher, lifecycleVisitor, typeVisitor);
var pipeVisitor = new _PipeMetadataVisitor(annotationMatcher); var pipeVisitor = new _PipeMetadataVisitor(annotationMatcher);
return new TypeMetadataReader._( return new TypeMetadataReader._(
directiveVisitor, pipeVisitor, templateCompiler); directiveVisitor, pipeVisitor, templateCompiler, typeVisitor);
} }
/// Reads *un-normalized* [CompileDirectiveMetadata]/[CompilePipeMetadata] from the /// Reads *un-normalized* [CompileDirectiveMetadata]/[CompilePipeMetadata] from the
@ -52,13 +54,19 @@ class TypeMetadataReader {
Future<dynamic> readTypeMetadata(ClassDeclaration node, AssetId assetId) { Future<dynamic> readTypeMetadata(ClassDeclaration node, AssetId assetId) {
_directiveVisitor.reset(assetId); _directiveVisitor.reset(assetId);
_pipeVisitor.reset(assetId); _pipeVisitor.reset(assetId);
_typeVisitor.reset(assetId);
node.accept(_directiveVisitor); node.accept(_directiveVisitor);
node.accept(_pipeVisitor); node.accept(_pipeVisitor);
node.accept(_typeVisitor);
if (_directiveVisitor.hasMetadata) { if (_directiveVisitor.hasMetadata) {
final metadata = _directiveVisitor.createMetadata(); final metadata = _directiveVisitor.createMetadata();
return _templateCompiler.normalizeDirectiveMetadata(metadata); return _templateCompiler.normalizeDirectiveMetadata(metadata);
} else if (_pipeVisitor.hasMetadata) { } else if (_pipeVisitor.hasMetadata) {
return new Future.value(_pipeVisitor.createMetadata()); return new Future.value(_pipeVisitor.createMetadata());
} else if (_typeVisitor.isInjectable) {
return new Future.value(_typeVisitor.type);
} else { } else {
return new Future.value(null); return new Future.value(null);
} }
@ -124,6 +132,67 @@ bool _expressionToBool(Expression node, String nodeDescription) {
return value; return value;
} }
class _CompileTypeMetadataVisitor extends Object
with RecursiveAstVisitor<CompileTypeMetadata> {
bool _isInjectable = false;
CompileTypeMetadata _type;
AssetId _assetId;
final AnnotationMatcher _annotationMatcher;
_CompileTypeMetadataVisitor(this._annotationMatcher);
bool get isInjectable => _isInjectable;
CompileTypeMetadata get type => _type;
void reset(AssetId assetId) {
this._assetId = assetId;
this._isInjectable = false;
this._type = null;
}
@override
Object visitAnnotation(Annotation node) {
final isComponent = _annotationMatcher.isComponent(node, _assetId);
final isDirective = _annotationMatcher.isDirective(node, _assetId);
final isInjectable = _annotationMatcher.isInjectable(node, _assetId);
_isInjectable = _isInjectable || isComponent || isDirective || isInjectable;
return null;
}
@override
Object visitClassDeclaration(ClassDeclaration node) {
node.metadata.accept(this);
if (this._isInjectable) {
_type = new CompileTypeMetadata(
moduleUrl: toAssetUri(_assetId),
name: node.name.toString(),
diDeps: _getCompileDiDependencyMetadata(node),
runtime: null // Intentionally `null`, cannot be provided here.
);
}
return null;
}
List<CompileDiDependencyMetadata> _getCompileDiDependencyMetadata(ClassDeclaration node) {
final constructor = node.getConstructor(null);
if (constructor == null) return [];
return constructor.parameters.parameters.map((p) {
final typeToken = p is SimpleFormalParameter && p.type != null ? _readIdentifier(p.type.name) : null;
final injectTokens = p.metadata.where((m) => m.name.toString() == "Inject").map((m) => _readIdentifier(m.arguments.arguments[0]));
final token = injectTokens.isNotEmpty ? injectTokens.first : typeToken;
return new CompileDiDependencyMetadata(token: token);
}).toList();
}
}
/// Visitor responsible for processing a [Directive] annotated /// Visitor responsible for processing a [Directive] annotated
/// [ClassDeclaration] and creating a [CompileDirectiveMetadata] object. /// [ClassDeclaration] and creating a [CompileDirectiveMetadata] object.
class _DirectiveMetadataVisitor extends Object class _DirectiveMetadataVisitor extends Object
@ -134,10 +203,12 @@ class _DirectiveMetadataVisitor extends Object
final _LifecycleHookVisitor _lifecycleVisitor; final _LifecycleHookVisitor _lifecycleVisitor;
final _CompileTypeMetadataVisitor _typeVisitor;
/// The [AssetId] we are currently processing. /// The [AssetId] we are currently processing.
AssetId _assetId; AssetId _assetId;
_DirectiveMetadataVisitor(this._annotationMatcher, this._lifecycleVisitor) { _DirectiveMetadataVisitor(this._annotationMatcher, this._lifecycleVisitor, this._typeVisitor) {
reset(null); reset(null);
} }
@ -154,12 +225,14 @@ class _DirectiveMetadataVisitor extends Object
List<String> _inputs; List<String> _inputs;
List<String> _outputs; List<String> _outputs;
Map<String, String> _host; Map<String, String> _host;
List<CompileProviderMetadata> _providers;
List<LifecycleHooks> _lifecycleHooks; List<LifecycleHooks> _lifecycleHooks;
CompileTemplateMetadata _cmpTemplate; CompileTemplateMetadata _cmpTemplate;
CompileTemplateMetadata _viewTemplate; CompileTemplateMetadata _viewTemplate;
void reset(AssetId assetId) { void reset(AssetId assetId) {
_lifecycleVisitor.reset(assetId); _lifecycleVisitor.reset(assetId);
_typeVisitor.reset(assetId);
_assetId = assetId; _assetId = assetId;
_type = null; _type = null;
@ -171,6 +244,7 @@ class _DirectiveMetadataVisitor extends Object
_inputs = <String>[]; _inputs = <String>[];
_outputs = <String>[]; _outputs = <String>[];
_host = <String, String>{}; _host = <String, String>{};
_providers = <CompileProviderMetadata>[];
_lifecycleHooks = null; _lifecycleHooks = null;
_cmpTemplate = null; _cmpTemplate = null;
_viewTemplate = null; _viewTemplate = null;
@ -192,6 +266,7 @@ class _DirectiveMetadataVisitor extends Object
inputs: _inputs, inputs: _inputs,
outputs: _outputs, outputs: _outputs,
host: _host, host: _host,
providers: _providers,
lifecycleHooks: _lifecycleHooks, lifecycleHooks: _lifecycleHooks,
template: _template); template: _template);
} }
@ -316,6 +391,34 @@ class _DirectiveMetadataVisitor extends Object
} }
} }
void _populateProviders(Expression providerValues) {
_checkMeta();
final providers = (providerValues as ListLiteral).elements.map((el) {
if (el is PrefixedIdentifier || el is SimpleIdentifier) {
return new CompileProviderMetadata(token: _readIdentifier(el));
} else if (el is InstanceCreationExpression && el.constructorName.toString() == "Provider") {
final token = el.argumentList.arguments.first;
var useClass;
el.argumentList.arguments.skip(1).forEach((arg) {
if (arg.name.toString() == "useClass:") {
final id = _readIdentifier(arg.expression);
useClass = new CompileTypeMetadata(prefix: id.prefix, name: id.name);
}
});
return new CompileProviderMetadata(token: _readIdentifier(token), useClass: useClass);
} else {
throw new ArgumentError(
'Incorrect value. Expected a Provider or a String, but got "${el}".');
}
});
_providers.addAll(providers);
}
//TODO Use AnnotationMatcher instead of string matching //TODO Use AnnotationMatcher instead of string matching
bool _isAnnotation(Annotation node, String annotationName) { bool _isAnnotation(Annotation node, String annotationName) {
var id = node.name; var id = node.name;
@ -356,12 +459,10 @@ class _DirectiveMetadataVisitor extends Object
@override @override
Object visitClassDeclaration(ClassDeclaration node) { Object visitClassDeclaration(ClassDeclaration node) {
node.metadata.accept(this); node.metadata.accept(this);
node.accept(_typeVisitor);
_type = _typeVisitor.type;
if (this._hasMetadata) { if (this._hasMetadata) {
_type = new CompileTypeMetadata(
moduleUrl: toAssetUri(_assetId),
name: node.name.toString(),
runtime: null // Intentionally `null`, cannot be provided here.
);
_lifecycleHooks = node.implementsClause != null _lifecycleHooks = node.implementsClause != null
? node.implementsClause.accept(_lifecycleVisitor) ? node.implementsClause.accept(_lifecycleVisitor)
: const []; : const [];
@ -405,6 +506,9 @@ class _DirectiveMetadataVisitor extends Object
case 'events': case 'events':
_populateEvents(node.expression); _populateEvents(node.expression);
break; break;
case 'providers':
_populateProviders(node.expression);
break;
} }
return null; return null;
} }
@ -687,3 +791,19 @@ class _PipeMetadataVisitor extends Object with RecursiveAstVisitor<Object> {
_pure = _expressionToBool(pureValue, 'Pipe#pure'); _pure = _expressionToBool(pureValue, 'Pipe#pure');
} }
} }
dynamic _readIdentifier(dynamic el) {
if (el is PrefixedIdentifier) {
return new CompileIdentifierMetadata(name: '${el.identifier}', prefix: '${el.prefix}');
} else if (el is SimpleIdentifier) {
return new CompileIdentifierMetadata(name: '$el');
} else if (el is SimpleStringLiteral){
return el.value;
} else {
throw new ArgumentError('Incorrect identifier "${el}".');
}
}

View File

@ -5,6 +5,7 @@ import 'dart:async';
import 'package:analyzer/analyzer.dart'; import 'package:analyzer/analyzer.dart';
import 'package:barback/barback.dart' show AssetId; import 'package:barback/barback.dart' show AssetId;
import 'package:angular2/src/compiler/directive_metadata.dart' show CompileIdentifierMetadata;
import 'package:angular2/src/compiler/template_compiler.dart'; import 'package:angular2/src/compiler/template_compiler.dart';
import 'package:angular2/src/transform/common/annotation_matcher.dart'; import 'package:angular2/src/transform/common/annotation_matcher.dart';
import 'package:angular2/src/transform/common/asset_reader.dart'; import 'package:angular2/src/transform/common/asset_reader.dart';
@ -14,6 +15,7 @@ import 'package:angular2/src/transform/common/interface_matcher.dart';
import 'package:angular2/src/transform/common/logging.dart'; import 'package:angular2/src/transform/common/logging.dart';
import 'package:angular2/src/transform/common/ng_compiler.dart'; import 'package:angular2/src/transform/common/ng_compiler.dart';
import 'package:angular2/src/transform/common/ng_meta.dart'; import 'package:angular2/src/transform/common/ng_meta.dart';
import 'package:angular2/src/transform/common/url_resolver.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone; import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'inliner.dart'; import 'inliner.dart';
@ -89,14 +91,15 @@ class _NgMetaVisitor extends Object with SimpleAstVisitor<Object> {
@override @override
Object visitClassDeclaration(ClassDeclaration node) { Object visitClassDeclaration(ClassDeclaration node) {
_normalizations.add( _normalizations.add(
_reader.readTypeMetadata(node, assetId).then((compileMetadataWithType) { _reader.readTypeMetadata(node, assetId).then((compileMetadataWithIdentifier) {
if (compileMetadataWithType != null) { if (compileMetadataWithIdentifier!= null) {
ngMeta.types[compileMetadataWithType.type.name] = ngMeta.identifiers[compileMetadataWithIdentifier.identifier.name] =
compileMetadataWithType; compileMetadataWithIdentifier;
} }
}).catchError((err) { }).catchError((err) {
log.error('ERROR: $err', asset: assetId); log.error('ERROR: $err', asset: assetId);
})); }));
return null; return null;
} }
@ -108,6 +111,11 @@ class _NgMetaVisitor extends Object with SimpleAstVisitor<Object> {
// doesn't support decorators on variable declarations (see // doesn't support decorators on variable declarations (see
// angular/angular#1747 and angular/ts2dart#249 for context). // angular/angular#1747 and angular/ts2dart#249 for context).
outer: for (var variable in node.variables.variables) { outer: for (var variable in node.variables.variables) {
if (variable.isConst) {
ngMeta.identifiers[variable.name.name] =
new CompileIdentifierMetadata(name: variable.name.name, moduleUrl: toAssetUri(assetId));
}
var initializer = variable.initializer; var initializer = variable.initializer;
if (initializer != null && initializer is ListLiteral) { if (initializer != null && initializer is ListLiteral) {
var otherNames = []; var otherNames = [];

View File

@ -74,8 +74,8 @@ class _CompileDataCreator {
var hasTemplate = ngDeps != null && var hasTemplate = ngDeps != null &&
ngDeps.reflectables != null && ngDeps.reflectables != null &&
ngDeps.reflectables.any((reflectable) { ngDeps.reflectables.any((reflectable) {
if (ngMeta.types.containsKey(reflectable.name)) { if (ngMeta.identifiers.containsKey(reflectable.name)) {
final metadata = ngMeta.types[reflectable.name]; final metadata = ngMeta.identifiers[reflectable.name];
return metadata is CompileDirectiveMetadata && return metadata is CompileDirectiveMetadata &&
metadata.template != null; metadata.template != null;
} }
@ -91,8 +91,8 @@ class _CompileDataCreator {
final platformPipes = await _readPlatformTypes(this.platformPipes, 'pipes'); final platformPipes = await _readPlatformTypes(this.platformPipes, 'pipes');
for (var reflectable in ngDeps.reflectables) { for (var reflectable in ngDeps.reflectables) {
if (ngMeta.types.containsKey(reflectable.name)) { if (ngMeta.identifiers.containsKey(reflectable.name)) {
final compileDirectiveMetadata = ngMeta.types[reflectable.name]; final compileDirectiveMetadata = ngMeta.identifiers[reflectable.name];
if (compileDirectiveMetadata is CompileDirectiveMetadata && if (compileDirectiveMetadata is CompileDirectiveMetadata &&
compileDirectiveMetadata.template != null) { compileDirectiveMetadata.template != null) {
final compileDatum = new NormalizedComponentWithViewDirectives( final compileDatum = new NormalizedComponentWithViewDirectives(
@ -106,6 +106,9 @@ class _CompileDataCreator {
compileDatum.pipes compileDatum.pipes
.addAll(_resolveTypeMetadata(ngMetaMap, reflectable.pipes)); .addAll(_resolveTypeMetadata(ngMetaMap, reflectable.pipes));
compileData[reflectable] = compileDatum; compileData[reflectable] = compileDatum;
_resolveDiDependencyMetadata(ngMetaMap, compileDirectiveMetadata.type, compileDirectiveMetadata.type.diDeps);
_resolveProviderMetadata(ngMetaMap, compileDirectiveMetadata);
} }
} }
} }
@ -117,16 +120,16 @@ class _CompileDataCreator {
var resolvedMetadata = []; var resolvedMetadata = [];
for (var dep in prefixedTypes) { for (var dep in prefixedTypes) {
if (!ngMetaMap.containsKey(dep.prefix)) { if (!ngMetaMap.containsKey(dep.prefix)) {
log.warning( log.error(
'Missing prefix "${dep.prefix}" ' 'Missing prefix "${dep.prefix}" '
'needed by "${dep}" from metadata map', 'needed by "${dep}" from metadata map,',
asset: entryPoint); asset: entryPoint);
continue; return null;
} }
final depNgMeta = ngMetaMap[dep.prefix]; final depNgMeta = ngMetaMap[dep.prefix];
if (depNgMeta.types.containsKey(dep.name)) { if (depNgMeta.identifiers.containsKey(dep.name)) {
resolvedMetadata.add(depNgMeta.types[dep.name]); resolvedMetadata.add(depNgMeta.identifiers[dep.name]);
} else if (depNgMeta.aliases.containsKey(dep.name)) { } else if (depNgMeta.aliases.containsKey(dep.name)) {
resolvedMetadata.addAll(depNgMeta.flatten(dep.name)); resolvedMetadata.addAll(depNgMeta.flatten(dep.name));
} else { } else {
@ -141,6 +144,86 @@ class _CompileDataCreator {
return resolvedMetadata; return resolvedMetadata;
} }
void _resolveProviderMetadata(Map<String, NgMeta> ngMetaMap, CompileDirectiveMetadata dirMeta) {
final neededBy = dirMeta.type;
if (dirMeta.providers == null) return;
final resolvedProviders = [];
for (var provider in dirMeta.providers) {
final alias = _resolveAlias(ngMetaMap, neededBy, provider.token);
if (alias != null) {
resolvedProviders.addAll(alias.map((a) => new CompileProviderMetadata(token:a)));
} else {
provider.token = _resolveIdentifier(ngMetaMap, neededBy, provider.token);
if (provider.useClass != null) {
provider.useClass = _resolveIdentifier(ngMetaMap, neededBy, provider.useClass);
}
resolvedProviders.add(provider);
}
}
dirMeta.providers = resolvedProviders;
}
void _resolveDiDependencyMetadata(
Map<String, NgMeta> ngMetaMap,CompileTypeMetadata neededBy, List<CompileDiDependencyMetadata> deps) {
if (deps == null) return;
for (var dep in deps) {
dep.token = _resolveIdentifier(ngMetaMap, neededBy, dep.token);
}
}
dynamic _resolveAlias(Map<String, NgMeta> ngMetaMap, CompileTypeMetadata neededBy, dynamic id) {
if (id is String || id == null) return null;
final prefix = id.prefix == null ? "" : id.prefix;
if (!ngMetaMap.containsKey(prefix)) {
log.error(
'Missing prefix "${prefix}" '
'needed by "${neededBy.name}" from metadata map',
asset: entryPoint);
return null;
}
final depNgMeta = ngMetaMap[prefix];
if (depNgMeta.aliases.containsKey(id.name)) {
return depNgMeta.flatten(id.name);
} else {
return null;
}
}
dynamic _resolveIdentifier(Map<String, NgMeta> ngMetaMap, CompileTypeMetadata neededBy, dynamic id) {
if (id is String || id == null) return id;
final prefix = id.prefix == null ? "" : id.prefix;
if (!ngMetaMap.containsKey(prefix)) {
log.error(
'Missing prefix "${prefix}" '
'needed by "${neededBy.name}" from metadata map',
asset: entryPoint);
return null;
}
final depNgMeta = ngMetaMap[prefix];
if (depNgMeta.identifiers.containsKey(id.name)) {
return depNgMeta.identifiers[id.name];
} else if (_isPrimitive(id.name)) {
return id;
} else {
log.error(
'Missing identifier "${id.name}" '
'needed by "${neededBy.name}" from metadata map',
asset: entryPoint);
return null;
}
}
bool _isPrimitive(String typeName) =>
typeName == "String" || typeName == "Object" || typeName == "num" || typeName == "int" || typeName == "double" || typeName == "bool";
Future<List<dynamic>> _readPlatformTypes( Future<List<dynamic>> _readPlatformTypes(
List<String> inputPlatformTypes, String configOption) async { List<String> inputPlatformTypes, String configOption) async {
if (inputPlatformTypes == null) return const []; if (inputPlatformTypes == null) return const [];
@ -168,8 +251,8 @@ class _CompileDataCreator {
if (jsonString != null && jsonString.isNotEmpty) { if (jsonString != null && jsonString.isNotEmpty) {
var newMetadata = new NgMeta.fromJson(JSON.decode(jsonString)); var newMetadata = new NgMeta.fromJson(JSON.decode(jsonString));
if (newMetadata.types.containsKey(token)) { if (newMetadata.identifiers.containsKey(token)) {
return [newMetadata.types[token]]; return [newMetadata.identifiers[token]];
} else if (newMetadata.aliases.containsKey(token)) { } else if (newMetadata.aliases.containsKey(token)) {
return newMetadata.flatten(token); return newMetadata.flatten(token);
} else { } else {
@ -194,7 +277,6 @@ class _CompileDataCreator {
return map; return map;
} }
final resolver = const TransformerUrlResolver(); final resolver = const TransformerUrlResolver();
ngMeta.ngDeps.imports ngMeta.ngDeps.imports
.where((model) => !isDartCoreUri(model.uri)) .where((model) => !isDartCoreUri(model.uri))
.forEach((model) { .forEach((model) {
@ -242,6 +324,7 @@ class _CompileDataCreator {
var ngMeta = retVal[prefix] = new NgMeta.empty(); var ngMeta = retVal[prefix] = new NgMeta.empty();
for (var importAssetUri in prefixToImports[prefix]) { for (var importAssetUri in prefixToImports[prefix]) {
var metaAssetId = fromUri(toMetaExtension(importAssetUri)); var metaAssetId = fromUri(toMetaExtension(importAssetUri));
if (await reader.hasInput(metaAssetId)) { if (await reader.hasInput(metaAssetId)) {
try { try {
var jsonString = await reader.readAsString(metaAssetId); var jsonString = await reader.readAsString(metaAssetId);

View File

@ -42,16 +42,18 @@ Future<Outputs> processTemplates(AssetReader reader, AssetId assetId,
var viewDefResults = await createCompileData( var viewDefResults = await createCompileData(
reader, assetId, platformDirectives, platformPipes); reader, assetId, platformDirectives, platformPipes);
if (viewDefResults == null) return null; if (viewDefResults == null) return null;
final compileTypeMetadatas = viewDefResults.ngMeta.types.values; final compileTypeMetadatas = viewDefResults.ngMeta.identifiers.values;
if (compileTypeMetadatas.isNotEmpty) { if (compileTypeMetadatas.isNotEmpty) {
var processor = new reg.Processor(); var processor = new reg.Processor();
compileTypeMetadatas.forEach(processor.process); compileTypeMetadatas.forEach(processor.process);
viewDefResults.ngMeta.ngDeps.getters if (viewDefResults.ngMeta.ngDeps != null) {
.addAll(processor.getterNames.map((e) => e.sanitizedName)); viewDefResults.ngMeta.ngDeps.getters
viewDefResults.ngMeta.ngDeps.setters .addAll(processor.getterNames.map((e) => e.sanitizedName));
.addAll(processor.setterNames.map((e) => e.sanitizedName)); viewDefResults.ngMeta.ngDeps.setters
viewDefResults.ngMeta.ngDeps.methods .addAll(processor.setterNames.map((e) => e.sanitizedName));
.addAll(processor.methodNames.map((e) => e.sanitizedName)); viewDefResults.ngMeta.ngDeps.methods
.addAll(processor.methodNames.map((e) => e.sanitizedName));
}
} }
var templateCompiler = zone.templateCompiler; var templateCompiler = zone.templateCompiler;
if (templateCompiler == null) { if (templateCompiler == null) {
@ -98,4 +100,4 @@ class Outputs {
final SourceModule templatesSource; final SourceModule templatesSource;
Outputs._(this.ngDeps, this.templatesSource); Outputs._(this.ngDeps, this.templatesSource);
} }

View File

@ -8,7 +8,7 @@ import 'package:guinness/guinness.dart';
main() => allTests(); main() => allTests();
void allTests() { void allTests() {
var mockData = [ var mockDirMetadata = [
CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N1')), CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N1')),
CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N2')), CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N2')),
CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N3')), CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N3')),
@ -28,14 +28,16 @@ void allTests() {
it('should be lossless', () { it('should be lossless', () {
var a = new NgMeta.empty(); var a = new NgMeta.empty();
a.types['T0'] = mockData[0]; a.identifiers['T0'] = mockDirMetadata[0];
a.types['T1'] = mockData[1]; a.identifiers['T1'] = mockDirMetadata[1];
a.types['T2'] = mockData[2]; a.identifiers['T2'] = mockDirMetadata[2];
a.types['T3'] = mockData[3]; a.identifiers['T3'] = mockDirMetadata[3];
a.aliases['a1'] = ['T1']; a.aliases['a1'] = ['T1'];
a.aliases['a2'] = ['a1']; a.aliases['a2'] = ['a1'];
a.aliases['a3'] = ['T3', 'a2']; a.aliases['a3'] = ['T3', 'a2'];
a.aliases['a4'] = ['a3', 'T3']; a.aliases['a4'] = ['a3', 'T3'];
_checkSimilar(a, new NgMeta.fromJson(a.toJson())); _checkSimilar(a, new NgMeta.fromJson(a.toJson()));
}); });
}); });
@ -43,35 +45,36 @@ void allTests() {
describe('flatten', () { describe('flatten', () {
it('should include recursive aliases.', () { it('should include recursive aliases.', () {
var a = new NgMeta.empty(); var a = new NgMeta.empty();
a.types['T0'] = mockData[0]; a.identifiers['T0'] = mockDirMetadata[0];
a.types['T1'] = mockData[1]; a.identifiers['T1'] = mockDirMetadata[1];
a.types['T2'] = mockData[2]; a.identifiers['T2'] = mockDirMetadata[2];
a.types['T3'] = mockData[3]; a.identifiers['T3'] = mockDirMetadata[3];
a.aliases['a1'] = ['T1']; a.aliases['a1'] = ['T1'];
a.aliases['a2'] = ['a1']; a.aliases['a2'] = ['a1'];
a.aliases['a3'] = ['T3', 'a2']; a.aliases['a3'] = ['T3', 'a2'];
a.aliases['a4'] = ['a3', 'T0']; a.aliases['a4'] = ['a3', 'T0'];
expect(a.flatten('a4')).toEqual([mockData[3], mockData[1], mockData[0]]);
expect(a.flatten('a4')).toEqual([mockDirMetadata[3], mockDirMetadata[1], mockDirMetadata[0]]);
}); });
it('should detect cycles.', () { it('should detect cycles.', () {
var a = new NgMeta.empty(); var a = new NgMeta.empty();
a.types['T0'] = mockData[0]; a.identifiers['T0'] = mockDirMetadata[0];
a.aliases['a1'] = ['T0', 'a1']; a.aliases['a1'] = ['T0', 'a1'];
a.aliases['a2'] = ['a1']; a.aliases['a2'] = ['a1'];
expect(a.flatten('a1')).toEqual([mockData[0]]); expect(a.flatten('a1')).toEqual([mockDirMetadata[0]]);
}); });
}); });
describe('merge', () { describe('merge', () {
it('should merge all types on addAll', () { it('should merge all identifiers on addAll', () {
var a = new NgMeta.empty(); var a = new NgMeta.empty();
var b = new NgMeta.empty(); var b = new NgMeta.empty();
a.types['T0'] = mockData[0]; a.identifiers['T0'] = mockDirMetadata[0];
b.types['T1'] = mockData[1]; b.identifiers['T1'] = mockDirMetadata[1];
a.addAll(b); a.addAll(b);
expect(a.types).toContain('T1'); expect(a.identifiers).toContain('T1');
expect(a.types['T1']).toEqual(mockData[1]); expect(a.identifiers['T1']).toEqual(mockDirMetadata[1]);
}); });
it('should merge all aliases on addAll', () { it('should merge all aliases on addAll', () {
@ -87,12 +90,12 @@ void allTests() {
} }
_checkSimilar(NgMeta a, NgMeta b) { _checkSimilar(NgMeta a, NgMeta b) {
expect(a.types.length).toEqual(b.types.length); expect(a.identifiers.length).toEqual(b.identifiers.length);
expect(a.aliases.length).toEqual(b.aliases.length); expect(a.aliases.length).toEqual(b.aliases.length);
for (var k in a.types.keys) { for (var k in a.identifiers.keys) {
expect(b.types).toContain(k); expect(b.identifiers).toContain(k);
var at = a.types[k]; var at = a.identifiers[k];
var bt = b.types[k]; var bt = b.identifiers[k];
expect(at.type.name).toEqual(bt.type.name); expect(at.type.name).toEqual(bt.type.name);
} }
for (var k in a.aliases.keys) { for (var k in a.aliases.keys) {

View File

@ -41,15 +41,15 @@ void allTests() {
// Establish some test NgMeta objects with one Component each. // Establish some test NgMeta objects with one Component each.
var fooComponentMeta = createFoo(moduleBase); var fooComponentMeta = createFoo(moduleBase);
fooNgMeta = new NgMeta(ngDeps: new NgDepsModel()); fooNgMeta = new NgMeta(ngDeps: new NgDepsModel());
fooNgMeta.types[fooComponentMeta.type.name] = fooComponentMeta; fooNgMeta.identifiers[fooComponentMeta.type.name] = fooComponentMeta;
var barComponentMeta = createBar(moduleBase); var barComponentMeta = createBar(moduleBase);
barNgMeta = new NgMeta(ngDeps: new NgDepsModel()); barNgMeta = new NgMeta(ngDeps: new NgDepsModel());
barNgMeta.types[barComponentMeta.type.name] = barComponentMeta; barNgMeta.identifiers[barComponentMeta.type.name] = barComponentMeta;
var bazComponentMeta = createBaz(moduleBase); var bazComponentMeta = createBaz(moduleBase);
bazNgMeta = new NgMeta(ngDeps: new NgDepsModel()); bazNgMeta = new NgMeta(ngDeps: new NgDepsModel());
barNgMeta.types[bazComponentMeta.type.name] = bazComponentMeta; barNgMeta.identifiers[bazComponentMeta.type.name] = bazComponentMeta;
fooAssetId = new AssetId('a', toSummaryExtension('lib/foo.dart')); fooAssetId = new AssetId('a', toSummaryExtension('lib/foo.dart'));
barAssetId = new AssetId('a', toSummaryExtension('lib/bar.dart')); barAssetId = new AssetId('a', toSummaryExtension('lib/bar.dart'));
@ -63,11 +63,11 @@ void allTests() {
updateReader(); updateReader();
var extracted = await _testLink(reader, fooAssetId); var extracted = await _testLink(reader, fooAssetId);
expect(extracted.types).toContain('FooComponent'); expect(extracted.identifiers).toContain('FooComponent');
expect(extracted.types).toContain('BarComponent'); expect(extracted.identifiers).toContain('BarComponent');
expect(extracted.types['FooComponent'].selector).toEqual('foo'); expect(extracted.identifiers['FooComponent'].selector).toEqual('foo');
expect(extracted.types['BarComponent'].selector).toEqual('bar'); expect(extracted.identifiers['BarComponent'].selector).toEqual('bar');
}); });
it('should include `DirectiveMetadata` recursively from exported files.', it('should include `DirectiveMetadata` recursively from exported files.',
@ -77,13 +77,13 @@ void allTests() {
updateReader(); updateReader();
var extracted = await _testLink(reader, fooAssetId); var extracted = await _testLink(reader, fooAssetId);
expect(extracted.types).toContain('FooComponent'); expect(extracted.identifiers).toContain('FooComponent');
expect(extracted.types).toContain('BarComponent'); expect(extracted.identifiers).toContain('BarComponent');
expect(extracted.types).toContain('BazComponent'); expect(extracted.identifiers).toContain('BazComponent');
expect(extracted.types['FooComponent'].selector).toEqual('foo'); expect(extracted.identifiers['FooComponent'].selector).toEqual('foo');
expect(extracted.types['BarComponent'].selector).toEqual('bar'); expect(extracted.identifiers['BarComponent'].selector).toEqual('bar');
expect(extracted.types['BazComponent'].selector).toEqual('baz'); expect(extracted.identifiers['BazComponent'].selector).toEqual('baz');
}); });
it('should handle `DirectiveMetadata` export cycles gracefully.', () async { it('should handle `DirectiveMetadata` export cycles gracefully.', () async {
@ -93,9 +93,9 @@ void allTests() {
updateReader(); updateReader();
var extracted = await _testLink(reader, bazAssetId); var extracted = await _testLink(reader, bazAssetId);
expect(extracted.types).toContain('FooComponent'); expect(extracted.identifiers).toContain('FooComponent');
expect(extracted.types).toContain('BarComponent'); expect(extracted.identifiers).toContain('BarComponent');
expect(extracted.types).toContain('BazComponent'); expect(extracted.identifiers).toContain('BazComponent');
}); });
it( it(
@ -109,11 +109,11 @@ void allTests() {
var extracted = await _testLink(reader, fooAssetId); var extracted = await _testLink(reader, fooAssetId);
expect(extracted.types).toContain('FooComponent'); expect(extracted.identifiers).toContain('FooComponent');
expect(extracted.types).toContain('BarComponent'); expect(extracted.identifiers).toContain('BarComponent');
expect(extracted.types['FooComponent'].selector).toEqual('foo'); expect(extracted.identifiers['FooComponent'].selector).toEqual('foo');
expect(extracted.types['BarComponent'].selector).toEqual('bar'); expect(extracted.identifiers['BarComponent'].selector).toEqual('bar');
}); });
}); });

View File

@ -6,6 +6,7 @@ import 'package:barback/barback.dart';
import 'package:dart_style/dart_style.dart'; import 'package:dart_style/dart_style.dart';
import 'package:guinness/guinness.dart'; import 'package:guinness/guinness.dart';
import 'package:angular2/src/compiler/directive_metadata.dart' show CompileIdentifierMetadata;
import 'package:angular2/src/core/change_detection/change_detection.dart'; import 'package:angular2/src/core/change_detection/change_detection.dart';
import 'package:angular2/src/platform/server/html_adapter.dart'; import 'package:angular2/src/platform/server/html_adapter.dart';
import 'package:angular2/src/core/linker/interfaces.dart' show LifecycleHooks; import 'package:angular2/src/core/linker/interfaces.dart' show LifecycleHooks;
@ -317,10 +318,10 @@ void allTests() {
it('should include hooks for implemented types (single)', () async { it('should include hooks for implemented types (single)', () async {
var ngMeta = await _testCreateModel('interfaces_files/soup.dart'); var ngMeta = await _testCreateModel('interfaces_files/soup.dart');
expect(ngMeta.types.isNotEmpty).toBeTrue(); expect(ngMeta.identifiers.isNotEmpty).toBeTrue();
expect(ngMeta.types['ChangingSoupComponent']).toBeNotNull(); expect(ngMeta.identifiers['ChangingSoupComponent']).toBeNotNull();
expect(ngMeta.types['ChangingSoupComponent'].selector).toEqual('[soup]'); expect(ngMeta.identifiers['ChangingSoupComponent'].selector).toEqual('[soup]');
expect(ngMeta.types['ChangingSoupComponent'].lifecycleHooks) expect(ngMeta.identifiers['ChangingSoupComponent'].lifecycleHooks)
.toContain(LifecycleHooks.OnChanges); .toContain(LifecycleHooks.OnChanges);
}); });
@ -328,10 +329,10 @@ void allTests() {
var ngMeta = await _testCreateModel( var ngMeta = await _testCreateModel(
'multiple_interface_lifecycle_files/soup.dart'); 'multiple_interface_lifecycle_files/soup.dart');
expect(ngMeta.types.isNotEmpty).toBeTrue(); expect(ngMeta.identifiers.isNotEmpty).toBeTrue();
expect(ngMeta.types['MultiSoupComponent']).toBeNotNull(); expect(ngMeta.identifiers['MultiSoupComponent']).toBeNotNull();
expect(ngMeta.types['MultiSoupComponent'].selector).toEqual('[soup]'); expect(ngMeta.identifiers['MultiSoupComponent'].selector).toEqual('[soup]');
expect(ngMeta.types['MultiSoupComponent'].lifecycleHooks) expect(ngMeta.identifiers['MultiSoupComponent'].lifecycleHooks)
..toContain(LifecycleHooks.OnChanges) ..toContain(LifecycleHooks.OnChanges)
..toContain(LifecycleHooks.OnDestroy) ..toContain(LifecycleHooks.OnDestroy)
..toContain(LifecycleHooks.OnInit); ..toContain(LifecycleHooks.OnInit);
@ -345,18 +346,18 @@ void allTests() {
'absolute_url_expression_files/hello.dart', 'absolute_url_expression_files/hello.dart',
reader: fakeReader); reader: fakeReader);
expect(ngMeta.types.isNotEmpty).toBeTrue(); expect(ngMeta.identifiers.isNotEmpty).toBeTrue();
expect(ngMeta.types['HelloCmp']).toBeNotNull(); expect(ngMeta.identifiers['HelloCmp']).toBeNotNull();
expect(ngMeta.types['HelloCmp'].selector).toEqual('hello-app'); expect(ngMeta.identifiers['HelloCmp'].selector).toEqual('hello-app');
}); });
it('should populate all provided values for Components & Directives', it('should populate all provided values for Components & Directives',
() async { () async {
var ngMeta = await _testCreateModel('unusual_component_files/hello.dart'); var ngMeta = await _testCreateModel('unusual_component_files/hello.dart');
expect(ngMeta.types.isNotEmpty).toBeTrue(); expect(ngMeta.identifiers.isNotEmpty).toBeTrue();
var component = ngMeta.types['UnusualComp']; var component = ngMeta.identifiers['UnusualComp'];
expect(component).toBeNotNull(); expect(component).toBeNotNull();
expect(component.selector).toEqual('unusual-comp'); expect(component.selector).toEqual('unusual-comp');
expect(component.isComponent).toBeTrue(); expect(component.isComponent).toBeTrue();
@ -370,7 +371,7 @@ void allTests() {
expect(component.hostAttributes).toContain('hostKey'); expect(component.hostAttributes).toContain('hostKey');
expect(component.hostAttributes['hostKey']).toEqual('hostValue'); expect(component.hostAttributes['hostKey']).toEqual('hostValue');
var directive = ngMeta.types['UnusualDirective']; var directive = ngMeta.identifiers['UnusualDirective'];
expect(directive).toBeNotNull(); expect(directive).toBeNotNull();
expect(directive.selector).toEqual('unusual-directive'); expect(directive.selector).toEqual('unusual-directive');
expect(directive.isComponent).toBeFalse(); expect(directive.isComponent).toBeFalse();
@ -388,10 +389,10 @@ void allTests() {
it('should include hooks for implemented types (single)', () async { it('should include hooks for implemented types (single)', () async {
var ngMeta = await _testCreateModel('interfaces_files/soup.dart'); var ngMeta = await _testCreateModel('interfaces_files/soup.dart');
expect(ngMeta.types.isNotEmpty).toBeTrue(); expect(ngMeta.identifiers.isNotEmpty).toBeTrue();
expect(ngMeta.types['ChangingSoupComponent']).toBeNotNull(); expect(ngMeta.identifiers['ChangingSoupComponent']).toBeNotNull();
expect(ngMeta.types['ChangingSoupComponent'].selector).toEqual('[soup]'); expect(ngMeta.identifiers['ChangingSoupComponent'].selector).toEqual('[soup]');
expect(ngMeta.types['ChangingSoupComponent'].lifecycleHooks) expect(ngMeta.identifiers['ChangingSoupComponent'].lifecycleHooks)
.toContain(LifecycleHooks.OnChanges); .toContain(LifecycleHooks.OnChanges);
}); });
@ -399,10 +400,10 @@ void allTests() {
var ngMeta = await _testCreateModel( var ngMeta = await _testCreateModel(
'multiple_interface_lifecycle_files/soup.dart'); 'multiple_interface_lifecycle_files/soup.dart');
expect(ngMeta.types.isNotEmpty).toBeTrue(); expect(ngMeta.identifiers.isNotEmpty).toBeTrue();
expect(ngMeta.types['MultiSoupComponent']).toBeNotNull(); expect(ngMeta.identifiers['MultiSoupComponent']).toBeNotNull();
expect(ngMeta.types['MultiSoupComponent'].selector).toEqual('[soup]'); expect(ngMeta.identifiers['MultiSoupComponent'].selector).toEqual('[soup]');
expect(ngMeta.types['MultiSoupComponent'].lifecycleHooks) expect(ngMeta.identifiers['MultiSoupComponent'].lifecycleHooks)
..toContain(LifecycleHooks.OnChanges) ..toContain(LifecycleHooks.OnChanges)
..toContain(LifecycleHooks.OnDestroy) ..toContain(LifecycleHooks.OnDestroy)
..toContain(LifecycleHooks.OnInit); ..toContain(LifecycleHooks.OnInit);
@ -416,10 +417,10 @@ void allTests() {
'absolute_url_expression_files/hello.dart', 'absolute_url_expression_files/hello.dart',
reader: fakeReader); reader: fakeReader);
expect(ngMeta.types.isNotEmpty).toBeTrue(); expect(ngMeta.identifiers.isNotEmpty).toBeTrue();
expect(ngMeta.types['HelloCmp']).toBeNotNull(); expect(ngMeta.identifiers['HelloCmp']).toBeNotNull();
expect(ngMeta.types['HelloCmp'].template).toBeNotNull(); expect(ngMeta.identifiers['HelloCmp'].template).toBeNotNull();
expect(ngMeta.types['HelloCmp'].template.templateUrl) expect(ngMeta.identifiers['HelloCmp'].template.templateUrl)
.toEqual('asset:other_package/lib/template.html'); .toEqual('asset:other_package/lib/template.html');
}); });
@ -445,6 +446,27 @@ void allTests() {
}); });
}); });
describe("identifiers", () {
it("should populate `identifier` with class types.", () async {
var model = (await _testCreateModel('identifiers/classes.dart'));
final moduleUrl = "asset:angular2/test/transform/directive_processor/identifiers/classes.dart";
expect(model.identifiers['Service1'].name).toEqual('Service1');
expect(model.identifiers['Service1'].moduleUrl).toEqual(moduleUrl);
expect(model.identifiers['Service2'].name).toEqual('Service2');
expect(model.identifiers['Service2'].moduleUrl).toEqual(moduleUrl);
});
it("should populate `identifier` with constants.", () async {
var model = (await _testCreateModel('identifiers/constants.dart'));
final moduleUrl = "asset:angular2/test/transform/directive_processor/identifiers/constants.dart";
expect(model.identifiers['a']).
toHaveSameProps(new CompileIdentifierMetadata(name: 'a', moduleUrl: moduleUrl));
expect(model.identifiers['b']).
toHaveSameProps(new CompileIdentifierMetadata(name: 'b', moduleUrl: moduleUrl));
expect(model.identifiers['c']).toBeNull();
});
});
describe('directives', () { describe('directives', () {
final reflectableNamed = (NgDepsModel model, String name) { final reflectableNamed = (NgDepsModel model, String name) {
return model.reflectables return model.reflectables
@ -537,27 +559,114 @@ void allTests() {
..prefix = 'dep2'); ..prefix = 'dep2');
}); });
it('should populate `diDependency`.',
() async {
var cmp =
(await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithDiDeps'];
expect(cmp).toBeNotNull();
var deps = cmp.type.diDeps;
expect(deps).toBeNotNull();
expect(deps.length).toEqual(2);
expect(deps[0].token.name).toEqual("ServiceDep");
expect(deps[1].token.name).toEqual("ServiceDep");
});
it('should populate `diDependency` using a string token.',
() async {
var cmp =
(await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithDiDepsStrToken'];
var deps = cmp.type.diDeps;
expect(deps).toBeNotNull();
expect(deps.length).toEqual(1);
expect(deps[0].token).toEqual("StringDep");
});
it('should populate `services`.',
() async {
var service =
(await _testCreateModel('directives_files/services.dart')).identifiers['Service'];
expect(service).toBeNotNull();
var deps = service.diDeps;
expect(deps).toBeNotNull();
expect(deps.length).toEqual(2);
expect(deps[0].token.name).toEqual("ServiceDep");
expect(deps[1].token.name).toEqual("ServiceDep");
});
it('should populate `providers` using types.',
() async {
var cmp =
(await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersTypes'];
expect(cmp).toBeNotNull();
expect(cmp.providers).toBeNotNull();
expect(cmp.providers.length).toEqual(2);
var firstToken = cmp.providers.first.token;
expect(firstToken.prefix).toEqual(null);
expect(firstToken.name).toEqual("ServiceDep");
var secondToken = cmp.providers[1].token;
expect(secondToken.prefix).toEqual("dep2");
expect(secondToken.name).toEqual("ServiceDep");
});
it('should populate `providers` using useClass.',
() async {
var cmp =
(await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersUseClass'];
expect(cmp).toBeNotNull();
expect(cmp.providers).toBeNotNull();
expect(cmp.providers.length).toEqual(1);
var token = cmp.providers.first.token;
var useClass = cmp.providers.first.useClass;
expect(token.prefix).toEqual(null);
expect(token.name).toEqual("ServiceDep");
expect(useClass.prefix).toEqual(null);
expect(useClass.name).toEqual("ServiceDep");
});
it('should populate `providers` using a string token.',
() async {
var cmp =
(await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersStringToken'];
expect(cmp).toBeNotNull();
expect(cmp.providers).toBeNotNull();
expect(cmp.providers.length).toEqual(1);
var token = cmp.providers.first.token;
expect(token).toEqual("StringDep");
});
it('should merge `outputs` from the annotation and fields.', () async { it('should merge `outputs` from the annotation and fields.', () async {
var model = await _testCreateModel('directives_files/components.dart'); var model = await _testCreateModel('directives_files/components.dart');
expect(model.types['ComponentWithOutputs'].outputs).toEqual( expect(model.identifiers['ComponentWithOutputs'].outputs).toEqual(
{'a': 'a', 'b': 'b', 'c': 'renamed', 'd': 'd', 'e': 'get-renamed'}); {'a': 'a', 'b': 'b', 'c': 'renamed', 'd': 'd', 'e': 'get-renamed'});
}); });
it('should merge `inputs` from the annotation and fields.', () async { it('should merge `inputs` from the annotation and fields.', () async {
var model = await _testCreateModel('directives_files/components.dart'); var model = await _testCreateModel('directives_files/components.dart');
expect(model.types['ComponentWithInputs'].inputs).toEqual( expect(model.identifiers['ComponentWithInputs'].inputs).toEqual(
{'a': 'a', 'b': 'b', 'c': 'renamed', 'd': 'd', 'e': 'set-renamed'}); {'a': 'a', 'b': 'b', 'c': 'renamed', 'd': 'd', 'e': 'set-renamed'});
}); });
it('should merge host bindings from the annotation and fields.', () async { it('should merge host bindings from the annotation and fields.', () async {
var model = await _testCreateModel('directives_files/components.dart'); var model = await _testCreateModel('directives_files/components.dart');
expect(model.types['ComponentWithHostBindings'].hostProperties) expect(model.identifiers['ComponentWithHostBindings'].hostProperties)
.toEqual({'a': 'a', 'b': 'b', 'renamed': 'c', 'd': 'd', 'get-renamed': 'e'}); .toEqual({'a': 'a', 'b': 'b', 'renamed': 'c', 'd': 'd', 'get-renamed': 'e'});
}); });
it('should merge host listeners from the annotation and fields.', () async { it('should merge host listeners from the annotation and fields.', () async {
var model = await _testCreateModel('directives_files/components.dart'); var model = await _testCreateModel('directives_files/components.dart');
expect(model.types['ComponentWithHostListeners'].hostListeners).toEqual({ expect(model.identifiers['ComponentWithHostListeners'].hostListeners).toEqual({
'a': 'onA()', 'a': 'onA()',
'b': 'onB()', 'b': 'onB()',
'c': 'onC(\$event.target,\$event.target.value)' 'c': 'onC(\$event.target,\$event.target.value)'
@ -617,13 +726,13 @@ void allTests() {
describe('pipes', () { describe('pipes', () {
it('should read the pipe name', () async { it('should read the pipe name', () async {
var model = await _testCreateModel('pipe_files/pipes.dart'); var model = await _testCreateModel('pipe_files/pipes.dart');
expect(model.types['NameOnlyPipe'].name).toEqual('nameOnly'); expect(model.identifiers['NameOnlyPipe'].name).toEqual('nameOnly');
expect(model.types['NameOnlyPipe'].pure).toBe(false); expect(model.identifiers['NameOnlyPipe'].pure).toBe(false);
}); });
it('should read the pure flag', () async { it('should read the pure flag', () async {
var model = await _testCreateModel('pipe_files/pipes.dart'); var model = await _testCreateModel('pipe_files/pipes.dart');
expect(model.types['NameAndPurePipe'].pure).toBe(true); expect(model.identifiers['NameAndPurePipe'].pure).toBe(true);
}); });
}); });
} }

View File

@ -1,7 +1,7 @@
library angular2.test.transform.directive_processor.directive_files.components; library angular2.test.transform.directive_processor.directive_files.components;
import 'package:angular2/angular2.dart' import 'package:angular2/angular2.dart'
show Component, Directive, View, NgElement, Output, Input; show Component, Directive, View, NgElement, Output, Input, Provider;
import 'dep1.dart'; import 'dep1.dart';
import 'dep2.dart' as dep2; import 'dep2.dart' as dep2;
@ -84,3 +84,35 @@ class ComponentWithHostListeners {
@HostListener('c', ['\$event.target', '\$event.target.value']) void onC( @HostListener('c', ['\$event.target', '\$event.target.value']) void onC(
t, v) {} t, v) {}
} }
@Component(
selector: 'component-with-providers-types',
template: '',
providers: [ServiceDep, dep2.ServiceDep])
class ComponentWithProvidersTypes {}
@Component(
selector: 'component-with-providers-string-token',
template: '',
providers: [const Provider("StringDep", useClass: ServiceDep)])
class ComponentWithProvidersStringToken {}
@Component(
selector: 'component-with-providers-use-class',
template: '',
providers: [const Provider(ServiceDep, useClass: ServiceDep)])
class ComponentWithProvidersUseClass {}
@Component(
selector: 'component-with-di-deps',
template: '')
class ComponentWithDiDeps {
ComponentWithDiDeps(ServiceDep arg1, @Inject(ServiceDep) arg2);
}
@Component(
selector: 'component-with-di-deps-string-token',
template: '')
class ComponentWithDiDepsStrToken {
ComponentWithDiDepsStrToken(@Inject("StringDep") arg1);
}

View File

@ -1,6 +1,6 @@
library angular2.test.transform.directive_processor.directive_files.dep1; library angular2.test.transform.directive_processor.directive_files.dep1;
import 'package:angular2/angular2.dart' show Component, Directive, View, Pipe; import 'package:angular2/angular2.dart' show Component, Directive, View, Pipe, Injectable;
@Component(selector: 'dep1') @Component(selector: 'dep1')
@View(template: 'Dep1') @View(template: 'Dep1')
@ -8,3 +8,6 @@ class Dep {}
@Pipe(name: 'dep1') @Pipe(name: 'dep1')
class PipeDep {} class PipeDep {}
@Injectable()
class ServiceDep {}

View File

@ -1,6 +1,6 @@
library angular2.test.transform.directive_processor.directive_files.dep2; library angular2.test.transform.directive_processor.directive_files.dep2;
import 'package:angular2/angular2.dart' show Component, Directive, View, Pipe; import 'package:angular2/angular2.dart' show Component, Directive, View, Pipe, Injectable;
@Component(selector: 'dep2') @Component(selector: 'dep2')
@View(template: 'Dep2') @View(template: 'Dep2')
@ -8,3 +8,6 @@ class Dep {}
@Pipe(name: 'dep2') @Pipe(name: 'dep2')
class PipeDep {} class PipeDep {}
@Injectable()
class ServiceDep {}

View File

@ -0,0 +1,10 @@
library angular2.test.transform.directive_processor.directive_files.components;
import 'package:angular2/angular2.dart'
show Injectable, Inject;
import 'dep1.dart';
@Injectable()
class Service {
Service(ServiceDep arg1, @Inject(ServiceDep) arg2);
}

View File

@ -0,0 +1,11 @@
library angular2.test.transform.directive_processor.identifiers.classes;
import 'package:angular2/angular2.dart' show Injectable;
@Injectable()
class Service1 {}
@Injectable()
class Service2 {}
class Service3 {}

View File

@ -0,0 +1,5 @@
library angular2.test.transform.directive_processor.identifiers.constants;
const a = "a";
const b = "b";
var c = "c";

View File

@ -7,8 +7,8 @@ import 'foo.dart' as prefix;
@View(template: '') @View(template: '')
class MyComponent { class MyComponent {
final prefix.MyContext c; final prefix.MyContext c;
final String generatedValue; final prefix.MyDep generatedValue;
MyComponent(this.c, String inValue) { MyComponent(this.c, prefix.MyDep inValue) {
generatedValue = 'generated ' + inValue; generatedValue = inValue;
} }
} }

View File

@ -5,6 +5,7 @@ import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef;
import 'package:angular2/src/core/metadata.dart'; import 'package:angular2/src/core/metadata.dart';
import 'foo.dart' as prefix; import 'foo.dart' as prefix;
import 'package:angular2/src/core/metadata.template.dart' as i0; import 'package:angular2/src/core/metadata.template.dart' as i0;
import 'foo.template.dart' as i1;
export 'bar.dart'; export 'bar.dart';
var _visited = false; var _visited = false;
@ -16,15 +17,16 @@ void initReflector() {
MyComponent, MyComponent,
new _ngRef.ReflectionInfo( new _ngRef.ReflectionInfo(
const [ const [
const Component(selector: 'soup'), const Component(selector: 'soup'),
const View(template: ''), const View(template: ''),
hostViewFactory_MyComponent hostViewFactory_MyComponent
], ],
const [ const [
const [prefix.MyContext], const [prefix.MyContext],
const [String] const [prefix.MyDep]
], ],
(prefix.MyContext c, String inValue) => (prefix.MyContext c, prefix.MyDep inValue) =>
new MyComponent(c, inValue))); new MyComponent(c, inValue)));
i0.initReflector(); i0.initReflector();
} i1.initReflector();
}

View File

@ -1,6 +1,11 @@
library foo; library foo;
import 'package:angular2/angular2.dart';
@Injectable()
class MyDep {}
class MyContext { class MyContext {
final String selector; final MyDep selector;
const MyContext(this.selector); const MyContext(this.selector);
} }

View File

@ -15,7 +15,9 @@ import 'package:angular2/src/transform/common/code/ng_deps_code.dart';
import 'package:angular2/src/transform/common/code/source_module.dart'; import 'package:angular2/src/transform/common/code/source_module.dart';
import 'package:angular2/src/transform/common/zone.dart' as zone; import 'package:angular2/src/transform/common/zone.dart' as zone;
import 'package:angular2/src/transform/template_compiler/generator.dart'; import 'package:angular2/src/transform/template_compiler/generator.dart';
import 'package:angular2/src/transform/template_compiler/compile_data_creator.dart';
import 'package:angular2/src/transform/common/model/parameter_model.pb.dart';
import '../common/compile_directive_metadata/ng_for.ng_meta.dart' as ngMeta; import '../common/compile_directive_metadata/ng_for.ng_meta.dart' as ngMeta;
import '../common/ng_meta_helper.dart'; import '../common/ng_meta_helper.dart';
import '../common/read_file.dart'; import '../common/read_file.dart';
@ -57,7 +59,7 @@ void allTests() {
fooNgMeta = new NgMeta(ngDeps: new NgDepsModel() fooNgMeta = new NgMeta(ngDeps: new NgDepsModel()
..libraryUri = 'test.foo' ..libraryUri = 'test.foo'
..reflectables.add(new ReflectionInfoModel()..name = fooComponentMeta.type.name)); ..reflectables.add(new ReflectionInfoModel()..name = fooComponentMeta.type.name));
fooNgMeta.types[fooComponentMeta.type.name] = fooComponentMeta; fooNgMeta.identifiers[fooComponentMeta.type.name] = fooComponentMeta;
barComponentMeta = createBar(moduleBase); barComponentMeta = createBar(moduleBase);
barPipeMeta = createBarPipe(moduleBase); barPipeMeta = createBarPipe(moduleBase);
@ -65,14 +67,14 @@ void allTests() {
..libraryUri = 'test.bar' ..libraryUri = 'test.bar'
..reflectables.add(new ReflectionInfoModel()..name = barPipeMeta.type.name) ..reflectables.add(new ReflectionInfoModel()..name = barPipeMeta.type.name)
..reflectables.add(new ReflectionInfoModel()..name = barComponentMeta.type.name)); ..reflectables.add(new ReflectionInfoModel()..name = barComponentMeta.type.name));
barNgMeta.types[barComponentMeta.type.name] = barComponentMeta; barNgMeta.identifiers[barComponentMeta.type.name] = barComponentMeta;
barNgMeta.types[barPipeMeta.type.name] = barPipeMeta; barNgMeta.identifiers[barPipeMeta.type.name] = barPipeMeta;
bazComponentMeta = createBaz(moduleBase); bazComponentMeta = createBaz(moduleBase);
bazNgMeta = new NgMeta(ngDeps: new NgDepsModel() bazNgMeta = new NgMeta(ngDeps: new NgDepsModel()
..libraryUri = 'test.baz' ..libraryUri = 'test.baz'
..reflectables.add(new ReflectionInfoModel()..name = bazComponentMeta.type.name)); ..reflectables.add(new ReflectionInfoModel()..name = bazComponentMeta.type.name));
barNgMeta.types[bazComponentMeta.type.name] = bazComponentMeta; barNgMeta.identifiers[bazComponentMeta.type.name] = bazComponentMeta;
fooAssetId = new AssetId('a', 'lib/foo.ng_meta.json'); fooAssetId = new AssetId('a', 'lib/foo.ng_meta.json');
barAssetId = new AssetId('a', 'lib/bar.ng_meta.json'); barAssetId = new AssetId('a', 'lib/bar.ng_meta.json');
@ -114,6 +116,145 @@ void allTests() {
expect(_generatedCode(outputs)).not.toContain('notifyDispatcher'); expect(_generatedCode(outputs)).not.toContain('notifyDispatcher');
}); });
it('should generate generate diDeps of injectable services.', () async {
bazNgMeta.identifiers['Service2'] = new CompileTypeMetadata(
name: 'Service2',
moduleUrl: 'moduleUrl');
barNgMeta.identifiers['Service'] = new CompileTypeMetadata(
name: 'Service',
moduleUrl: 'moduleUrl',
diDeps: [new CompileDiDependencyMetadata(token: new CompileIdentifierMetadata(name: 'Service2'))]);
barNgMeta.ngDeps.imports.add(new ImportModel()..uri = 'package:a/baz.dart');
fooComponentMeta.template = new CompileTemplateMetadata(template: "import 'bar.dart';");
fooComponentMeta.providers = [
new CompileProviderMetadata(
token: new CompileIdentifierMetadata(name: 'Service'),
useClass: new CompileTypeMetadata(name: 'Service')
)
];
final viewAnnotation = new AnnotationModel()..name = 'View'..isView = true;
final reflectable = fooNgMeta.ngDeps.reflectables.first;
reflectable.annotations.add(viewAnnotation);
fooNgMeta.ngDeps.imports.add(new ImportModel()..uri = 'package:a/bar.dart');
updateReader();
final viewDefResults = await createCompileData(reader, fooAssetId, [], []);
final cmp = viewDefResults.viewDefinitions.values.first.component;
expect(cmp.providers.length).toEqual(1);
expect(cmp.providers[0].useClass.name).toEqual("Service");
expect(cmp.providers[0].useClass.diDeps.first.token.name).toEqual("Service2");
});
it('should generate providers from types.', () async {
barNgMeta.identifiers['Service'] = new CompileTypeMetadata(name: 'Service', moduleUrl: 'moduleUrl');
fooComponentMeta.template = new CompileTemplateMetadata(template: "import 'bar.dart';");
fooComponentMeta.providers = [new CompileProviderMetadata(token: new CompileIdentifierMetadata(name: 'Service'))];
fooComponentMeta.type.diDeps = [new CompileDiDependencyMetadata(token: new CompileIdentifierMetadata(name: 'Service'))];
final viewAnnotation = new AnnotationModel()..name = 'View'..isView = true;
final reflectable = fooNgMeta.ngDeps.reflectables.first;
reflectable.annotations.add(viewAnnotation);
fooNgMeta.ngDeps.imports.add(new ImportModel()..uri = 'package:a/bar.dart');
updateReader();
final viewDefResults = await createCompileData(reader, fooAssetId, [], []);
final cmp = viewDefResults.viewDefinitions.values.first.component;
expect(cmp.providers.length).toEqual(1);
expect(cmp.providers[0].token.name).toEqual("Service");
expect(cmp.providers[0].token.moduleUrl).toEqual("moduleUrl");
expect(cmp.type.diDeps.length).toEqual(1);
expect(cmp.type.diDeps[0].token.name).toEqual("Service");
expect(cmp.type.diDeps[0].token.moduleUrl).toEqual("moduleUrl");
});
it('should generate providers from Provider objects (references).', () async {
barNgMeta.identifiers['Service1'] = new CompileTypeMetadata(name: 'Service1', moduleUrl: 'moduleUrl');
barNgMeta.identifiers['Service2'] = new CompileTypeMetadata(name: 'Service2', moduleUrl: 'moduleUrl');
fooComponentMeta.template = new CompileTemplateMetadata(template: "import 'bar.dart';");
fooComponentMeta.providers = [new CompileProviderMetadata(token: new CompileIdentifierMetadata(name: 'Service1'), useClass:
new CompileTypeMetadata(name: 'Service2'))];
final viewAnnotation = new AnnotationModel()..name = 'View'..isView = true;
final reflectable = fooNgMeta.ngDeps.reflectables.first;
reflectable.annotations.add(viewAnnotation);
fooNgMeta.ngDeps.imports.add(new ImportModel()..uri = 'package:a/bar.dart');
updateReader();
final viewDefResults = await createCompileData(reader, fooAssetId, [], []);
final cmp = viewDefResults.viewDefinitions.values.first.component;
expect(cmp.providers.length).toEqual(1);
expect(cmp.providers[0].token.name).toEqual("Service1");
expect(cmp.providers[0].token.moduleUrl).toEqual("moduleUrl");
expect(cmp.providers[0].useClass.name).toEqual("Service2");
expect(cmp.providers[0].useClass.moduleUrl).toEqual("moduleUrl");
});
it('should generate providers from Provider objects (literals).', () async {
barNgMeta.identifiers['Service'] = new CompileTypeMetadata(name: 'Service', moduleUrl: 'moduleUrl');
fooComponentMeta.template = new CompileTemplateMetadata(template: "import 'bar.dart';");
fooComponentMeta.providers = [new CompileProviderMetadata(token: "StrService", useClass:
new CompileTypeMetadata(name: 'Service'))];
fooComponentMeta.type.diDeps = [new CompileDiDependencyMetadata(token: "StrService")];
final viewAnnotation = new AnnotationModel()..name = 'View'..isView = true;
final reflectable = fooNgMeta.ngDeps.reflectables.first;
reflectable.annotations.add(viewAnnotation);
fooNgMeta.ngDeps.imports.add(new ImportModel()..uri = 'package:a/bar.dart');
updateReader();
final viewDefResults = await createCompileData(reader, fooAssetId, [], []);
final cmp = viewDefResults.viewDefinitions.values.first.component;
expect(cmp.providers.length).toEqual(1);
expect(cmp.providers[0].token).toEqual("StrService");
expect(cmp.providers[0].useClass.name).toEqual("Service");
expect(cmp.providers[0].useClass.moduleUrl).toEqual("moduleUrl");
expect(cmp.type.diDeps.length).toEqual(1);
expect(cmp.type.diDeps[0].token).toEqual("StrService");
});
it('should include providers mentioned in aliases.', () async {
barNgMeta.identifiers['Service'] = new CompileTypeMetadata(name: 'Service', moduleUrl: 'moduleUrl');
fooComponentMeta.template = new CompileTemplateMetadata(template: "import 'bar.dart';");
fooNgMeta.aliases['providerAlias'] = ['Service'];
fooComponentMeta.providers = [new CompileProviderMetadata(token: new CompileIdentifierMetadata(name: 'providerAlias'))];
final viewAnnotation = new AnnotationModel()..name = 'View'..isView = true;
final reflectable = fooNgMeta.ngDeps.reflectables.first;
reflectable.annotations.add(viewAnnotation);
fooNgMeta.ngDeps.imports.add(new ImportModel()..uri = 'package:a/bar.dart');
updateReader();
final viewDefResults = await createCompileData(reader, fooAssetId, [], []);
final cmp = viewDefResults.viewDefinitions.values.first.component;
expect(cmp.providers.length).toEqual(1);
expect(cmp.providers[0].token.name).toEqual("Service");
});
it('should parse simple expressions in inline templates.', () async { it('should parse simple expressions in inline templates.', () async {
fooComponentMeta.template = new CompileTemplateMetadata( fooComponentMeta.template = new CompileTemplateMetadata(
template: '<div [a]="b">{{greeting}}</div>', template: '<div [a]="b">{{greeting}}</div>',
@ -369,7 +510,7 @@ void allTests() {
..name = 'View' ..name = 'View'
..isView = true; ..isView = true;
barNgMeta.types['PLATFORM'] = barComponentMeta; barNgMeta.identifiers['PLATFORM'] = barComponentMeta;
updateReader(); updateReader();
final outputs = await process(fooAssetId, final outputs = await process(fooAssetId,

View File

@ -2,7 +2,6 @@ var broccoli = require('broccoli');
var fs = require('fs'); var fs = require('fs');
var makeBrowserTree = require('./trees/browser_tree'); var makeBrowserTree = require('./trees/browser_tree');
var makeNodeTree = require('./trees/node_tree'); var makeNodeTree = require('./trees/node_tree');
var makeDartTree = require('./trees/dart_tree');
var path = require('path'); var path = require('path');
var printSlowTrees = require('broccoli-slow-trees'); var printSlowTrees = require('broccoli-slow-trees');
var Q = require('q'); var Q = require('q');
@ -111,6 +110,7 @@ export class AngularBuilder {
logs: this.options.logs, logs: this.options.logs,
projects: projects projects: projects
}; };
var makeDartTree = require('./trees/dart_tree');
let tree = makeDartTree(options); let tree = makeDartTree(options);
return new broccoli.Builder(tree); return new broccoli.Builder(tree);
} }

View File

@ -5,10 +5,11 @@ var insert = require('gulp-insert');
var fs = require('fs-extra'); var fs = require('fs-extra');
var browserify = require('browserify'); var browserify = require('browserify');
var path = require('path'); var path = require('path');
var Builder = require('systemjs-builder');
module.exports.bundle = function(buildConfig, moduleName, outputFile, outputConfig, module.exports.bundle = function(buildConfig, moduleName, outputFile, outputConfig,
sfx) { sfx) {
var Builder = require('systemjs-builder');
var sfx = sfx || false; var sfx = sfx || false;
var builder = new Builder(); var builder = new Builder();
builder.config(buildConfig); builder.config(buildConfig);

View File

@ -825,8 +825,12 @@ const COMPILER = [
'BoundTextAst.visit(visitor:TemplateAstVisitor, context:any):any', 'BoundTextAst.visit(visitor:TemplateAstVisitor, context:any):any',
'CompileDirectiveMetadata', 'CompileDirectiveMetadata',
'CompileDirectiveMetadata.changeDetection:ChangeDetectionStrategy', 'CompileDirectiveMetadata.changeDetection:ChangeDetectionStrategy',
'CompileDirectiveMetadata.constructor({type,isComponent,dynamicLoadable,selector,exportAs,changeDetection,inputs,outputs,hostListeners,hostProperties,hostAttributes,lifecycleHooks,template}:{type?:CompileTypeMetadata, isComponent?:boolean, dynamicLoadable?:boolean, selector?:string, exportAs?:string, changeDetection?:ChangeDetectionStrategy, inputs?:{[key:string]:string}, outputs?:{[key:string]:string}, hostListeners?:{[key:string]:string}, hostProperties?:{[key:string]:string}, hostAttributes?:{[key:string]:string}, lifecycleHooks?:LifecycleHooks[], template?:CompileTemplateMetadata})', 'CompileDirectiveMetadata.constructor({type,isComponent,dynamicLoadable,selector,exportAs,changeDetection,inputs,outputs,hostListeners,hostProperties,hostAttributes,lifecycleHooks,providers,viewProviders,queries,viewQueries,template}:{type?:CompileTypeMetadata, isComponent?:boolean, dynamicLoadable?:boolean, selector?:string, exportAs?:string, changeDetection?:ChangeDetectionStrategy, inputs?:{[key:string]:string}, outputs?:{[key:string]:string}, hostListeners?:{[key:string]:string}, hostProperties?:{[key:string]:string}, hostAttributes?:{[key:string]:string}, lifecycleHooks?:LifecycleHooks[], providers?:Array<CompileProviderMetadata|CompileTypeMetadata|any[]>, viewProviders?:Array<CompileProviderMetadata|CompileTypeMetadata|any[]>, queries?:CompileQueryMetadata[], viewQueries?:CompileQueryMetadata[], template?:CompileTemplateMetadata})',
'CompileDirectiveMetadata.create({type,isComponent,dynamicLoadable,selector,exportAs,changeDetection,inputs,outputs,host,lifecycleHooks,template}:{type?:CompileTypeMetadata, isComponent?:boolean, dynamicLoadable?:boolean, selector?:string, exportAs?:string, changeDetection?:ChangeDetectionStrategy, inputs?:string[], outputs?:string[], host?:{[key:string]:string}, lifecycleHooks?:LifecycleHooks[], template?:CompileTemplateMetadata}):CompileDirectiveMetadata', 'CompileDirectiveMetadata.create({type,isComponent,dynamicLoadable,selector,exportAs,changeDetection,inputs,outputs,host,lifecycleHooks,providers,viewProviders,queries,viewQueries,template}:{type?:CompileTypeMetadata, isComponent?:boolean, dynamicLoadable?:boolean, selector?:string, exportAs?:string, changeDetection?:ChangeDetectionStrategy, inputs?:string[], outputs?:string[], host?:{[key:string]:string}, lifecycleHooks?:LifecycleHooks[], providers?:Array<CompileProviderMetadata|CompileTypeMetadata|any[]>, viewProviders?:Array<CompileProviderMetadata|CompileTypeMetadata|any[]>, queries?:CompileQueryMetadata[], viewQueries?:CompileQueryMetadata[], template?:CompileTemplateMetadata}):CompileDirectiveMetadata',
'CompileDirectiveMetadata.providers:Array<CompileProviderMetadata|CompileTypeMetadata|any[]>',
'CompileDirectiveMetadata.queries:CompileQueryMetadata[]',
'CompileDirectiveMetadata.viewProviders:Array<CompileProviderMetadata|CompileTypeMetadata|any[]>',
'CompileDirectiveMetadata.viewQueries:CompileQueryMetadata[]',
'CompileDirectiveMetadata.dynamicLoadable:boolean', 'CompileDirectiveMetadata.dynamicLoadable:boolean',
'CompileDirectiveMetadata.exportAs:string', 'CompileDirectiveMetadata.exportAs:string',
'CompileDirectiveMetadata.fromJson(data:{[key:string]:any}):CompileDirectiveMetadata', 'CompileDirectiveMetadata.fromJson(data:{[key:string]:any}):CompileDirectiveMetadata',
@ -841,6 +845,7 @@ const COMPILER = [
'CompileDirectiveMetadata.template:CompileTemplateMetadata', 'CompileDirectiveMetadata.template:CompileTemplateMetadata',
'CompileDirectiveMetadata.toJson():{[key:string]:any}', 'CompileDirectiveMetadata.toJson():{[key:string]:any}',
'CompileDirectiveMetadata.type:CompileTypeMetadata', 'CompileDirectiveMetadata.type:CompileTypeMetadata',
'CompileDirectiveMetadata.identifier:CompileIdentifierMetadata',
'CompileTemplateMetadata', 'CompileTemplateMetadata',
'CompileTemplateMetadata.constructor({encapsulation,template,templateUrl,styles,styleUrls,ngContentSelectors}:{encapsulation?:ViewEncapsulation, template?:string, templateUrl?:string, styles?:string[], styleUrls?:string[], ngContentSelectors?:string[]})', 'CompileTemplateMetadata.constructor({encapsulation,template,templateUrl,styles,styleUrls,ngContentSelectors}:{encapsulation?:ViewEncapsulation, template?:string, templateUrl?:string, styles?:string[], styleUrls?:string[], ngContentSelectors?:string[]})',
'CompileTemplateMetadata.encapsulation:ViewEncapsulation', 'CompileTemplateMetadata.encapsulation:ViewEncapsulation',
@ -852,13 +857,17 @@ const COMPILER = [
'CompileTemplateMetadata.templateUrl:string', 'CompileTemplateMetadata.templateUrl:string',
'CompileTemplateMetadata.toJson():{[key:string]:any}', 'CompileTemplateMetadata.toJson():{[key:string]:any}',
'CompileTypeMetadata', 'CompileTypeMetadata',
'CompileTypeMetadata.constructor({runtime,name,moduleUrl,isHost}:{runtime?:Type, name?:string, moduleUrl?:string, isHost?:boolean})', 'CompileTypeMetadata.constructor({runtime,name,moduleUrl,prefix,isHost,diDeps}:{runtime?:Type, name?:string, moduleUrl?:string, prefix?:string, isHost?:boolean, diDeps?:CompileDiDependencyMetadata[]})',
'CompileTypeMetadata.fromJson(data:{[key:string]:any}):CompileTypeMetadata', 'CompileTypeMetadata.fromJson(data:{[key:string]:any}):CompileTypeMetadata',
'CompileTypeMetadata.isHost:boolean', 'CompileTypeMetadata.isHost:boolean',
'CompileTypeMetadata.moduleUrl:string', 'CompileTypeMetadata.moduleUrl:string',
'CompileTypeMetadata.name:string', 'CompileTypeMetadata.name:string',
'CompileTypeMetadata.runtime:Type', 'CompileTypeMetadata.runtime:Type',
'CompileTypeMetadata.toJson():{[key:string]:any}', 'CompileTypeMetadata.toJson():{[key:string]:any}',
'CompileTypeMetadata.diDeps:CompileDiDependencyMetadata[]',
'CompileTypeMetadata.prefix:string',
'CompileTypeMetadata.identifier:CompileIdentifierMetadata',
'CompileTypeMetadata.type:CompileTypeMetadata',
'DirectiveAst', 'DirectiveAst',
'DirectiveAst.constructor(directive:CompileDirectiveMetadata, inputs:BoundDirectivePropertyAst[], hostProperties:BoundElementPropertyAst[], hostEvents:BoundEventAst[], exportAsVars:VariableAst[], sourceSpan:ParseSourceSpan)', 'DirectiveAst.constructor(directive:CompileDirectiveMetadata, inputs:BoundDirectivePropertyAst[], hostProperties:BoundElementPropertyAst[], hostEvents:BoundEventAst[], exportAsVars:VariableAst[], sourceSpan:ParseSourceSpan)',
'DirectiveAst.visit(visitor:TemplateAstVisitor, context:any):any', 'DirectiveAst.visit(visitor:TemplateAstVisitor, context:any):any',