diff --git a/modules/angular2/src/compiler/directive_metadata.ts b/modules/angular2/src/compiler/directive_metadata.ts
index 360acf64bd..3296ff0565 100644
--- a/modules/angular2/src/compiler/directive_metadata.ts
+++ b/modules/angular2/src/compiler/directive_metadata.ts
@@ -177,7 +177,10 @@ export class CompileProviderMetadata {
static fromJson(data: {[key: string]: any}): CompileProviderMetadata {
return new CompileProviderMetadata({
token: objFromJson(data['token'], CompileIdentifierMetadata.fromJson),
- useClass: objFromJson(data['useClass'], CompileTypeMetadata.fromJson)
+ useClass: objFromJson(data['useClass'], CompileTypeMetadata.fromJson),
+ useExisting: objFromJson(data['useExisting'], CompileIdentifierMetadata.fromJson),
+ useValue: objFromJson(data['useValue'], CompileIdentifierMetadata.fromJson),
+ useFactory: objFromJson(data['useFactory'], CompileFactoryMetadata.fromJson)
});
}
@@ -185,7 +188,10 @@ export class CompileProviderMetadata {
return {
// Note: Runtime type can't be serialized...
'token': objToJson(this.token),
- 'useClass': objToJson(this.useClass)
+ 'useClass': objToJson(this.useClass),
+ 'useExisting': objToJson(this.useExisting),
+ 'useValue': objToJson(this.useValue),
+ 'useFactory': objToJson(this.useFactory)
};
}
}
@@ -198,15 +204,17 @@ export class CompileFactoryMetadata implements CompileIdentifierMetadata {
constConstructor: boolean;
diDeps: CompileDiDependencyMetadata[];
- constructor({runtime, name, moduleUrl, constConstructor, diDeps}: {
+ constructor({runtime, name, moduleUrl, prefix, constConstructor, diDeps}: {
runtime?: Function,
name?: string,
+ prefix?: string,
moduleUrl?: string,
constConstructor?: boolean,
diDeps?: CompileDiDependencyMetadata[]
}) {
this.runtime = runtime;
this.name = name;
+ this.prefix = prefix;
this.moduleUrl = moduleUrl;
this.diDeps = diDeps;
this.constConstructor = constConstructor;
@@ -214,7 +222,25 @@ export class CompileFactoryMetadata implements CompileIdentifierMetadata {
get identifier(): CompileIdentifierMetadata { return this; }
- toJson() { return null; }
+ static fromJson(data: {[key: string]: any}): CompileFactoryMetadata {
+ return new CompileFactoryMetadata({
+ name: data['name'],
+ prefix: data['prefix'],
+ moduleUrl: data['moduleUrl'],
+ constConstructor: data['constConstructor'],
+ diDeps: arrayFromJson(data['diDeps'], CompileDiDependencyMetadata.fromJson)
+ });
+ }
+
+ toJson(): {[key: string]: any} {
+ return {
+ 'name': this.name,
+ 'prefix': this.prefix,
+ 'moduleUrl': this.moduleUrl,
+ 'constConstructor': this.constConstructor,
+ 'diDeps': arrayToJson(this.diDeps)
+ };
+ }
}
/**
diff --git a/modules/angular2/test/compiler/directive_metadata_spec.ts b/modules/angular2/test/compiler/directive_metadata_spec.ts
index ac6b5fb627..f5346c8d02 100644
--- a/modules/angular2/test/compiler/directive_metadata_spec.ts
+++ b/modules/angular2/test/compiler/directive_metadata_spec.ts
@@ -18,7 +18,9 @@ import {
CompileTemplateMetadata,
CompileProviderMetadata,
CompileDiDependencyMetadata,
- CompileQueryMetadata
+ CompileQueryMetadata,
+ CompileIdentifierMetadata,
+ CompileFactoryMetadata
} from 'angular2/src/compiler/directive_metadata';
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
import {ChangeDetectionStrategy} from 'angular2/src/core/change_detection';
@@ -31,25 +33,21 @@ export function main() {
var fullDirectiveMeta: CompileDirectiveMetadata;
beforeEach(() => {
- fullTypeMeta = new CompileTypeMetadata({
- name: 'SomeType',
- moduleUrl: 'someUrl',
+ var diDep = new CompileDiDependencyMetadata({
+ isAttribute: true,
+ isSelf: true,
isHost: true,
- diDeps: [
- new CompileDiDependencyMetadata({
- isAttribute: true,
- isSelf: true,
- isHost: true,
- isSkipSelf: true,
- isOptional: true,
- token: 'someToken',
- query: new CompileQueryMetadata(
- {selectors: ['one'], descendants: true, first: true, propertyName: 'one'}),
- viewQuery: new CompileQueryMetadata(
- {selectors: ['one'], descendants: true, first: true, propertyName: 'one'})
- })
- ]
+ isSkipSelf: true,
+ isOptional: true,
+ token: 'someToken',
+ query: new CompileQueryMetadata(
+ {selectors: ['one'], descendants: true, first: true, propertyName: 'one'}),
+ viewQuery: new CompileQueryMetadata(
+ {selectors: ['one'], descendants: true, first: true, propertyName: 'one'})
});
+
+ fullTypeMeta = new CompileTypeMetadata(
+ {name: 'SomeType', moduleUrl: 'someUrl', isHost: true, diDeps: [diDep]});
fullTemplateMeta = new CompileTemplateMetadata({
encapsulation: ViewEncapsulation.Emulated,
template: '',
@@ -69,7 +67,15 @@ export function main() {
outputs: ['someEvent'],
host: {'(event1)': 'handler1', '[prop1]': 'expr1', 'attr1': 'attrValue2'},
lifecycleHooks: [LifecycleHooks.OnChanges],
- providers: [new CompileProviderMetadata({token: 'token', useClass: fullTypeMeta})]
+ providers: [
+ new CompileProviderMetadata({
+ token: 'token',
+ useClass: fullTypeMeta,
+ useExisting: new CompileIdentifierMetadata({name: 'someName'}),
+ useFactory: new CompileFactoryMetadata({name: 'someName', diDeps: [diDep]}),
+ useValue: 'someValue',
+ })
+ ]
});
});
diff --git a/modules_dart/transform/lib/src/transform/common/type_metadata_reader.dart b/modules_dart/transform/lib/src/transform/common/type_metadata_reader.dart
index fbaad1a5e3..a249e3f657 100644
--- a/modules_dart/transform/lib/src/transform/common/type_metadata_reader.dart
+++ b/modules_dart/transform/lib/src/transform/common/type_metadata_reader.dart
@@ -431,14 +431,38 @@ class _DirectiveMetadataVisitor extends Object
) {
final token = el.argumentList.arguments.first;
- var useClass;
+ var useClass, useExisting, useValue, factoryId, useFactory, deps;
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);
+ } else if (arg.name.toString() == "toClass:") {
+ final id = _readIdentifier(arg.expression);
+ useClass = new CompileTypeMetadata(prefix: id.prefix, name: id.name);
+
+ } else if (arg.name.toString() == "useExisting:") {
+ useExisting = _readIdentifier(arg.expression);
+ } else if (arg.name.toString() == "toAlias:") {
+ useExisting = _readIdentifier(arg.expression);
+
+ } else if (arg.name.toString() == "useValue:") {
+ useValue = _readIdentifier(arg.expression);
+ } else if (arg.name.toString() == "toValue:") {
+ useValue = _readIdentifier(arg.expression);
+
+ } else if (arg.name.toString() == "useFactory:") {
+ factoryId = _readIdentifier(arg.expression);
+ } else if (arg.name.toString() == "toFactory:") {
+ factoryId = _readIdentifier(arg.expression);
+
+ } else if (arg.name.toString() == "deps:") {
+ deps = _readDeps(arg.expression);
}
});
- return new CompileProviderMetadata(token: _readIdentifier(token), useClass: useClass);
+ if (factoryId != null) {
+ useFactory = new CompileFactoryMetadata(name: factoryId.name, prefix: factoryId.prefix);
+ }
+ return new CompileProviderMetadata(token: _readIdentifier(token), useClass: useClass, useExisting: useExisting, useValue: useValue, useFactory: useFactory, deps: deps);
} else {
throw new ArgumentError(
@@ -451,6 +475,29 @@ class _DirectiveMetadataVisitor extends Object
}
}
+ List _readDeps(ListLiteral deps) {
+ return deps.elements.map((p) {
+ final list = p is ListLiteral ? p.elements : [p];
+ final first = list.first;
+
+ var token;
+ if (first is InstanceCreationExpression && first.constructorName.toString() == "Inject") {
+ token = _readIdentifier(first.argumentList.arguments[0]);
+ } else {
+ token = _readIdentifier(first);
+ }
+
+ return new CompileDiDependencyMetadata(
+ token: token,
+ isSelf: _hasConst(list, "Self"),
+ isHost: _hasConst(list, "Host"),
+ isSkipSelf: _hasConst(list, "SkipSelf"),
+ isOptional: _hasConst(list, "Optional"));
+ }).toList();
+ }
+
+ bool _hasConst(List list, String name) => list.where((m) => m is InstanceCreationExpression && m.constructorName.toString() == name).isNotEmpty;
+
//TODO Use AnnotationMatcher instead of string matching
bool _isAnnotation(Annotation node, String annotationName) {
var id = node.name;
diff --git a/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart b/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart
index 61e90cc9f3..2d725354fd 100644
--- a/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart
+++ b/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart
@@ -162,6 +162,17 @@ class _CompileDataCreator {
if (provider.useClass != null) {
provider.useClass = _resolveIdentifier(ngMetaMap, neededBy, provider.useClass);
}
+ if (provider.useExisting != null) {
+ provider.useExisting = _resolveIdentifier(ngMetaMap, neededBy, provider.useExisting);
+ }
+ if (provider.useValue != null) {
+ provider.useValue = _resolveIdentifier(ngMetaMap, neededBy, provider.useValue);
+ }
+ if (provider.useFactory != null) {
+ final resolved = _resolveIdentifier(ngMetaMap, neededBy, provider.useFactory);
+ provider.useFactory.moduleUrl = resolved.moduleUrl;
+ _resolveDiDependencyMetadata(ngMetaMap, neededBy, provider.useFactory.diDeps);
+ }
resolvedProviders.add(provider);
}
}
diff --git a/modules_dart/transform/test/transform/directive_processor/all_tests.dart b/modules_dart/transform/test/transform/directive_processor/all_tests.dart
index 5c023a1772..ba6eb15e45 100644
--- a/modules_dart/transform/test/transform/directive_processor/all_tests.dart
+++ b/modules_dart/transform/test/transform/directive_processor/all_tests.dart
@@ -671,6 +671,160 @@ void allTests() {
expect(useClass.name).toEqual("ServiceDep");
});
+ it('should populate `providers` using toClass.',
+ () async {
+ var cmp =
+ (await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersToClass'];
+
+ expect(cmp).toBeNotNull();
+ expect(cmp.providers).toBeNotNull();
+ expect(cmp.providers.length).toEqual(1);
+
+ var token = cmp.providers.first.token;
+ var useExisting = cmp.providers.first.useClass;
+
+ expect(useExisting.prefix).toEqual(null);
+ expect(useExisting.name).toEqual("ServiceDep");
+ });
+
+ it('should populate `providers` using useExisting.',
+ () async {
+ var cmp =
+ (await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersUseExisting'];
+
+ expect(cmp).toBeNotNull();
+ expect(cmp.providers).toBeNotNull();
+ expect(cmp.providers.length).toEqual(1);
+
+ var token = cmp.providers.first.token;
+ var useExisting = cmp.providers.first.useExisting;
+
+ expect(useExisting.prefix).toEqual(null);
+ expect(useExisting.name).toEqual("ServiceDep");
+ });
+
+ it('should populate `providers` using toAlias.',
+ () async {
+ var cmp =
+ (await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersToAlias'];
+
+ expect(cmp).toBeNotNull();
+ expect(cmp.providers).toBeNotNull();
+ expect(cmp.providers.length).toEqual(1);
+
+ var token = cmp.providers.first.token;
+ var useExisting = cmp.providers.first.useExisting;
+
+ expect(useExisting.prefix).toEqual(null);
+ expect(useExisting.name).toEqual("ServiceDep");
+ });
+
+ it('should populate `providers` using useExisting (string token).',
+ () async {
+ var cmp =
+ (await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersUseExistingStr'];
+
+ expect(cmp).toBeNotNull();
+ expect(cmp.providers).toBeNotNull();
+ expect(cmp.providers.length).toEqual(1);
+
+ var token = cmp.providers.first.token;
+ var useExisting = cmp.providers.first.useExisting;
+
+ expect(useExisting).toEqual("StrToken");
+ });
+
+ it('should populate `providers` using useValue.',
+ () async {
+ var cmp =
+ (await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersUseValue'];
+
+ expect(cmp).toBeNotNull();
+ expect(cmp.providers).toBeNotNull();
+ expect(cmp.providers.length).toEqual(1);
+
+ var token = cmp.providers.first.token;
+ var useValue = cmp.providers.first.useValue;
+
+ expect(useValue.prefix).toEqual(null);
+ expect(useValue.name).toEqual("ServiceDep");
+ });
+
+ it('should populate `providers` using toValue.',
+ () async {
+ var cmp =
+ (await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersToValue'];
+
+ expect(cmp).toBeNotNull();
+ expect(cmp.providers).toBeNotNull();
+ expect(cmp.providers.length).toEqual(1);
+
+ var token = cmp.providers.first.token;
+ var useValue = cmp.providers.first.useValue;
+
+ expect(useValue.prefix).toEqual(null);
+ expect(useValue.name).toEqual("ServiceDep");
+ });
+
+ it('should populate `providers` using useValue (string token).',
+ () async {
+ var cmp =
+ (await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersUseValueStr'];
+
+ expect(cmp).toBeNotNull();
+ expect(cmp.providers).toBeNotNull();
+ expect(cmp.providers.length).toEqual(1);
+
+ var token = cmp.providers.first.token;
+ var useValue = cmp.providers.first.useValue;
+
+ expect(useValue).toEqual("StrToken");
+ });
+
+ it('should populate `providers` using useFactory.',
+ () async {
+ var cmp =
+ (await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersUseFactory'];
+
+ expect(cmp).toBeNotNull();
+ expect(cmp.providers).toBeNotNull();
+ expect(cmp.providers.length).toEqual(1);
+
+ var token = cmp.providers.first.token;
+ var useFactory = cmp.providers.first.useFactory;
+ var deps = cmp.providers.first.deps;
+
+ expect(useFactory.prefix).toEqual(null);
+ expect(useFactory.name).toEqual("funcDep");
+
+ expect(deps[0].token.name).toEqual("ServiceDep");
+ expect(deps[1].token).toEqual("Str");
+ expect(deps[2].token.name).toEqual("ServiceDep");
+ expect(deps[3].token.name).toEqual("ServiceDep");
+ expect(deps[3].isSelf).toEqual(true);
+ expect(deps[4].token.name).toEqual("ServiceDep");
+ expect(deps[4].isSkipSelf).toEqual(true);
+ expect(deps[5].token.name).toEqual("ServiceDep");
+ expect(deps[5].isOptional).toEqual(true);
+ });
+
+ it('should populate `providers` using toFactory.',
+ () async {
+ var cmp =
+ (await _testCreateModel('directives_files/components.dart')).identifiers['ComponentWithProvidersToFactory'];
+
+ expect(cmp).toBeNotNull();
+ expect(cmp.providers).toBeNotNull();
+ expect(cmp.providers.length).toEqual(1);
+
+ var token = cmp.providers.first.token;
+ var useFactory = cmp.providers.first.useFactory;
+ var deps = cmp.providers.first.deps;
+
+ expect(useFactory.prefix).toEqual(null);
+ expect(useFactory.name).toEqual("funcDep");
+ });
+
it('should populate `providers` using a string token.',
() async {
var cmp =
diff --git a/modules_dart/transform/test/transform/directive_processor/directives_files/components.dart b/modules_dart/transform/test/transform/directive_processor/directives_files/components.dart
index 92a39b51ce..d2ea2d0f60 100644
--- a/modules_dart/transform/test/transform/directive_processor/directives_files/components.dart
+++ b/modules_dart/transform/test/transform/directive_processor/directives_files/components.dart
@@ -127,9 +127,82 @@ class ComponentWithDiDeps {
);
}
+@Component(
+ selector: 'component-with-providers-use-class',
+ template: '',
+ providers: [const Provider(ServiceDep, useClass: ServiceDep)])
+class ComponentWithProvidersUseClass {}
+
+@Component(
+ selector: 'component-with-providers-to-class',
+ template: '',
+ providers: [const Binding(ServiceDep, toClass: ServiceDep)])
+class ComponentWithProvidersToClass{}
+
+
+@Component(
+ selector: 'component-with-providers-use-existing',
+ template: '',
+ providers: [const Provider(ServiceDep, useExisting: ServiceDep)])
+class ComponentWithProvidersUseExisting{}
+
+@Component(
+ selector: 'component-with-providers-to-alias',
+ template: '',
+ providers: [const Binding(ServiceDep, toAlias: ServiceDep)])
+class ComponentWithProvidersToAlias{}
+
+@Component(
+ selector: 'component-with-providers-use-existing-string',
+ template: '',
+ providers: [const Provider(ServiceDep, useExisting: 'StrToken')])
+class ComponentWithProvidersUseExistingStr{}
+
+
+@Component(
+ selector: 'component-with-providers-use-value',
+ template: '',
+ providers: [const Provider(ServiceDep, useValue: ServiceDep)])
+class ComponentWithProvidersUseValue{}
+
+@Component(
+ selector: 'component-with-providers-to-value',
+ template: '',
+ providers: [const Binding(ServiceDep, toValue: ServiceDep)])
+class ComponentWithProvidersToValue{}
+
+@Component(
+ selector: 'component-with-providers-use-value-string',
+ template: '',
+ providers: [const Provider(ServiceDep, useValue: 'StrToken')])
+class ComponentWithProvidersUseValueStr{}
+
+
+@Component(
+ selector: 'component-with-providers-use-factory',
+ template: '',
+ providers: [const Provider(ServiceDep, useFactory: funcDep, deps:
+ const [
+ ServiceDep,
+ "Str",
+ [const Inject(ServiceDep)],
+ [ServiceDep, const Self()],
+ [ServiceDep, const SkipSelf()],
+ [ServiceDep, const Optional()]
+ ])])
+class ComponentWithProvidersUseFactory{}
+
+@Component(
+ selector: 'component-with-providers-to-factory',
+ template: '',
+ providers: [const Binding(ServiceDep, toFactory: funcDep)])
+class ComponentWithProvidersToFactory{}
+
@Component(
selector: 'component-with-di-deps-string-token',
template: '')
class ComponentWithDiDepsStrToken {
ComponentWithDiDepsStrToken(@Inject("StringDep") arg1);
}
+
+funcDep(){}
diff --git a/modules_dart/transform/test/transform/template_compiler/all_tests.dart b/modules_dart/transform/test/transform/template_compiler/all_tests.dart
index bbd0fca8a8..dfd092c2bc 100644
--- a/modules_dart/transform/test/transform/template_compiler/all_tests.dart
+++ b/modules_dart/transform/test/transform/template_compiler/all_tests.dart
@@ -217,8 +217,17 @@ void allTests() {
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'))];
+ fooComponentMeta.providers = [
+ new CompileProviderMetadata(token: new CompileIdentifierMetadata(name: 'Service1'), useClass: new CompileTypeMetadata(name: 'Service2')),
+ new CompileProviderMetadata(token: new CompileIdentifierMetadata(name: 'Service1'), useExisting: new CompileIdentifierMetadata(name: 'Service2')),
+ new CompileProviderMetadata(token: new CompileIdentifierMetadata(name: 'Service1'), useValue: new CompileIdentifierMetadata(name: 'Service2')),
+ new CompileProviderMetadata(token: new CompileIdentifierMetadata(name: 'Service1'), useFactory:
+ new CompileFactoryMetadata(
+ name: 'Service2',
+ diDeps: [new CompileDiDependencyMetadata(token: new CompileIdentifierMetadata(name: 'Service2'))]
+ )
+ )
+ ];
final viewAnnotation = new AnnotationModel()..name = 'View'..isView = true;
final reflectable = fooNgMeta.ngDeps.reflectables.first;
@@ -230,12 +239,29 @@ void allTests() {
final viewDefResults = await createCompileData(reader, fooAssetId, [], [], {});
final cmp = viewDefResults.viewDefinitions.values.first.component;
- expect(cmp.providers.length).toEqual(1);
+ expect(cmp.providers.length).toEqual(4);
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");
+
+ expect(cmp.providers[1].token.name).toEqual("Service1");
+ expect(cmp.providers[1].token.moduleUrl).toEqual("moduleUrl");
+ expect(cmp.providers[1].useExisting.name).toEqual("Service2");
+ expect(cmp.providers[1].useExisting.moduleUrl).toEqual("moduleUrl");
+
+ expect(cmp.providers[2].token.name).toEqual("Service1");
+ expect(cmp.providers[2].token.moduleUrl).toEqual("moduleUrl");
+ expect(cmp.providers[2].useValue.name).toEqual("Service2");
+ expect(cmp.providers[2].useValue.moduleUrl).toEqual("moduleUrl");
+
+ expect(cmp.providers[3].token.name).toEqual("Service1");
+ expect(cmp.providers[3].token.moduleUrl).toEqual("moduleUrl");
+ expect(cmp.providers[3].useFactory.name).toEqual("Service2");
+ expect(cmp.providers[3].useFactory.moduleUrl).toEqual("moduleUrl");
+ expect(cmp.providers[3].useFactory.diDeps[0].token.name).toEqual("Service2");
+ expect(cmp.providers[3].useFactory.diDeps[0].token.moduleUrl).toEqual("moduleUrl");
});
it('should generate providers from Provider objects (literals).', () async {