Skip to content

Commit

Permalink
feat(transformers): collect provider information
Browse files Browse the repository at this point in the history
  • Loading branch information
vsavkin authored and vikerman committed Mar 4, 2016
1 parent 6402d61 commit 81beb1c
Show file tree
Hide file tree
Showing 7 changed files with 371 additions and 28 deletions.
34 changes: 30 additions & 4 deletions modules/angular2/src/compiler/directive_metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,21 @@ 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)
});
}

toJson(): {[key: string]: any} {
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)
};
}
}
Expand All @@ -198,23 +204,43 @@ 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;
}

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

/**
Expand Down
44 changes: 25 additions & 19 deletions modules/angular2/test/compiler/directive_metadata_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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: '<a></a>',
Expand All @@ -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',
})
]
});

});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -451,6 +475,29 @@ class _DirectiveMetadataVisitor extends Object
}
}

List<CompileDiDependencyMetadata> _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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
Loading

0 comments on commit 81beb1c

Please sign in to comment.