From 39b6e0efba06978a6a74db6cf1ab8431f9298134 Mon Sep 17 00:00:00 2001 From: vsavkin Date: Fri, 26 Feb 2016 12:43:38 -0800 Subject: [PATCH] feat(transformers): collect information for CompileDiDependencyMetadata --- .../src/compiler/directive_metadata.ts | 46 ++++++++++++++++--- .../test/compiler/directive_metadata_spec.ts | 25 ++++++++-- .../common/type_metadata_reader.dart | 27 ++++++++++- .../compile_data_creator.dart | 6 +++ .../directive_processor/all_tests.dart | 10 +++- .../directives_files/components.dart | 11 ++++- .../template_compiler/all_tests.dart | 33 +++++++++++++ 7 files changed, 146 insertions(+), 12 deletions(-) diff --git a/modules/angular2/src/compiler/directive_metadata.ts b/modules/angular2/src/compiler/directive_metadata.ts index 42ee61d78a..360acf64bd 100644 --- a/modules/angular2/src/compiler/directive_metadata.ts +++ b/modules/angular2/src/compiler/directive_metadata.ts @@ -120,14 +120,29 @@ export class CompileDiDependencyMetadata { } static fromJson(data: {[key: string]: any}): CompileDiDependencyMetadata { - return new CompileDiDependencyMetadata( - {token: objFromJson(data['token'], CompileIdentifierMetadata.fromJson)}); + return new CompileDiDependencyMetadata({ + token: objFromJson(data['token'], CompileIdentifierMetadata.fromJson), + query: objFromJson(data['query'], CompileQueryMetadata.fromJson), + viewQuery: objFromJson(data['viewQuery'], CompileQueryMetadata.fromJson), + isAttribute: data['isAttribute'], + isSelf: data['isSelf'], + isHost: data['isHost'], + isSkipSelf: data['isSkipSelf'], + isOptional: data['isOptional'] + }); } toJson(): {[key: string]: any} { return { // Note: Runtime type can't be serialized... - 'token': objToJson(this.token) + 'token': objToJson(this.token), + 'query': objToJson(this.query), + 'viewQuery': objToJson(this.viewQuery), + 'isAttribute': this.isAttribute, + 'isSelf': this.isSelf, + 'isHost': this.isHost, + 'isSkipSelf': this.isSkipSelf, + 'isOptional': this.isOptional }; } } @@ -274,9 +289,28 @@ export class CompileQueryMetadata { } = {}) { this.selectors = selectors; this.descendants = descendants; - this.first = first; + this.first = normalizeBool(first); this.propertyName = propertyName; } + + static fromJson(data: {[key: string]: any}): CompileQueryMetadata { + return new CompileQueryMetadata({ + selectors: arrayFromJson(data['selectors'], CompileIdentifierMetadata.fromJson), + descendants: data['descendants'], + first: data['first'], + propertyName: data['propertyName'] + }); + } + + toJson(): {[key: string]: any} { + return { + // Note: Runtime type can't be serialized... + 'selectors': arrayToJson(this.selectors), + 'descendants': this.descendants, + 'first': this.first, + 'propertyName': this.propertyName + }; + } } /** @@ -581,11 +615,11 @@ var _COMPILE_METADATA_FROM_JSON = { }; function arrayFromJson(obj: any[], fn: (a: {[key: string]: any}) => any): any { - return isBlank(obj) ? null : obj.map(fn); + return isBlank(obj) ? null : obj.map(o => objFromJson(o, fn)); } function arrayToJson(obj: any[]): string | {[key: string]: any} { - return isBlank(obj) ? null : obj.map(o => o.toJson()); + return isBlank(obj) ? null : obj.map(objToJson); } function objFromJson(obj: any, fn: (a: {[key: string]: any}) => any): any { diff --git a/modules/angular2/test/compiler/directive_metadata_spec.ts b/modules/angular2/test/compiler/directive_metadata_spec.ts index 2c1d030f19..ac6b5fb627 100644 --- a/modules/angular2/test/compiler/directive_metadata_spec.ts +++ b/modules/angular2/test/compiler/directive_metadata_spec.ts @@ -16,7 +16,9 @@ import { CompileDirectiveMetadata, CompileTypeMetadata, CompileTemplateMetadata, - CompileProviderMetadata + CompileProviderMetadata, + CompileDiDependencyMetadata, + CompileQueryMetadata } from 'angular2/src/compiler/directive_metadata'; import {ViewEncapsulation} from 'angular2/src/core/metadata/view'; import {ChangeDetectionStrategy} from 'angular2/src/core/change_detection'; @@ -29,8 +31,25 @@ export function main() { var fullDirectiveMeta: CompileDirectiveMetadata; beforeEach(() => { - fullTypeMeta = new CompileTypeMetadata( - {name: 'SomeType', moduleUrl: 'someUrl', isHost: true, diDeps: []}); + fullTypeMeta = new CompileTypeMetadata({ + name: 'SomeType', + moduleUrl: 'someUrl', + 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'}) + }) + ] + }); fullTemplateMeta = new CompileTemplateMetadata({ encapsulation: ViewEncapsulation.Emulated, template: '', 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 b980fcce88..fbaad1a5e3 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 @@ -185,9 +185,34 @@ class _CompileTypeMetadataVisitor extends Object 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); + final query = _hasAnnotation(p, "Query") ? _createQueryMetadata(_getAnnotation(p, "Query")) : null; + final viewQuery = _hasAnnotation(p, "ViewQuery") ? _createQueryMetadata(_getAnnotation(p, "ViewQuery")) : null; + + return new CompileDiDependencyMetadata( + token: token, + isAttribute: _hasAnnotation(p, "Attribute"), + isSelf: _hasAnnotation(p, "Self"), + isHost: _hasAnnotation(p, "Host"), + isSkipSelf: _hasAnnotation(p, "SkipSelf"), + isOptional: _hasAnnotation(p, "Optional"), + query: query, + viewQuery: viewQuery); }).toList(); } + + _getAnnotation(p, String attrName) => p.metadata.where((m) => m.name.toString() == attrName).first; + _hasAnnotation(p, String attrName) => p.metadata.where((m) => m.name.toString() == attrName).isNotEmpty; + _createQueryMetadata(Annotation a) { + final selector = _readIdentifier(a.arguments.arguments.first); + var descendants = false; + a.arguments.arguments.skip(0).forEach((arg) { + if (arg is NamedExpression && arg.name.toString() == "descendants:") + descendants = naiveEval(arg.expression); + }); + + final selectors = selector is String ? selector.split(",") : [selector]; + return new CompileQueryMetadata(selectors: selectors, descendants: descendants); + } } 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 785bbe5abf..61e90cc9f3 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 @@ -174,6 +174,12 @@ class _CompileDataCreator { if (deps == null) return; for (var dep in deps) { dep.token = _resolveIdentifier(ngMetaMap, neededBy, dep.token); + if (dep.query != null) { + dep.query.selectors = dep.query.selectors.map((s) => _resolveIdentifier(ngMetaMap, neededBy, s)).toList(); + } + if (dep.viewQuery != null) { + dep.viewQuery.selectors = dep.viewQuery.selectors.map((s) => _resolveIdentifier(ngMetaMap, neededBy, s)).toList(); + } } } 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 60e405a816..5c023a1772 100644 --- a/modules_dart/transform/test/transform/directive_processor/all_tests.dart +++ b/modules_dart/transform/test/transform/directive_processor/all_tests.dart @@ -597,9 +597,17 @@ void allTests() { expect(cmp).toBeNotNull(); var deps = cmp.type.diDeps; expect(deps).toBeNotNull(); - expect(deps.length).toEqual(2); + expect(deps.length).toEqual(8); expect(deps[0].token.name).toEqual("ServiceDep"); expect(deps[1].token.name).toEqual("ServiceDep"); + expect(deps[2].isAttribute).toEqual(true); + expect(deps[3].isSelf).toEqual(true); + expect(deps[4].isSkipSelf).toEqual(true); + expect(deps[5].isOptional).toEqual(true); + expect(deps[6].query.selectors[0].name).toEqual("ServiceDep"); + expect(deps[6].query.descendants).toEqual(true); + expect(deps[7].viewQuery.selectors[0]).toEqual("one"); + expect(deps[7].viewQuery.selectors[1]).toEqual("two"); }); it('should populate `diDependency` using a string token.', 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 f54eaa66bb..92a39b51ce 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 @@ -115,7 +115,16 @@ class ComponentWithProvidersUseClass {} selector: 'component-with-di-deps', template: '') class ComponentWithDiDeps { - ComponentWithDiDeps(ServiceDep arg1, @Inject(ServiceDep) arg2); + ComponentWithDiDeps( + ServiceDep arg1, + @Inject(ServiceDep) arg2, + @Attribute('one') arg3, + @Self() ServiceDep arg4, + @SkipSelf() ServiceDep arg5, + @Optional() ServiceDep arg6, + @Query(ServiceDep, descendants:true) arg6, + @ViewQuery("one,two") arg7 + ); } @Component( 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 99e21befa8..c61ea43a7f 100644 --- a/modules_dart/transform/test/transform/template_compiler/all_tests.dart +++ b/modules_dart/transform/test/transform/template_compiler/all_tests.dart @@ -179,6 +179,39 @@ void allTests() { expect(cmp.type.diDeps[0].token.moduleUrl).toEqual("moduleUrl"); }); + it('should resolve queries and viewQueries.', () async { + barNgMeta.identifiers['Service'] = new CompileTypeMetadata(name: 'Service', moduleUrl: 'moduleUrl'); + + fooComponentMeta.template = new CompileTemplateMetadata(template: "import 'bar.dart';"); + fooComponentMeta.type.diDeps = [ + new CompileDiDependencyMetadata( + token: 'someToken', + query: new CompileQueryMetadata(selectors: [new CompileIdentifierMetadata(name: 'Service')]) + ), + new CompileDiDependencyMetadata( + token: 'someToken', + viewQuery: new CompileQueryMetadata(selectors: [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.type.diDeps.length).toEqual(2); + + expect(cmp.type.diDeps[0].query.selectors[0].name).toEqual("Service"); + expect(cmp.type.diDeps[0].query.selectors[0].moduleUrl).toEqual("moduleUrl"); + expect(cmp.type.diDeps[1].viewQuery.selectors[0].name).toEqual("Service"); + expect(cmp.type.diDeps[1].viewQuery.selectors[0].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');