From 44f829dbc66326d305a5aa535c1060623828e12b Mon Sep 17 00:00:00 2001 From: Tim Blasi Date: Tue, 5 May 2015 10:31:21 -0700 Subject: [PATCH] feat(dart/transform): Use the render Compiler and the DirectiveParser Update the `TemplateCompile` step to use the full render `Compiler`. Provide `DirectiveMetadata` for `ViewDefinition` objects and use it to run the `DirectiveParser` step of the render compile pipeline. --- modules/angular2/src/dom/html_adapter.dart | 16 +- .../common/directive_metadata_reader.dart | 3 + .../angular2/src/transform/common/parser.dart | 9 +- .../compile_step_factory.dart | 2 + .../template_compiler/generator.dart | 108 ++------ .../view_definition_creator.dart | 232 ++++++++++++++++++ .../test/transform/integration/all_tests.dart | 2 + .../expected/bar.ng_meta.json | 1 + .../template_compiler/all_tests.dart | 26 ++ .../duplicate_files/hello.ng_meta.json | 14 ++ .../hello.ng_meta.json | 14 ++ .../inline_method_files/hello.ng_meta.json | 14 ++ .../expected/hello.ng_deps.dart | 28 +++ .../one_directive_files/hello.ng_deps.dart | 28 +++ .../one_directive_files/hello.ng_meta.json | 25 ++ .../url_expression_files/hello.ng_meta.json | 14 ++ .../url_method_files/hello.ng_meta.json | 14 ++ .../expected/goodbye.ng_deps.dart | 22 ++ .../expected/hello.ng_deps.dart | 24 ++ .../with_prefix_files/goodbye.ng_deps.dart | 20 ++ .../with_prefix_files/goodbye.ng_meta.json | 13 + .../with_prefix_files/hello.ng_deps.dart | 24 ++ .../with_prefix_files/hello.ng_meta.json | 14 ++ tools/broccoli/trees/dart_tree.ts | 2 +- 24 files changed, 576 insertions(+), 93 deletions(-) create mode 100644 modules/angular2/src/transform/template_compiler/view_definition_creator.dart create mode 100644 modules/angular2/test/transform/integration/simple_annotation_files/expected/bar.ng_meta.json create mode 100644 modules/angular2/test/transform/template_compiler/duplicate_files/hello.ng_meta.json create mode 100644 modules/angular2/test/transform/template_compiler/inline_expression_files/hello.ng_meta.json create mode 100644 modules/angular2/test/transform/template_compiler/inline_method_files/hello.ng_meta.json create mode 100644 modules/angular2/test/transform/template_compiler/one_directive_files/expected/hello.ng_deps.dart create mode 100644 modules/angular2/test/transform/template_compiler/one_directive_files/hello.ng_deps.dart create mode 100644 modules/angular2/test/transform/template_compiler/one_directive_files/hello.ng_meta.json create mode 100644 modules/angular2/test/transform/template_compiler/url_expression_files/hello.ng_meta.json create mode 100644 modules/angular2/test/transform/template_compiler/url_method_files/hello.ng_meta.json create mode 100644 modules/angular2/test/transform/template_compiler/with_prefix_files/expected/goodbye.ng_deps.dart create mode 100644 modules/angular2/test/transform/template_compiler/with_prefix_files/expected/hello.ng_deps.dart create mode 100644 modules/angular2/test/transform/template_compiler/with_prefix_files/goodbye.ng_deps.dart create mode 100644 modules/angular2/test/transform/template_compiler/with_prefix_files/goodbye.ng_meta.json create mode 100644 modules/angular2/test/transform/template_compiler/with_prefix_files/hello.ng_deps.dart create mode 100644 modules/angular2/test/transform/template_compiler/with_prefix_files/hello.ng_meta.json diff --git a/modules/angular2/src/dom/html_adapter.dart b/modules/angular2/src/dom/html_adapter.dart index 297f8680be..611e50239c 100644 --- a/modules/angular2/src/dom/html_adapter.dart +++ b/modules/angular2/src/dom/html_adapter.dart @@ -83,7 +83,16 @@ class Html5LibDomAdapter implements DomAdapter { throw 'not implemented'; } String nodeName(node) { - throw 'not implemented'; + switch (node.nodeType) { + case Node.ELEMENT_NODE: + return (node as Element).localName; + case Node.TEXT_NODE: + return '#text'; + default: + throw 'not implemented for type ${node.nodeType}. ' + 'See http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1950641247' + ' for node types definitions.'; + } } String nodeValue(node) => node.data; String type(node) { @@ -179,9 +188,8 @@ class Html5LibDomAdapter implements DomAdapter { getElementsByTagName(element, String name) { throw 'not implemented'; } - List classList(element) { - throw 'not implemented'; - } + List classList(element) => element.classes.toList(); + addClass(element, String classname) { element.classes.add(classname); } diff --git a/modules/angular2/src/transform/common/directive_metadata_reader.dart b/modules/angular2/src/transform/common/directive_metadata_reader.dart index 5dfe3bf301..dd63cb984a 100644 --- a/modules/angular2/src/transform/common/directive_metadata_reader.dart +++ b/modules/angular2/src/transform/common/directive_metadata_reader.dart @@ -9,6 +9,9 @@ import 'parser.dart'; DirectiveMetadata readDirectiveMetadata(RegisteredType t) { var visitor = new _DirectiveMetadataVisitor(); t.annotations.accept(visitor); + if (visitor.meta != null) { + visitor.meta.id = '${t.typeName}'; + } return visitor.meta; } diff --git a/modules/angular2/src/transform/common/parser.dart b/modules/angular2/src/transform/common/parser.dart index 5c038819b1..b86ca7f69f 100644 --- a/modules/angular2/src/transform/common/parser.dart +++ b/modules/angular2/src/transform/common/parser.dart @@ -68,7 +68,8 @@ class NgDeps { final List imports = []; final List exports = []; final List registeredTypes = []; - FunctionDeclaration setupMethod; + LibraryDirective lib = null; + FunctionDeclaration setupMethod = null; NgDeps(this.code); } @@ -76,6 +77,12 @@ class NgDeps { class _ParseNgDepsVisitor extends Object with RecursiveAstVisitor { NgDeps ngDeps = null; + @override + Object visitLibraryDirective(LibraryDirective node) { + ngDeps.lib = node; + return null; + } + @override Object visitImportDirective(ImportDirective node) { ngDeps.imports.add(node); diff --git a/modules/angular2/src/transform/template_compiler/compile_step_factory.dart b/modules/angular2/src/transform/template_compiler/compile_step_factory.dart index 3625bccc3e..df6e26559b 100644 --- a/modules/angular2/src/transform/template_compiler/compile_step_factory.dart +++ b/modules/angular2/src/transform/template_compiler/compile_step_factory.dart @@ -6,6 +6,7 @@ import 'package:angular2/src/render/api.dart'; import 'package:angular2/src/render/dom/compiler/compile_step.dart'; import 'package:angular2/src/render/dom/compiler/compile_step_factory.dart' as base; +import 'package:angular2/src/render/dom/compiler/directive_parser.dart'; import 'package:angular2/src/render/dom/compiler/property_binding_parser.dart'; import 'package:angular2/src/render/dom/compiler/text_interpolation_parser.dart'; import 'package:angular2/src/render/dom/compiler/view_splitter.dart'; @@ -20,6 +21,7 @@ class CompileStepFactory implements base.CompileStepFactory { return [ new ViewSplitter(_parser), new PropertyBindingParser(_parser), + new DirectiveParser(_parser, template.directives), new TextInterpolationParser(_parser) ]; } diff --git a/modules/angular2/src/transform/template_compiler/generator.dart b/modules/angular2/src/transform/template_compiler/generator.dart index 29d7a95df7..52ff5a3eee 100644 --- a/modules/angular2/src/transform/template_compiler/generator.dart +++ b/modules/angular2/src/transform/template_compiler/generator.dart @@ -2,24 +2,22 @@ library angular2.transform.template_compiler.generator; import 'dart:async'; -import 'package:analyzer/analyzer.dart'; import 'package:angular2/src/change_detection/parser/lexer.dart' as ng; import 'package:angular2/src/change_detection/parser/parser.dart' as ng; import 'package:angular2/src/render/api.dart'; -import 'package:angular2/src/render/dom/compiler/compile_pipeline.dart'; +import 'package:angular2/src/render/dom/compiler/compiler.dart'; import 'package:angular2/src/render/dom/compiler/template_loader.dart'; import "package:angular2/src/services/xhr.dart" show XHR; import 'package:angular2/src/reflection/reflection.dart'; import 'package:angular2/src/services/url_resolver.dart'; import 'package:angular2/src/transform/common/asset_reader.dart'; -import 'package:angular2/src/transform/common/logging.dart'; import 'package:angular2/src/transform/common/names.dart'; -import 'package:angular2/src/transform/common/parser.dart'; import 'package:angular2/src/transform/common/property_utils.dart' as prop; import 'package:barback/barback.dart'; import 'compile_step_factory.dart'; import 'recording_reflection_capabilities.dart'; +import 'view_definition_creator.dart'; import 'xhr_impl.dart'; /// Reads the `.ng_deps.dart` file represented by `entryPoint` and parses any @@ -28,42 +26,40 @@ import 'xhr_impl.dart'; /// /// This method assumes a {@link DomAdapter} has been registered. Future processTemplates(AssetReader reader, AssetId entryPoint) async { - var parser = new Parser(reader); - NgDeps ngDeps = await parser.parse(entryPoint); + var viewDefResults = await createViewDefinitions(reader, entryPoint); var extractor = new _TemplateExtractor(new XhrImpl(reader, entryPoint)); var registrations = new StringBuffer(); - for (var rType in ngDeps.registeredTypes) { - var values = await extractor.extractTemplates(rType); + for (var viewDef in viewDefResults.viewDefinitions.values) { + var values = await extractor.extractTemplates(viewDef); if (values == null) continue; - var calls = _generateGetters('${rType.typeName}', values.getterNames); + var calls = _generateGetters(values.getterNames); if (calls.isNotEmpty) { registrations.write('..${REGISTER_GETTERS_METHOD_NAME}' '({${calls.join(', ')}})'); } - calls = _generateSetters('${rType.typeName}', values.setterNames); + calls = _generateSetters(values.setterNames); if (calls.isNotEmpty) { registrations.write('..${REGISTER_SETTERS_METHOD_NAME}' '({${calls.join(', ')}})'); } - calls = _generateMethods('${rType.typeName}', values.methodNames); + calls = _generateMethods(values.methodNames); if (calls.isNotEmpty) { registrations.write('..${REGISTER_METHODS_METHOD_NAME}' '({${calls.join(', ')}})'); } } - var code = ngDeps.code; + var code = viewDefResults.ngDeps.code; if (registrations.length == 0) return code; - var codeInjectIdx = ngDeps.registeredTypes.last.registerMethod.end; + var codeInjectIdx = + viewDefResults.ngDeps.registeredTypes.last.registerMethod.end; return '${code.substring(0, codeInjectIdx)}' '${registrations}' '${code.substring(codeInjectIdx)}'; } -Iterable _generateGetters( - String typeName, Iterable getterNames) { - // TODO(kegluneq): Include `typeName` where possible. +Iterable _generateGetters(Iterable getterNames) { return getterNames.map((getterName) { if (!prop.isValid(getterName)) { // TODO(kegluenq): Eagerly throw here once #1295 is addressed. @@ -74,8 +70,7 @@ Iterable _generateGetters( }); } -Iterable _generateSetters( - String typeName, Iterable setterName) { +Iterable _generateSetters(Iterable setterName) { return setterName.map((setterName) { if (!prop.isValid(setterName)) { // TODO(kegluenq): Eagerly throw here once #1295 is addressed. @@ -87,8 +82,7 @@ Iterable _generateSetters( }); } -Iterable _generateMethods( - String typeName, Iterable methodNames) { +Iterable _generateMethods(Iterable methodNames) { return methodNames.map((methodName) { if (!prop.isValid(methodName)) { // TODO(kegluenq): Eagerly throw here once #1295 is addressed. @@ -104,85 +98,25 @@ Iterable _generateMethods( /// template code if necessary, and determines what values will be /// reflectively accessed from that template. class _TemplateExtractor { - final CompileStepFactory _factory; - final _TemplateExtractVisitor _visitor = new _TemplateExtractVisitor(); - final TemplateLoader _loader; + final RenderCompiler _compiler; - _TemplateExtractor(XHR xhr) - : _loader = new TemplateLoader(xhr, new UrlResolver()), - _factory = new CompileStepFactory(new ng.Parser(new ng.Lexer())); + _TemplateExtractor(XHR xhr) : _compiler = new DomCompiler( + new CompileStepFactory(new ng.Parser(new ng.Lexer())), + new TemplateLoader(xhr, new UrlResolver())); - Future extractTemplates(RegisteredType t) { - return _processTemplate(_processRegisteredType(t)); - } - - Future _processTemplate( + Future extractTemplates( ViewDefinition viewDef) async { // Check for "imperative views". if (viewDef.template == null && viewDef.absUrl == null) return null; - var recordingCapabilities = new RecordingReflectionCapabilities(); var savedReflectionCapabilities = reflector.reflectionCapabilities; + var recordingCapabilities = new RecordingReflectionCapabilities(); reflector.reflectionCapabilities = recordingCapabilities; // TODO(kegluneq): Rewrite url to inline `template` where possible. - // See [https://github.com/angular/angular/issues/1035]. - var domNode = await _loader.load(viewDef); - - new CompilePipeline(_factory.createSteps(viewDef, [])).process( - domNode, '$domNode'); + await _compiler.compile(viewDef); reflector.reflectionCapabilities = savedReflectionCapabilities; return recordingCapabilities; } - - ViewDefinition _processRegisteredType(RegisteredType t) { - _visitor.reset(); - t.annotations.accept(_visitor); - return _visitor.viewDef; - } -} - -/// Visitor responsible for processing the `annotations` property of a -/// {@link RegisterType} object and pulling out template information. -class _TemplateExtractVisitor extends Object with RecursiveAstVisitor { - ViewDefinition viewDef = new ViewDefinition(); - - void reset() { - viewDef = new ViewDefinition(); - } - - @override - Object visitNamedExpression(NamedExpression node) { - // TODO(kegluneq): Remove this limitation. - if (node.name is! Label || node.name.label is! SimpleIdentifier) { - logger.error( - 'Angular 2 currently only supports simple identifiers in directives.' - ' Source: ${node}'); - return null; - } - var keyString = '${node.name.label}'; - if (keyString == 'template' || keyString == 'templateUrl') { - if (node.expression is! SimpleStringLiteral) { - logger.error( - 'Angular 2 currently only supports string literals in directives.' - ' Source: ${node}'); - return null; - } - var valueString = stringLiteralToString(node.expression); - if (keyString == 'templateUrl') { - if (viewDef.absUrl != null) { - logger.error( - 'Found multiple values for "templateUrl". Source: ${node}'); - } - viewDef.absUrl = valueString; - } else { - if (viewDef.template != null) { - logger.error('Found multiple values for "template". Source: ${node}'); - } - viewDef.template = valueString; - } - } - return null; - } } diff --git a/modules/angular2/src/transform/template_compiler/view_definition_creator.dart b/modules/angular2/src/transform/template_compiler/view_definition_creator.dart new file mode 100644 index 0000000000..ff6e18bb75 --- /dev/null +++ b/modules/angular2/src/transform/template_compiler/view_definition_creator.dart @@ -0,0 +1,232 @@ +library angular2.transform.template_compiler.view_definition_creator; + +import 'dart:async'; +import 'dart:convert'; + +import 'package:analyzer/analyzer.dart'; +import 'package:angular2/src/render/api.dart'; +import 'package:angular2/src/render/dom/convert.dart'; +import 'package:angular2/src/transform/common/asset_reader.dart'; +import 'package:angular2/src/transform/common/logging.dart'; +import 'package:angular2/src/transform/common/names.dart'; +import 'package:angular2/src/transform/common/parser.dart'; +import 'package:barback/barback.dart'; +import 'package:code_transformers/assets.dart'; + +/// Creates [ViewDefinition] objects for all `View` `Directive`s defined in +/// `entryPoint`. +Future createViewDefinitions( + AssetReader reader, AssetId entryPoint) async { + return await new _ViewDefinitionCreator(reader, entryPoint).createViewDefs(); +} + +class ViewDefinitionResults { + final NgDeps ngDeps; + final Map viewDefinitions; + ViewDefinitionResults._(this.ngDeps, this.viewDefinitions); +} + +String _getComponentId(AssetId assetId, String className) => + '$assetId:$className'; + +/// Creates [ViewDefinition] objects for all `View` `Directive`s defined in +/// `entryPoint`. +class _ViewDefinitionCreator { + final AssetReader reader; + final AssetId entryPoint; + final Future ngDepsFuture; + + _ViewDefinitionCreator(AssetReader reader, AssetId entryPoint) + : this.reader = reader, + this.entryPoint = entryPoint, + ngDepsFuture = new Parser(reader).parse(entryPoint); + + Future createViewDefs() async { + var ngDeps = await ngDepsFuture; + + var retVal = {}; + var visitor = new _TemplateExtractVisitor(await _createMetadataMap()); + ngDeps.registeredTypes.forEach((rType) { + visitor.reset(); + rType.annotations.accept(visitor); + if (visitor.viewDef != null) { + var typeName = '${rType.typeName}'; + if (visitor._metadataMap.containsKey(typeName)) { + visitor.viewDef.componentId = visitor._metadataMap[typeName].id; + } else { + logger.warning('Missing component "$typeName" in metadata map', + asset: entryPoint); + visitor.viewDef.componentId = _getComponentId(entryPoint, typeName); + } + retVal[rType] = visitor.viewDef; + } + }); + return new ViewDefinitionResults._(ngDeps, retVal); + } + + /// Creates a map from [AssetId] to import prefix for `.dart` libraries + /// imported by `entryPoint`, excluding any `.ng_deps.dart` files it imports. + /// Unprefixed imports have `null` as their value. `entryPoint` is included + /// in the map with no prefix. + Future> _createImportAssetToPrefixMap() async { + // TODO(kegluneq): Support `part` directives. + var ngDeps = await ngDepsFuture; + + var importAssetToPrefix = {}; + // Include the `.ng_meta.dart` file associated with `entryPoint`. + importAssetToPrefix[new AssetId( + entryPoint.package, toMetaExtension(entryPoint.path))] = null; + + for (ImportDirective node in ngDeps.imports) { + var uri = stringLiteralToString(node.uri); + if (uri.endsWith('.dart') && !uri.endsWith(DEPS_EXTENSION)) { + var prefix = node.prefix != null && node.prefix.name != null + ? '${node.prefix.name}' + : null; + importAssetToPrefix[ + uriToAssetId(entryPoint, uri, logger, null /* span */)] = prefix; + } + } + return importAssetToPrefix; + } + + /// Reads the `.ng_meta.json` files associated with all of `entryPoint`'s + /// imports and creates a map `Type` name, prefixed if appropriate to the + /// associated [DirectiveMetadata]. + /// + /// For example, if in `entryPoint` we have: + /// + /// ``` + /// import 'component.dart' as prefix; + /// ``` + /// + /// and in 'component.dart' we have: + /// + /// ``` + /// @Component(...) + /// class MyComponent {...} + /// ``` + /// + /// This method will look for `component.ng_meta.json`to contain the + /// serialized [DirectiveMetadata] `MyComponent` and any other `Directive`s + /// declared in `component.dart`. We use this information to build a map: + /// + /// ``` + /// { + /// "prefix.MyComponent": [DirectiveMetadata for MyComponent], + /// ...... + /// } + /// ``` + Future> _createMetadataMap() async { + var importAssetToPrefix = await _createImportAssetToPrefixMap(); + + var retVal = {}; + for (var importAssetId in importAssetToPrefix.keys) { + var metaAssetId = new AssetId( + importAssetId.package, toMetaExtension(importAssetId.path)); + if (await reader.hasInput(metaAssetId)) { + try { + var json = await reader.readAsString(metaAssetId); + var jsonMap = JSON.decode(json); + jsonMap.forEach((className, metaDataMap) { + var prefixStr = importAssetToPrefix[importAssetId]; + var key = prefixStr != null ? '$prefixStr.$className' : className; + var value = directiveMetadataFromMap(metaDataMap) + ..id = _getComponentId(importAssetId, className); + retVal[key] = value; + }); + } catch (ex, stackTrace) { + logger.warning('Failed to decode: $ex, $stackTrace', + asset: metaAssetId); + } + } + } + return retVal; + } +} + +/// Visitor responsible for processing the `annotations` property of a +/// {@link RegisterType} object and pulling out [ViewDefinition] information. +class _TemplateExtractVisitor extends Object with RecursiveAstVisitor { + ViewDefinition viewDef = null; + final Map _metadataMap; + + _TemplateExtractVisitor(this._metadataMap); + + void reset() { + viewDef = null; + } + + /// These correspond to the annotations themselves. + @override + Object visitInstanceCreationExpression(InstanceCreationExpression node) { + if ('${node.constructorName.type}' == 'View') { + viewDef = new ViewDefinition(directives: []); + node.visitChildren(this); + } + return null; + } + + /// These correspond to the annotation parameters. + @override + Object visitNamedExpression(NamedExpression node) { + // TODO(kegluneq): Remove this limitation. + if (node.name is! Label || node.name.label is! SimpleIdentifier) { + logger.error( + 'Angular 2 currently only supports simple identifiers in directives.' + ' Source: ${node}'); + return null; + } + var keyString = '${node.name.label}'; + if (keyString == 'directives') { + _readDirectives(node.expression); + } + if (keyString == 'template' || keyString == 'templateUrl') { + if (node.expression is! SimpleStringLiteral) { + logger.error( + 'Angular 2 currently only supports string literals in directives.' + ' Source: ${node}'); + return null; + } + var valueString = stringLiteralToString(node.expression); + if (keyString == 'templateUrl') { + if (viewDef.absUrl != null) { + logger.error( + 'Found multiple values for "templateUrl". Source: ${node}'); + } + viewDef.absUrl = valueString; + } else { + // keyString == 'template' + if (viewDef.template != null) { + logger.error('Found multiple values for "template". Source: ${node}'); + } + viewDef.template = valueString; + } + } + return null; + } + + void _readDirectives(Expression node) { + if (node is! ListLiteral) { + logger.error( + 'Angular 2 currently only supports list literals as values for' + ' "directives". Source: $node'); + return; + } + var directiveList = (node as ListLiteral); + for (var node in directiveList.elements) { + if (node is! SimpleIdentifier && node is! PrefixedIdentifier) { + logger.error( + 'Angular 2 currently only supports simple and prefixed identifiers ' + 'as values for "directives". Source: $node'); + return; + } + var name = '$node'; + if (_metadataMap.containsKey(name)) { + viewDef.directives.add(_metadataMap[name]); + } else { + logger.warning('Could not find Directive entry for $name'); + } + } + } +} diff --git a/modules/angular2/test/transform/integration/all_tests.dart b/modules/angular2/test/transform/integration/all_tests.dart index df4024f815..f32aa8c939 100644 --- a/modules/angular2/test/transform/integration/all_tests.dart +++ b/modules/angular2/test/transform/integration/all_tests.dart @@ -57,6 +57,8 @@ void allTests() { outputs: { 'a|web/bar.ng_deps.dart': 'simple_annotation_files/expected/bar.ng_deps.dart', + 'a|web/bar.ng_meta.json': + 'simple_annotation_files/expected/bar.ng_meta.json', 'a|web/index.ng_deps.dart': 'simple_annotation_files/expected/index.ng_deps.dart' }), diff --git a/modules/angular2/test/transform/integration/simple_annotation_files/expected/bar.ng_meta.json b/modules/angular2/test/transform/integration/simple_annotation_files/expected/bar.ng_meta.json new file mode 100644 index 0000000000..a0ae1769f7 --- /dev/null +++ b/modules/angular2/test/transform/integration/simple_annotation_files/expected/bar.ng_meta.json @@ -0,0 +1 @@ +{"MyComponent":{"id":"MyComponent","selector":"[soup]","compileChildren":true,"hostListeners":{},"hostProperties":{},"properties":{},"readAttributes":[],"type":1,"version":1}} \ No newline at end of file diff --git a/modules/angular2/test/transform/template_compiler/all_tests.dart b/modules/angular2/test/transform/template_compiler/all_tests.dart index 61e60414be..043258ee60 100644 --- a/modules/angular2/test/transform/template_compiler/all_tests.dart +++ b/modules/angular2/test/transform/template_compiler/all_tests.dart @@ -58,6 +58,32 @@ void allTests() { var output = await processTemplates(reader, new AssetId('a', inputPath)); _formatThenExpectEquals(output, expected); }); + + it('should parse `View` directives with a single dependency.', () async { + var inputPath = 'template_compiler/one_directive_files/hello.ng_deps.dart'; + var expected = readFile( + 'template_compiler/one_directive_files/expected/hello.ng_deps.dart'); + + var output = await processTemplates(reader, new AssetId('a', inputPath)); + _formatThenExpectEquals(output, expected); + }); + + it('should parse `View` directives with a single prefixed dependency.', + () async { + var inputPath = 'template_compiler/with_prefix_files/hello.ng_deps.dart'; + var expected = readFile( + 'template_compiler/with_prefix_files/expected/hello.ng_deps.dart'); + + var output = await processTemplates(reader, new AssetId('a', inputPath)); + _formatThenExpectEquals(output, expected); + + inputPath = 'template_compiler/with_prefix_files/goodbye.ng_deps.dart'; + expected = readFile( + 'template_compiler/with_prefix_files/expected/goodbye.ng_deps.dart'); + + output = await processTemplates(reader, new AssetId('a', inputPath)); + _formatThenExpectEquals(output, expected); + }); } void _formatThenExpectEquals(String actual, String expected) { diff --git a/modules/angular2/test/transform/template_compiler/duplicate_files/hello.ng_meta.json b/modules/angular2/test/transform/template_compiler/duplicate_files/hello.ng_meta.json new file mode 100644 index 0000000000..d933030dc4 --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/duplicate_files/hello.ng_meta.json @@ -0,0 +1,14 @@ +{ + "HelloCmp": + { + "id":"HelloCmp", + "selector":"hello-app", + "compileChildren":true, + "hostListeners":{}, + "hostProperties":{}, + "properties":{}, + "readAttributes":[], + "type":1, + "version":1 + } +} \ No newline at end of file diff --git a/modules/angular2/test/transform/template_compiler/inline_expression_files/hello.ng_meta.json b/modules/angular2/test/transform/template_compiler/inline_expression_files/hello.ng_meta.json new file mode 100644 index 0000000000..d933030dc4 --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/inline_expression_files/hello.ng_meta.json @@ -0,0 +1,14 @@ +{ + "HelloCmp": + { + "id":"HelloCmp", + "selector":"hello-app", + "compileChildren":true, + "hostListeners":{}, + "hostProperties":{}, + "properties":{}, + "readAttributes":[], + "type":1, + "version":1 + } +} \ No newline at end of file diff --git a/modules/angular2/test/transform/template_compiler/inline_method_files/hello.ng_meta.json b/modules/angular2/test/transform/template_compiler/inline_method_files/hello.ng_meta.json new file mode 100644 index 0000000000..d933030dc4 --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/inline_method_files/hello.ng_meta.json @@ -0,0 +1,14 @@ +{ + "HelloCmp": + { + "id":"HelloCmp", + "selector":"hello-app", + "compileChildren":true, + "hostListeners":{}, + "hostProperties":{}, + "properties":{}, + "readAttributes":[], + "type":1, + "version":1 + } +} \ No newline at end of file diff --git a/modules/angular2/test/transform/template_compiler/one_directive_files/expected/hello.ng_deps.dart b/modules/angular2/test/transform/template_compiler/one_directive_files/expected/hello.ng_deps.dart new file mode 100644 index 0000000000..4b53eab40b --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/one_directive_files/expected/hello.ng_deps.dart @@ -0,0 +1,28 @@ +library examples.hello_world.index_common_dart.ng_deps.dart; + +import 'hello.dart'; +import 'package:angular2/angular2.dart' + show bootstrap, Component, Directive, View, NgElement; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; + reflector + ..registerType(HelloCmp, { + 'factory': () => new HelloCmp(), + 'parameters': const [const []], + 'annotations': const [ + const Component(selector: 'hello-app'), + const View(template: 'goodbye-app', directives: const [GoodbyeCmp]) + ] + }) + ..registerType(GoodbyeCmp, { + 'factory': () => new GoodbyeCmp(), + 'parameters': const [const []], + 'annotations': const [ + const Component(selector: 'goodbye-app'), + const View(template: 'Goodbye') + ] + }); +} diff --git a/modules/angular2/test/transform/template_compiler/one_directive_files/hello.ng_deps.dart b/modules/angular2/test/transform/template_compiler/one_directive_files/hello.ng_deps.dart new file mode 100644 index 0000000000..4b53eab40b --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/one_directive_files/hello.ng_deps.dart @@ -0,0 +1,28 @@ +library examples.hello_world.index_common_dart.ng_deps.dart; + +import 'hello.dart'; +import 'package:angular2/angular2.dart' + show bootstrap, Component, Directive, View, NgElement; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; + reflector + ..registerType(HelloCmp, { + 'factory': () => new HelloCmp(), + 'parameters': const [const []], + 'annotations': const [ + const Component(selector: 'hello-app'), + const View(template: 'goodbye-app', directives: const [GoodbyeCmp]) + ] + }) + ..registerType(GoodbyeCmp, { + 'factory': () => new GoodbyeCmp(), + 'parameters': const [const []], + 'annotations': const [ + const Component(selector: 'goodbye-app'), + const View(template: 'Goodbye') + ] + }); +} diff --git a/modules/angular2/test/transform/template_compiler/one_directive_files/hello.ng_meta.json b/modules/angular2/test/transform/template_compiler/one_directive_files/hello.ng_meta.json new file mode 100644 index 0000000000..97b57bed1c --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/one_directive_files/hello.ng_meta.json @@ -0,0 +1,25 @@ +{ + "HelloCmp": + { + "id":"HelloCmp", + "selector":"hello-app", + "compileChildren":true, + "hostListeners":{}, + "hostProperties":{}, + "properties":{}, + "readAttributes":[], + "type":1, + "version":1 + }, + "GoodbyeCmp":{ + "id":"GoodbyeCmp", + "selector":"goodbye-app", + "compileChildren":true, + "hostListeners":{}, + "hostProperties":{}, + "properties":{}, + "readAttributes":[], + "type":1, + "version":1 + } +} \ No newline at end of file diff --git a/modules/angular2/test/transform/template_compiler/url_expression_files/hello.ng_meta.json b/modules/angular2/test/transform/template_compiler/url_expression_files/hello.ng_meta.json new file mode 100644 index 0000000000..d933030dc4 --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/url_expression_files/hello.ng_meta.json @@ -0,0 +1,14 @@ +{ + "HelloCmp": + { + "id":"HelloCmp", + "selector":"hello-app", + "compileChildren":true, + "hostListeners":{}, + "hostProperties":{}, + "properties":{}, + "readAttributes":[], + "type":1, + "version":1 + } +} \ No newline at end of file diff --git a/modules/angular2/test/transform/template_compiler/url_method_files/hello.ng_meta.json b/modules/angular2/test/transform/template_compiler/url_method_files/hello.ng_meta.json new file mode 100644 index 0000000000..d933030dc4 --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/url_method_files/hello.ng_meta.json @@ -0,0 +1,14 @@ +{ + "HelloCmp": + { + "id":"HelloCmp", + "selector":"hello-app", + "compileChildren":true, + "hostListeners":{}, + "hostProperties":{}, + "properties":{}, + "readAttributes":[], + "type":1, + "version":1 + } +} \ No newline at end of file diff --git a/modules/angular2/test/transform/template_compiler/with_prefix_files/expected/goodbye.ng_deps.dart b/modules/angular2/test/transform/template_compiler/with_prefix_files/expected/goodbye.ng_deps.dart new file mode 100644 index 0000000000..297b26e0c5 --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/with_prefix_files/expected/goodbye.ng_deps.dart @@ -0,0 +1,22 @@ +library examples.hello_world.index_common_dart.ng_deps.dart; + +import 'goodbye.dart'; +import 'package:angular2/angular2.dart' + show bootstrap, Component, Directive, View, NgElement; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; + reflector + ..registerType(GoodbyeCmp, { + 'factory': () => new GoodbyeCmp(), + 'parameters': const [const []], + 'annotations': const [ + const Component(selector: 'goodbye-app'), + const View(template: 'Goodbye {{name}}') + ] + }) + ..registerGetters({'name': (o) => o.name}) + ..registerSetters({'name': (o, v) => o.name = v}); +} diff --git a/modules/angular2/test/transform/template_compiler/with_prefix_files/expected/hello.ng_deps.dart b/modules/angular2/test/transform/template_compiler/with_prefix_files/expected/hello.ng_deps.dart new file mode 100644 index 0000000000..6dd69eb21c --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/with_prefix_files/expected/hello.ng_deps.dart @@ -0,0 +1,24 @@ +library examples.hello_world.index_common_dart.ng_deps.dart; + +import 'hello.dart'; +import 'goodbye.dart' as prefix; +import 'goodbye.ng_deps.dart' as i0; +import 'package:angular2/angular2.dart' + show bootstrap, Component, Directive, View, NgElement; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; + reflector + ..registerType(HelloCmp, { + 'factory': () => new HelloCmp(), + 'parameters': const [const []], + 'annotations': const [ + const Component(selector: 'hello-app'), + const View( + template: 'goodbye-app', directives: const [prefix.GoodbyeCmp]) + ] + }); + i0.initReflector(reflector); +} diff --git a/modules/angular2/test/transform/template_compiler/with_prefix_files/goodbye.ng_deps.dart b/modules/angular2/test/transform/template_compiler/with_prefix_files/goodbye.ng_deps.dart new file mode 100644 index 0000000000..4e17a6d062 --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/with_prefix_files/goodbye.ng_deps.dart @@ -0,0 +1,20 @@ +library examples.hello_world.index_common_dart.ng_deps.dart; + +import 'goodbye.dart'; +import 'package:angular2/angular2.dart' + show bootstrap, Component, Directive, View, NgElement; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; + reflector + ..registerType(GoodbyeCmp, { + 'factory': () => new GoodbyeCmp(), + 'parameters': const [const []], + 'annotations': const [ + const Component(selector: 'goodbye-app'), + const View(template: 'Goodbye {{name}}') + ] + }); +} diff --git a/modules/angular2/test/transform/template_compiler/with_prefix_files/goodbye.ng_meta.json b/modules/angular2/test/transform/template_compiler/with_prefix_files/goodbye.ng_meta.json new file mode 100644 index 0000000000..158b2eac80 --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/with_prefix_files/goodbye.ng_meta.json @@ -0,0 +1,13 @@ +{ + "GoodbyeCmp":{ + "id":"GoodbyeCmp", + "selector":"goodbye-app", + "compileChildren":true, + "hostListeners":{}, + "hostProperties":{}, + "properties":{}, + "readAttributes":[], + "type":1, + "version":1 + } +} \ No newline at end of file diff --git a/modules/angular2/test/transform/template_compiler/with_prefix_files/hello.ng_deps.dart b/modules/angular2/test/transform/template_compiler/with_prefix_files/hello.ng_deps.dart new file mode 100644 index 0000000000..6dd69eb21c --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/with_prefix_files/hello.ng_deps.dart @@ -0,0 +1,24 @@ +library examples.hello_world.index_common_dart.ng_deps.dart; + +import 'hello.dart'; +import 'goodbye.dart' as prefix; +import 'goodbye.ng_deps.dart' as i0; +import 'package:angular2/angular2.dart' + show bootstrap, Component, Directive, View, NgElement; + +var _visited = false; +void initReflector(reflector) { + if (_visited) return; + _visited = true; + reflector + ..registerType(HelloCmp, { + 'factory': () => new HelloCmp(), + 'parameters': const [const []], + 'annotations': const [ + const Component(selector: 'hello-app'), + const View( + template: 'goodbye-app', directives: const [prefix.GoodbyeCmp]) + ] + }); + i0.initReflector(reflector); +} diff --git a/modules/angular2/test/transform/template_compiler/with_prefix_files/hello.ng_meta.json b/modules/angular2/test/transform/template_compiler/with_prefix_files/hello.ng_meta.json new file mode 100644 index 0000000000..d933030dc4 --- /dev/null +++ b/modules/angular2/test/transform/template_compiler/with_prefix_files/hello.ng_meta.json @@ -0,0 +1,14 @@ +{ + "HelloCmp": + { + "id":"HelloCmp", + "selector":"hello-app", + "compileChildren":true, + "hostListeners":{}, + "hostProperties":{}, + "properties":{}, + "readAttributes":[], + "type":1, + "version":1 + } +} \ No newline at end of file diff --git a/tools/broccoli/trees/dart_tree.ts b/tools/broccoli/trees/dart_tree.ts index 1cbf02586f..6636ba9c3b 100644 --- a/tools/broccoli/trees/dart_tree.ts +++ b/tools/broccoli/trees/dart_tree.ts @@ -46,7 +46,7 @@ function getSourceTree() { var tsInputTree = modulesFunnel(['**/*.js', '**/*.ts', '**/*.dart'], ['rtts_assert/**/*']); var transpiled = ts2dart.transpile(tsInputTree); // Native sources, dart only examples, etc. - var dartSrcs = modulesFunnel(['**/*.dart']); + var dartSrcs = modulesFunnel(['**/*.dart', '**/*.ng_meta.json']); return mergeTrees([transpiled, dartSrcs]); }