From 52236bd76570088b3856282cbbe9fd91d0d0a9a7 Mon Sep 17 00:00:00 2001 From: Tim Blasi Date: Thu, 1 Oct 2015 09:10:26 -0700 Subject: [PATCH] refactor(transformer): use the new compiler Part of #3605 --- .../transform/bind_generator/generator.dart | 49 +- .../transform/common/code/ng_deps_code.dart | 23 +- .../transform/common/code/source_module.dart | 34 ++ .../lib/src/transform/common/code/uri.dart | 76 +++ .../common/directive_metadata_reader.dart | 568 ++++++++++-------- .../common/model/ng_deps_model.pb.dart | 62 +- .../common/model/ng_deps_model.proto | 5 + .../lib/src/transform/common/names.dart | 41 +- .../lib/src/transform/common/ng_compiler.dart | 40 ++ .../lib/src/transform/common/ng_meta.dart | 40 +- .../lib/src/transform/common/options.dart | 16 +- .../src/transform/common/options_reader.dart | 15 +- .../src/transform/common/registered_type.dart | 19 +- .../src/transform/common/url_resolver.dart | 57 ++ .../lib/src/transform/common/xhr_impl.dart | 25 +- .../lib/src/transform/di_transformer.dart | 36 -- .../directive_linker/transformer.dart | 8 +- .../extractor.dart | 74 --- .../transformer.dart | 49 -- .../directive_metadata_linker/linker.dart | 78 +++ .../transformer.dart | 56 ++ .../directive_processor/inliner.dart | 220 +++---- .../directive_processor/rewriter.dart | 177 ++---- .../directive_processor/transformer.dart | 35 +- .../lib/src/transform/inliner_for_test.dart | 151 +++++ .../change_detector_codegen.dart | 47 +- ...creator.dart => compile_data_creator.dart} | 134 ++--- .../compile_step_factory.dart | 25 - .../template_compiler/generator.dart | 221 ++++--- .../template_compiler/reflection/codegen.dart | 15 +- .../template_compiler/reflection/model.dart | 6 +- .../reflection/processor.dart | 110 +--- .../reflection/reflection_capabilities.dart | 2 - .../template_compiler/transformer.dart | 22 +- .../lib/src/transform/transformer.dart | 15 +- .../transform/bind_generator/all_tests.dart | 25 +- .../events_files/bar.ng_deps.dart | 18 - .../events_files/expected/bar.ng_deps.dart | 19 - .../ng_for.ng_meta.dart | 26 + .../test/transform/common/ng_meta_test.dart | 11 +- .../adjacent_strings_files/foo.ng_deps.dart | 15 - .../all_tests.dart | 246 -------- .../directive_aliases_files/bar.aliases.json | 8 - .../directive_aliases_files/foo.aliases.json | 9 - .../changeDetection.ng_deps.dart | 19 - .../compile_children.ng_deps.dart | 23 - .../directive_export_as.ng_deps.dart | 16 - .../events.ng_deps.dart | 19 - .../host_listeners.ng_deps.dart | 23 - .../lifecycle.ng_deps.dart | 40 -- .../properties.ng_deps.dart | 19 - .../selector.ng_deps.dart | 16 - .../too_many_directives.ng_deps.dart | 20 - .../export_files/bar.ng_deps.dart | 15 - .../recursive_export_files/foo.ng_deps.dart | 19 - .../simple_files/foo.ng_deps.dart | 15 - .../absolute_export_files/bar.ng_deps.dart | 0 .../absolute_export_files/bar.ng_meta.json | 32 + .../absolute_export_files/foo.ng_deps.dart | 0 .../absolute_export_files/foo.ng_meta.json | 33 + .../directive_metadata_linker/all_tests.dart | 79 +++ .../export_cycle_files/bar.ng_meta.json | 33 + .../export_cycle_files/baz.ng_meta.json | 33 + .../export_cycle_files/foo.ng_meta.json | 33 + .../export_files}/bar.ng_deps.dart | 0 .../export_files/bar.ng_meta.json | 32 + .../export_files}/foo.ng_deps.dart | 0 .../export_files/foo.ng_meta.json | 33 + .../recursive_export_files/bar.ng_deps.dart | 0 .../recursive_export_files/bar.ng_meta.json | 33 + .../recursive_export_files/baz.ng_deps.dart | 0 .../recursive_export_files/baz.ng_meta.json | 32 + .../recursive_export_files}/foo.ng_deps.dart | 0 .../recursive_export_files/foo.ng_meta.json | 33 + .../directive_processor/all_tests.dart | 262 ++++---- .../custom_metadata/package_soup.dart | 2 + .../custom_metadata/relative_soup.dart | 2 + .../interface_chain_files/soup.dart | 1 + .../interfaces_files/soup.dart | 1 + .../soup.dart | 1 + .../multiple_part_files/main.dart | 1 + .../multiple_part_files/part1.dart | 1 + .../multiple_part_files/part2.dart | 1 + .../hello.dart | 10 - .../template_other.css | 1 - .../parameter_metadata/soup.dart | 1 + .../directive_processor/part_files/main.dart | 1 + .../directive_processor/part_files/part.dart | 1 + .../soup.dart | 1 + .../prop_metadata_files/fields.dart | 1 + .../prop_metadata_files/getters.dart | 1 + .../getters_and_setters.dart | 1 + .../prop_metadata_files/setters.dart | 1 + .../superclass_files/soup.dart | 1 + .../superclass_lifecycle_files/soup.dart | 1 + .../template_files/property.dart | 8 + .../unusual_component_files/hello.dart | 22 + .../template.html | 0 .../absolute_url_expression_files/hello.dart | 13 + .../template.css | 0 .../template.html | 0 .../transform/inliner_for_test/all_tests.dart | 84 +++ .../multiple_style_urls_files/hello.dart | 0 .../multiple_style_urls_files}/template.css | 0 .../multiple_style_urls_files}/template.html | 0 .../template_other.css | 0 .../split_url_expression_files/hello.dart | 0 .../split_url_expression_files}/template.html | 0 .../url_expression_files/hello.dart | 0 .../url_expression_files/template.html | 1 + .../test/transform/integration/all_tests.dart | 61 +- .../directive_chain_files/bar.dart | 10 + .../directive_chain_files/baz.dart | 3 + .../expected/bar.ng_deps.dart | 25 + .../directive_chain_files/foo.dart | 6 + .../directive_chain_files/index.dart | 10 + .../integration/directive_dep_files/bar.dart | 10 + .../expected/bar.ng_deps.dart | 25 + .../integration/directive_dep_files/foo.dart | 6 + .../directive_dep_files/index.dart | 10 + .../integration/event_getter_files/bar.dart | 9 + .../expected/bar.ng_deps.dart | 26 + .../integration/event_getter_files/index.dart | 11 + .../integration/list_of_types_files/bar.dart | 1 + .../expected/bar.ng_deps.dart | 6 +- .../simple_annotation_files/bar.dart | 1 + .../expected/bar.ng_deps.dart | 9 +- .../expected/index.ng_deps.dart | 4 +- .../integration/synthetic_ctor_files/bar.dart | 1 + .../expected/bar.ng_deps.dart | 9 +- .../expected/bar.ng_deps.dart | 80 +-- .../integration/two_deps_files/bar.dart | 1 + .../two_deps_files/expected/bar.ng_deps.dart | 6 +- .../template_compiler/all_tests.dart | 49 +- .../hello1.ng_meta.json | 60 +- .../hello2.ng_meta.json | 60 +- .../duplicate_files/hello.ng_meta.json | 16 - .../expected/hello.ng_deps.dart | 9 +- .../hello.ng_deps.dart | 4 +- .../event_files/hello.ng_meta.json | 32 + .../expected/hello.ng_deps.dart | 9 +- .../hello.ng_meta.json | 30 +- .../expected/hello.ng_deps.dart | 9 +- .../inline_method_files/hello.ng_meta.json | 30 +- .../ng_for_files/hello.ng_deps.dart | 1 + .../ng_for_files/hello.ng_meta.json | 30 +- .../expected/hello.ng_deps.dart | 8 +- .../one_directive_files/hello.ng_meta.json | 60 +- .../expected/hello.ng_deps.dart | 8 +- .../url_expression_files/hello.ng_meta.json | 30 +- .../expected/hello.ng_deps.dart | 9 +- .../url_method_files/hello.ng_meta.json | 30 +- .../expected/goodbye.ng_deps.dart | 8 +- .../expected/hello.ng_deps.dart | 5 +- .../expected/ng2_prefix.ng_deps.dart | 8 +- .../with_prefix_files/goodbye.ng_meta.json | 30 +- .../with_prefix_files/hello.ng_meta.json | 30 +- .../with_prefix_files/ng2_prefix.ng_meta.json | 30 +- .../test/transform/transform.server.spec.dart | 8 +- 159 files changed, 2770 insertions(+), 2162 deletions(-) create mode 100644 modules_dart/transform/lib/src/transform/common/code/source_module.dart create mode 100644 modules_dart/transform/lib/src/transform/common/code/uri.dart create mode 100644 modules_dart/transform/lib/src/transform/common/ng_compiler.dart create mode 100644 modules_dart/transform/lib/src/transform/common/url_resolver.dart delete mode 100644 modules_dart/transform/lib/src/transform/di_transformer.dart delete mode 100644 modules_dart/transform/lib/src/transform/directive_metadata_extractor/extractor.dart delete mode 100644 modules_dart/transform/lib/src/transform/directive_metadata_extractor/transformer.dart create mode 100644 modules_dart/transform/lib/src/transform/directive_metadata_linker/linker.dart create mode 100644 modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart create mode 100644 modules_dart/transform/lib/src/transform/inliner_for_test.dart rename modules_dart/transform/lib/src/transform/template_compiler/{view_definition_creator.dart => compile_data_creator.dart} (63%) delete mode 100644 modules_dart/transform/lib/src/transform/template_compiler/compile_step_factory.dart delete mode 100644 modules_dart/transform/test/transform/bind_generator/events_files/bar.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/bind_generator/events_files/expected/bar.ng_deps.dart create mode 100644 modules_dart/transform/test/transform/common/compile_directive_metadata/ng_for.ng_meta.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/adjacent_strings_files/foo.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/all_tests.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/bar.aliases.json delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/foo.aliases.json delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/changeDetection.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/compile_children.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/directive_export_as.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/events.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/host_listeners.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/lifecycle.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/properties.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/selector.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/too_many_directives.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/export_files/bar.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/recursive_export_files/foo.ng_deps.dart delete mode 100644 modules_dart/transform/test/transform/directive_metadata_extractor/simple_files/foo.ng_deps.dart rename modules_dart/transform/test/transform/{directive_metadata_extractor => directive_metadata_linker}/absolute_export_files/bar.ng_deps.dart (100%) create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/bar.ng_meta.json rename modules_dart/transform/test/transform/{directive_metadata_extractor => directive_metadata_linker}/absolute_export_files/foo.ng_deps.dart (100%) create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/foo.ng_meta.json create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/all_tests.dart create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/bar.ng_meta.json create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/baz.ng_meta.json create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/foo.ng_meta.json rename modules_dart/transform/test/transform/{directive_metadata_extractor/directive_aliases_files => directive_metadata_linker/export_files}/bar.ng_deps.dart (100%) create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/export_files/bar.ng_meta.json rename modules_dart/transform/test/transform/{directive_metadata_extractor/directive_aliases_files => directive_metadata_linker/export_files}/foo.ng_deps.dart (100%) create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/export_files/foo.ng_meta.json rename modules_dart/transform/test/transform/{directive_metadata_extractor => directive_metadata_linker}/recursive_export_files/bar.ng_deps.dart (100%) create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/bar.ng_meta.json rename modules_dart/transform/test/transform/{directive_metadata_extractor => directive_metadata_linker}/recursive_export_files/baz.ng_deps.dart (100%) create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/baz.ng_meta.json rename modules_dart/transform/test/transform/{directive_metadata_extractor/export_files => directive_metadata_linker/recursive_export_files}/foo.ng_deps.dart (100%) create mode 100644 modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/foo.ng_meta.json delete mode 100644 modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/hello.dart delete mode 100644 modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/template_other.css create mode 100644 modules_dart/transform/test/transform/directive_processor/template_files/property.dart create mode 100644 modules_dart/transform/test/transform/directive_processor/unusual_component_files/hello.dart rename modules_dart/transform/test/transform/directive_processor/{multiple_style_urls_files => unusual_component_files}/template.html (100%) create mode 100644 modules_dart/transform/test/transform/inliner_for_test/absolute_url_expression_files/hello.dart rename modules_dart/transform/test/transform/{directive_processor/multiple_style_urls_files => inliner_for_test/absolute_url_expression_files}/template.css (100%) rename modules_dart/transform/test/transform/{directive_processor/multiple_style_urls_not_inlined_files => inliner_for_test/absolute_url_expression_files}/template.html (100%) create mode 100644 modules_dart/transform/test/transform/inliner_for_test/all_tests.dart rename modules_dart/transform/test/transform/{directive_processor => inliner_for_test}/multiple_style_urls_files/hello.dart (100%) rename modules_dart/transform/test/transform/{directive_processor/multiple_style_urls_not_inlined_files => inliner_for_test/multiple_style_urls_files}/template.css (100%) rename modules_dart/transform/test/transform/{directive_processor/split_url_expression_files => inliner_for_test/multiple_style_urls_files}/template.html (100%) rename modules_dart/transform/test/transform/{directive_processor => inliner_for_test}/multiple_style_urls_files/template_other.css (100%) rename modules_dart/transform/test/transform/{directive_processor => inliner_for_test}/split_url_expression_files/hello.dart (100%) rename modules_dart/transform/test/transform/{directive_processor/url_expression_files => inliner_for_test/split_url_expression_files}/template.html (100%) rename modules_dart/transform/test/transform/{directive_processor => inliner_for_test}/url_expression_files/hello.dart (100%) create mode 100644 modules_dart/transform/test/transform/inliner_for_test/url_expression_files/template.html create mode 100644 modules_dart/transform/test/transform/integration/directive_chain_files/bar.dart create mode 100644 modules_dart/transform/test/transform/integration/directive_chain_files/baz.dart create mode 100644 modules_dart/transform/test/transform/integration/directive_chain_files/expected/bar.ng_deps.dart create mode 100644 modules_dart/transform/test/transform/integration/directive_chain_files/foo.dart create mode 100644 modules_dart/transform/test/transform/integration/directive_chain_files/index.dart create mode 100644 modules_dart/transform/test/transform/integration/directive_dep_files/bar.dart create mode 100644 modules_dart/transform/test/transform/integration/directive_dep_files/expected/bar.ng_deps.dart create mode 100644 modules_dart/transform/test/transform/integration/directive_dep_files/foo.dart create mode 100644 modules_dart/transform/test/transform/integration/directive_dep_files/index.dart create mode 100644 modules_dart/transform/test/transform/integration/event_getter_files/bar.dart create mode 100644 modules_dart/transform/test/transform/integration/event_getter_files/expected/bar.ng_deps.dart create mode 100644 modules_dart/transform/test/transform/integration/event_getter_files/index.dart delete mode 100644 modules_dart/transform/test/transform/template_compiler/duplicate_files/hello.ng_meta.json rename modules_dart/transform/test/transform/template_compiler/{duplicate_files => event_files}/expected/hello.ng_deps.dart (60%) rename modules_dart/transform/test/transform/template_compiler/{duplicate_files => event_files}/hello.ng_deps.dart (76%) create mode 100644 modules_dart/transform/test/transform/template_compiler/event_files/hello.ng_meta.json diff --git a/modules_dart/transform/lib/src/transform/bind_generator/generator.dart b/modules_dart/transform/lib/src/transform/bind_generator/generator.dart index 3bcdd14861..acc0091065 100644 --- a/modules_dart/transform/lib/src/transform/bind_generator/generator.dart +++ b/modules_dart/transform/lib/src/transform/bind_generator/generator.dart @@ -34,7 +34,6 @@ class _ExtractQueryFieldsFromAnnotation extends Object } } - class _ExtractQueryFieldsFromPropMetadata extends Object with RecursiveAstVisitor { final ConstantEvaluator _evaluator = new ConstantEvaluator(); @@ -52,7 +51,10 @@ class _ExtractQueryFieldsFromPropMetadata extends Object var res = false; list.elements.forEach((item) { var n = item.constructorName.toString(); - if(n == "ContentChild" || n == "ViewChild" || n == "ContentChildren" || n == "ViewChildren") { + if (n == "ContentChild" || + n == "ViewChild" || + n == "ContentChildren" || + n == "ViewChildren") { res = true; } }); @@ -65,14 +67,12 @@ class _ExtractQueryFieldsFromPropMetadata extends Object } } - Future createNgSettersAndGetters( AssetReader reader, AssetId entryPoint) async { NgDeps ngDeps = await NgDeps.parse(reader, entryPoint); String code = ngDeps.code; var setters = _generateSetters(_createPropertiesMap(ngDeps)); - var getters = _generateGetters(_createEventPropertiesList(ngDeps)); ngDeps.registeredTypes.forEach((t) { final fromAnnotation = new _ExtractQueryFieldsFromAnnotation(); @@ -86,16 +86,13 @@ Future createNgSettersAndGetters( setters.addAll(_generateSetters(fromPropMetadata.asMap())); }); - if (setters.isEmpty && getters.isEmpty) return code; + if (setters.isEmpty) return code; var out = new StringBuffer(); var codeInjectIdx = ngDeps.registeredTypes.last.registerMethod.end; out.write(code.substring(0, codeInjectIdx)); if (setters.isNotEmpty) { out.write('..registerSetters({${setters.join(', ')}})'); } - if (getters.isNotEmpty) { - out.write('..registerGetters({${getters.join(', ')}})'); - } out.write(code.substring(codeInjectIdx)); return '$out'; } @@ -123,7 +120,7 @@ List _generateSetters(Map bindMap) { /// the bind properties and the values are either the one and only type /// binding to that property or the empty string. Map _createPropertiesMap(NgDeps ngDeps) { - var visitor = new ExtractNamedExpressionVisitor('inputs'); + var visitor = new ExtractNamedExpressionVisitor('properties'); var bindMap = {}; ngDeps.registeredTypes.forEach((RegisteredType t) { visitor.bindConfig.clear(); @@ -147,37 +144,3 @@ Map _createPropertiesMap(NgDeps ngDeps) { }); return bindMap; } - -/// Consumes the list generated by {@link _createEventPropertiesList} to codegen -/// getters. -List _generateGetters(List eventProperties) { - var getters = []; - // TODO(kegluneq): Include types for receivers. See #886. - for (var property in eventProperties) { - if (!prop.isValid(property)) { - // TODO(kegluenq): Eagerly throw here once #1295 is addressed. - getters.add(prop.lazyInvalidGetter(property)); - } else { - getters.add(''' '${prop.sanitize(property)}': (o) => o.$property'''); - } - } - return getters; -} - -/// Collapses all `events` in {@link ngDeps} into a list of corresponding -/// property names. -List _createEventPropertiesList(NgDeps ngDeps) { - var visitor = new ExtractNamedExpressionVisitor('outputs'); - var propertyNames = []; - ngDeps.registeredTypes.forEach((RegisteredType t) { - visitor.bindConfig.clear(); - t.annotations.accept(visitor); - visitor.bindConfig.forEach((String config) { - // See comments for `Directive` in annotations_impl/annotations.ts for - // details on how `events` is specified. We are pulling out the property - // name only (everything before the first `:`). - propertyNames.add(config.split(':').first.trim()); - }); - }); - return propertyNames; -} diff --git a/modules_dart/transform/lib/src/transform/common/code/ng_deps_code.dart b/modules_dart/transform/lib/src/transform/common/code/ng_deps_code.dart index b99c393f58..d34a76c240 100644 --- a/modules_dart/transform/lib/src/transform/common/code/ng_deps_code.dart +++ b/modules_dart/transform/lib/src/transform/common/code/ng_deps_code.dart @@ -38,17 +38,9 @@ class NgDepsVisitor extends RecursiveAstVisitor { } void _createModel(String libraryUri) { - _model = new NgDepsModel()..libraryUri = libraryUri; - - // We need to import & export the original file. - var origDartFile = path.basename(processedFile.path); - _model.imports.add(new ImportModel()..uri = origDartFile); - _model.exports.add(new ExportModel()..uri = origDartFile); - - // Used to register reflective information. - _model.imports.add(new ImportModel() - ..uri = REFLECTOR_IMPORT - ..prefix = REFLECTOR_PREFIX); + _model = new NgDepsModel() + ..libraryUri = libraryUri + ..sourceFile = path.basename(processedFile.path); } @override @@ -139,6 +131,14 @@ abstract class NgDepsWriterMixin buffer.writeln('library ${model.libraryUri}${DEPS_EXTENSION};\n'); } + // We need to import & export the source file. + writeImportModel(new ImportModel()..uri = model.sourceFile); + + // Used to register reflective information. + writeImportModel(new ImportModel() + ..uri = REFLECTOR_IMPORT + ..prefix = REFLECTOR_PREFIX); + // We do not support `partUris`, so skip outputting them. for (var importModel in model.imports) { // Ignore deferred imports here so as to not load the deferred libraries @@ -149,6 +149,7 @@ abstract class NgDepsWriterMixin writeImportModel(importModel); } + writeExportModel(new ExportModel()..uri = model.sourceFile); model.exports.forEach(writeExportModel); buffer diff --git a/modules_dart/transform/lib/src/transform/common/code/source_module.dart b/modules_dart/transform/lib/src/transform/common/code/source_module.dart new file mode 100644 index 0000000000..c6eec03e9c --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/code/source_module.dart @@ -0,0 +1,34 @@ +library angular2.transform.common.code.reflection_info_code; + +import 'package:angular2/src/compiler/source_module.dart'; + +import 'uri.dart'; + +/// Writes the full Dart code for the provided [SourceModule]. +/// +/// If `libraryName` is provided, the generated source will be generated with +/// the approprate "library" directive. +String writeSourceModule(SourceModule sourceModule, {String libraryName}) { + if (sourceModule == null) return null; + var buf = new StringBuffer(); + var sourceWithImports = sourceModule.getSourceWithImports(); + + if (libraryName != null && libraryName.isNotEmpty) { + buf..writeln('library $libraryName;')..writeln(); + } + sourceWithImports.imports.forEach((import) { + // Format for importLine := [uri, prefix] + if (import.length != 2) { + throw new FormatException( + 'Unexpected import format! ' + 'Angular 2 compiler returned imports in an unexpected format. ' + 'Expected [, ].', + import.join(', ')); + } + buf.writeln(writeImportUri(import[0], + prefix: import[1], fromAbsolute: sourceModule.moduleUrl)); + }); + buf..writeln()..writeln(sourceWithImports.source); + + return buf.toString(); +} diff --git a/modules_dart/transform/lib/src/transform/common/code/uri.dart b/modules_dart/transform/lib/src/transform/common/code/uri.dart new file mode 100644 index 0000000000..0815e154df --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/code/uri.dart @@ -0,0 +1,76 @@ +library angular2.transform.common.code.reflection_info_code; + +import 'package:angular2/src/transform/common/url_resolver.dart'; +import 'package:path/path.dart' as path; + +/// Generates an `import` statement for the file specified by `importPath`. +/// +/// If `fromAbsolute` is specified, `importPath` may be a relative path, +/// otherwise it is expected to be absolute. +String writeImportUri(String importPath, {String prefix, String fromAbsolute}) { + var codegenImportPath; + + var resolver = const TransformerUrlResolver(); + var importUri = resolver.toAssetScheme(Uri.parse(importPath)); + if (_canPackageImport(importUri) || + fromAbsolute == null || + fromAbsolute.isEmpty) { + codegenImportPath = _toPackageImport(importUri); + } else { + var moduleUri = resolver.toAssetScheme(Uri.parse(fromAbsolute)); + if (_canImportRelative(importUri, from: moduleUri)) { + codegenImportPath = path.url.relative(importUri.toString(), + from: path.dirname(moduleUri.toString())); + } else { + var errMsg; + if (fromAbsolute == null || fromAbsolute.isEmpty) { + errMsg = 'Can only import $importPath using a relative uri'; + } else { + errMsg = 'Cannot import $importPath from $fromAbsolute'; + } + throw new FormatException(errMsg, importPath); + } + } + + if (prefix != null && prefix.isNotEmpty) { + prefix = ' as $prefix'; + } + return 'import \'$codegenImportPath\'$prefix;'; +} + +// For a relative import, the scheme, first (package) and second (lib|test|web) +// path segments must be equal. +bool _canImportRelative(Uri importUri, {Uri from}) { + if (importUri == null) throw new ArgumentError.notNull('importUri'); + if (from == null) throw new ArgumentError.notNull('from'); + assert(importUri.scheme == 'asset'); + assert(importUri.pathSegments.length >= 2); + assert(from.scheme == 'asset'); + assert(from.pathSegments.length >= 2); + return importUri.pathSegments.first == from.pathSegments.first && + importUri.pathSegments[1] == from.pathSegments[1]; +} + +/// Pub's package scheme assumes that an asset lives under the lib/ directory, +/// so an asset: Uri is package-importable if its second path segment is lib/. +/// +/// For a file located at angular2/lib/src/file.dart: +/// - Asset scheme => asset:angular2/lib/src/file.dart +/// - Package scheme => package:angular2/src/file.dart +bool _canPackageImport(Uri assetImport) { + if (assetImport == null) throw new ArgumentError.notNull('assetImport'); + if (!assetImport.isAbsolute || assetImport.scheme != 'asset') { + throw new ArgumentError.value(assetImport, 'assetImport', + 'Must be an absolute uri using the asset: scheme'); + } + return assetImport.pathSegments.length >= 2 && + assetImport.pathSegments[1] == 'lib'; +} + +String _toPackageImport(Uri assetImport) { + assert(_canPackageImport(assetImport)); + var subPath = assetImport.pathSegments + .getRange(2, assetImport.pathSegments.length) + .join('/'); + return 'package:${assetImport.pathSegments.first}/$subPath'; +} diff --git a/modules_dart/transform/lib/src/transform/common/directive_metadata_reader.dart b/modules_dart/transform/lib/src/transform/common/directive_metadata_reader.dart index 5a93e1e134..da790aec9c 100644 --- a/modules_dart/transform/lib/src/transform/common/directive_metadata_reader.dart +++ b/modules_dart/transform/lib/src/transform/common/directive_metadata_reader.dart @@ -1,212 +1,224 @@ library angular2.transform.common.directive_metadata_reader; +import 'dart:async'; + import 'package:analyzer/analyzer.dart'; -import 'package:analyzer/src/generated/element.dart'; -import 'package:angular2/src/core/render/api.dart'; +import 'package:angular2/src/compiler/directive_metadata.dart'; +import 'package:angular2/src/compiler/template_compiler.dart'; import 'package:angular2/src/core/change_detection/change_detection.dart'; +import 'package:angular2/src/core/compiler/interfaces.dart' show LifecycleHooks; +import 'package:angular2/src/core/render/api.dart' show ViewEncapsulation; +import 'package:angular2/src/transform/common/annotation_matcher.dart'; +import 'package:angular2/src/transform/common/interface_matcher.dart'; +import 'package:barback/barback.dart' show AssetId; -/// Reads [RenderDirectiveMetadata] from the `node`. `node` is expected to be an -/// instance of [ClassDeclaration] (a class which may have a [Directive] or -/// [Component] annotation) or an [InstanceCreationExpression] (an instantiation -/// of [ReflectionInfo]). -RenderDirectiveMetadata readDirectiveMetadata(AstNode node) { - var visitor; - if (node is ClassDeclaration) { - visitor = new _DeclarationVisitor(); - } else if (node is InstanceCreationExpression) { - visitor = new _ReflectionInfoVisitor(); - } else { - throw new ArgumentError('Incorrect value passed to readDirectiveMetadata. ' - 'Expected types are ClassDeclaration and InstanceCreationExpression ' - 'Provided type was ${node.runtimeType}'); - } - node.accept(visitor); - return visitor.meta; -} +class DirectiveMetadataReader { + final _DirectiveMetadataVisitor _visitor; + final TemplateCompiler _templateCompiler; -num _getDirectiveType(String annotationName, Element element) { - var byNameMatch = -1; - // TODO(kegluneq): Detect subtypes & implementations of `Directive`s. - switch (annotationName) { - case 'Directive': - byNameMatch = RenderDirectiveMetadata.DIRECTIVE_TYPE; - break; - case 'Component': - byNameMatch = RenderDirectiveMetadata.COMPONENT_TYPE; - break; - default: - return -1; + DirectiveMetadataReader._(this._visitor, this._templateCompiler); + + /// Accepts an [AnnotationMatcher] which tests that an [Annotation] + /// is a [Directive], [Component], or [View]. + factory DirectiveMetadataReader(AnnotationMatcher annotationMatcher, + InterfaceMatcher interfaceMatcher, TemplateCompiler templateCompiler) { + var lifecycleVisitor = new _LifecycleHookVisitor(interfaceMatcher); + var visitor = + new _DirectiveMetadataVisitor(annotationMatcher, lifecycleVisitor); + + return new DirectiveMetadataReader._(visitor, templateCompiler); } - if (element != null) { - var byResolvedAst = -1; - var libName = element.library.name; - // If we have resolved, ensure the library is correct. - if (libName == 'angular2.src.core.metadata.directives' || - libName == 'angular2.src.core.metadata') { - byResolvedAst = byNameMatch; + + /// Reads *un-normalized* [CompileDirectiveMetadata] from the + /// [ClassDeclaration] `node`. + /// + /// `node` is expected to be a class which may have a [Directive] or [Component] + /// annotation. If `node` does not have one of these annotations, this function + /// returns `null`. + /// + /// `assetId` is the [AssetId] from which `node` was read, unless `node` was + /// read from a part file, in which case `assetId` should be the [AssetId] of + /// the parent file. + Future readDirectiveMetadata( + ClassDeclaration node, AssetId assetId) { + _visitor.reset(assetId); + node.accept(_visitor); + if (!_visitor.hasMetadata) { + return new Future.value(null); + } else { + final metadata = _visitor.createMetadata(); + if (!metadata.isComponent) return new Future.value(metadata); + return _templateCompiler.normalizeDirectiveMetadata(metadata); } - // TODO(kegluneq): @keertip, can we expose this as a warning? - assert(byNameMatch == byResolvedAst); - } - return byNameMatch; -} - -class _ReflectionInfoVisitor extends _DirectiveMetadataVisitor { - // TODO(kegluneq): Create a more robust check that this is a real - // `ReflectionInfo` instantiation. - static bool _isReflectionInfo(InstanceCreationExpression node) { - var name = node.constructorName.type.name; - name = name is PrefixedIdentifier ? name.identifier : name; - return '$name' == 'ReflectionInfo'; - } - - @override - Object visitInstanceCreationExpression(InstanceCreationExpression node) { - if (_isReflectionInfo(node)) { - // NOTE(kegluneq): This is very tightly coupled with the `Reflector` - // implementation. Clean this up with a better intermediate representation - // for .ng_deps.dart files. - var reflectionInfoArgs = node.argumentList.arguments; - if (reflectionInfoArgs.length > 0) { - // Process annotations to determine information specified via - // `Component` and `Directive` parameters. - reflectionInfoArgs[0].accept(this); - if (_hasMeta && reflectionInfoArgs.length > 3) { - // Process interfaces to determine which lifecycle events we need to - // react to for this `Directive`. - _processInterfaces(reflectionInfoArgs[3]); - } - } - return null; - } - var directiveType = _getDirectiveType( - '${node.constructorName.type.name}', node.staticElement); - if (directiveType >= 0) { - if (_hasMeta) { - throw new FormatException( - 'Only one Directive is allowed per class. ' - 'Found "$node" but already processed "$meta".', - '$node' /* source */); - } - _initializeMetadata(directiveType); - super.visitInstanceCreationExpression(node); - } - // Annotation we do not recognize - no need to visit. - return null; - } - - void _processInterfaces(Expression lifecycleValue) { - _checkMeta(); - if (lifecycleValue is! ListLiteral) { - throw new FormatException( - 'Angular 2 expects a List but could not understand the value for interfaces. ' - '$lifecycleValue'); - } - ListLiteral l = lifecycleValue; - _populateLifecycle(l.elements.map((s) => s.toSource().split('.').last)); } } -class _DeclarationVisitor extends _DirectiveMetadataVisitor { - @override - Object visitClassDeclaration(ClassDeclaration node) { - node.metadata.accept(this); - if (this._hasMeta) { - if (node.implementsClause != null && - node.implementsClause.interfaces != null) { - _populateLifecycle(node.implementsClause.interfaces - .map((s) => s.toSource().split('.').last)); - } - } - return null; +/// Visitor that attempts to evaluate a provided `node` syntactically. +/// +/// This lack of semantic information means it cannot do much - for +/// example, it can create a list from a list literal and combine adjacent +/// strings but cannot determine that an identifier is a constant string, +/// even if that identifier is defined in the same [CompilationUnit]. +/// +/// Returns the result of evaluation or [ConstantEvaluator.NOT_A_CONSTANT] +/// where appropriate. +final ConstantEvaluator _evaluator = new ConstantEvaluator(); + +/// Evaluates the [Map] represented by `expression` and adds all `key`, +/// `value` pairs to `map`. If `expression` does not evaluate to a [Map], +/// throws a descriptive [FormatException]. +void _populateMap(Expression expression, Map map, String propertyName) { + var evaluated = expression.accept(_evaluator); + if (evaluated is! Map) { + throw new FormatException( + 'Angular 2 expects a Map but could not understand the value for ' + '$propertyName.', + '$expression' /* source */); } + evaluated.forEach((key, value) { + if (value != null) { + map[key] = '$value'; + } + }); } -/// Visitor responsible for processing [Directive] code into a -/// [RenderDirectiveMetadata] object. +/// Evaluates the [List] represented by `expression` and adds all values, +/// to `list`. If `expression` does not evaluate to a [List], throws a +/// descriptive [FormatException]. +void _populateList( + Expression expression, List list, String propertyName) { + var evaluated = expression.accept(_evaluator); + if (evaluated is! List) { + throw new FormatException( + 'Angular 2 expects a List but could not understand the value for ' + '$propertyName.', + '$expression' /* source */); + } + list.addAll(evaluated.map((e) => e.toString())); +} + +/// Evaluates `node` and expects that the result will be a string. If not, +/// throws a [FormatException]. +String _expressionToString(Expression node, String nodeDescription) { + var value = node.accept(_evaluator); + if (value is! String) { + throw new FormatException( + 'Angular 2 could not understand the value ' + 'in $nodeDescription.', + '$node' /* source */); + } + return value; +} + +/// Visitor responsible for processing a [Directive] annotated +/// [ClassDeclaration] and creating a [CompileDirectiveMetadata] object. class _DirectiveMetadataVisitor extends Object with RecursiveAstVisitor { - bool get _hasMeta => _type != null; + /// Tests [Annotation]s to determine if they deifne a [Directive], + /// [Component], [View], or none of these. + final AnnotationMatcher _annotationMatcher; - // Annotation fields - num _type; - String _selector; - bool _compileChildren; - List _inputs; - Map _host; - List _readAttributes; - String _exportAs; - bool _callOnDestroy; - bool _callOnChange; - bool _callDoCheck; - bool _callOnInit; - bool _callAfterContentInit; - bool _callAfterContentChecked; - bool _callAfterViewInit; - bool _callAfterViewChecked; - ChangeDetectionStrategy _changeDetection; - List _outputs; + final _LifecycleHookVisitor _lifecycleVisitor; - final ConstantEvaluator _evaluator = new ConstantEvaluator(); + /// The [AssetId] we are currently processing. + AssetId _assetId; - void _initializeMetadata(num directiveType) { - assert(directiveType >= 0); - - _type = directiveType; - _selector = ''; - _compileChildren = true; - _inputs = []; - _host = {}; - _readAttributes = []; - _exportAs = null; - _callOnDestroy = false; - _callOnChange = false; - _callDoCheck = false; - _callOnInit = false; - _callAfterContentInit = false; - _callAfterContentChecked = false; - _callAfterViewInit = false; - _callAfterViewChecked = false; - _changeDetection = null; - _outputs = []; + _DirectiveMetadataVisitor(this._annotationMatcher, this._lifecycleVisitor) { + reset(null); } - RenderDirectiveMetadata get meta => RenderDirectiveMetadata.create( + /// Whether the visitor has found a [Component] or [Directive] annotation + /// since the last call to `reset`. + bool _hasMetadata = false; + + // Annotation fields + CompileTypeMetadata _type; + bool _isComponent; + String _selector; + String _exportAs; + ChangeDetectionStrategy _changeDetection; + List _properties; + List _events; + Map _host; + List _lifecycleHooks; + CompileTemplateMetadata _template; + + void reset(AssetId assetId) { + _lifecycleVisitor.reset(assetId); + _assetId = assetId; + + _type = null; + _isComponent = false; + _hasMetadata = false; + _selector = ''; + _exportAs = null; + _changeDetection = ChangeDetectionStrategy.Default; + _properties = []; + _events = []; + _host = {}; + _lifecycleHooks = null; + _template = null; + } + + bool get hasMetadata => _hasMetadata; + + CompileDirectiveMetadata createMetadata() => CompileDirectiveMetadata.create( type: _type, + isComponent: _isComponent, + dynamicLoadable: true, // NOTE(kegluneq): For future optimization. selector: _selector, - compileChildren: _compileChildren, - inputs: _inputs, - host: _host, - readAttributes: _readAttributes, exportAs: _exportAs, - callOnDestroy: _callOnDestroy, - callOnChanges: _callOnChange, - callDoCheck: _callDoCheck, - callOnInit: _callOnInit, - callAfterContentInit: _callAfterContentInit, - callAfterContentChecked: _callAfterContentChecked, - callAfterViewInit: _callAfterViewInit, - callAfterViewChecked: _callAfterViewChecked, changeDetection: _changeDetection, - outputs: _outputs); + properties: _properties, + events: _events, + host: _host, + lifecycleHooks: _lifecycleHooks, + template: _template); @override Object visitAnnotation(Annotation node) { - var directiveType = _getDirectiveType('${node.name}', node.element); - if (directiveType >= 0) { - if (_hasMeta) { + var isComponent = _annotationMatcher.isComponent(node, _assetId); + var isDirective = _annotationMatcher.isDirective(node, _assetId); + if (isDirective) { + if (_hasMetadata) { throw new FormatException( 'Only one Directive is allowed per class. ' - 'Found "$node" but already processed "$meta".', + 'Found unexpected "$node".', '$node' /* source */); } - _initializeMetadata(directiveType); + _isComponent = isComponent; + _hasMetadata = true; super.visitAnnotation(node); + } else if (_annotationMatcher.isView(node, _assetId)) { + if (_template != null) { + throw new FormatException( + 'Only one View is allowed per class. ' + 'Found unexpected "$node".', + '$node' /* source */); + } + _template = new _CompileTemplateMetadataVisitor().visitAnnotation(node); } + // Annotation we do not recognize - no need to visit. return null; } + @override + Object visitClassDeclaration(ClassDeclaration node) { + node.metadata.accept(this); + if (this._hasMetadata) { + _type = new CompileTypeMetadata( + moduleUrl: 'asset:${_assetId.package}/${_assetId.path}', + name: node.name.toString(), + runtime: null // Intentionally `null`, cannot be provided here. + ); + _lifecycleHooks = node.implementsClause != null + ? node.implementsClause.accept(_lifecycleVisitor) + : const []; + } + return null; + } + @override Object visitNamedExpression(NamedExpression node) { // TODO(kegluneq): Remove this limitation. @@ -220,10 +232,7 @@ class _DirectiveMetadataVisitor extends Object case 'selector': _populateSelector(node.expression); break; - case 'compileChildren': - _populateCompileChildren(node.expression); - break; - case 'inputs': + case 'properties': _populateProperties(node.expression); break; case 'host': @@ -235,84 +244,29 @@ class _DirectiveMetadataVisitor extends Object case 'changeDetection': _populateChangeDetection(node.expression); break; - case 'outputs': + case 'events': _populateEvents(node.expression); break; } return null; } - String _expressionToString(Expression node, String nodeDescription) { - var value = node.accept(_evaluator); - if (value is! String) { - throw new FormatException( - 'Angular 2 could not understand the value ' - 'in $nodeDescription.', - '$node' /* source */); - } - return value; - } - void _populateSelector(Expression selectorValue) { _checkMeta(); _selector = _expressionToString(selectorValue, 'Directive#selector'); } void _checkMeta() { - if (!_hasMeta) { + if (!_hasMetadata) { throw new ArgumentError( 'Incorrect value passed to readDirectiveMetadata. ' - 'Expected types are ClassDeclaration and InstanceCreationExpression'); + 'Expected type is ClassDeclaration'); } } - void _populateCompileChildren(Expression compileChildrenValue) { - _checkMeta(); - var evaluated = compileChildrenValue.accept(_evaluator); - if (evaluated is! bool) { - throw new FormatException( - 'Angular 2 expects a bool but could not understand the value for ' - 'Directive#compileChildren.', - '$compileChildrenValue' /* source */); - } - _compileChildren = evaluated; - } - - /// Evaluates the [Map] represented by `expression` and adds all `key`, - /// `value` pairs to `map`. If `expression` does not evaluate to a [Map], - /// throws a descriptive [FormatException]. - void _populateMap(Expression expression, Map map, String propertyName) { - var evaluated = expression.accept(_evaluator); - if (evaluated is! Map) { - throw new FormatException( - 'Angular 2 expects a Map but could not understand the value for ' - '$propertyName.', - '$expression' /* source */); - } - evaluated.forEach((key, value) { - if (value != null) { - map[key] = '$value'; - } - }); - } - - /// Evaluates the [List] represented by `expression` and adds all values, - /// to `list`. If `expression` does not evaluate to a [List], throws a - /// descriptive [FormatException]. - void _populateList(Expression expression, List list, String propertyName) { - var evaluated = expression.accept(_evaluator); - if (evaluated is! List) { - throw new FormatException( - 'Angular 2 expects a List but could not understand the value for ' - '$propertyName.', - '$expression' /* source */); - } - list.addAll(evaluated); - } - void _populateProperties(Expression propertiesValue) { _checkMeta(); - _populateList(propertiesValue, _inputs, 'Directive#properties'); + _populateList(propertiesValue, _properties, 'Directive#properties'); } void _populateHost(Expression hostValue) { @@ -325,32 +279,138 @@ class _DirectiveMetadataVisitor extends Object _exportAs = _expressionToString(exportAsValue, 'Directive#exportAs'); } - void _populateLifecycle(Iterable lifecycleInterfaceNames) { - _checkMeta(); - _callOnDestroy = lifecycleInterfaceNames.contains("OnDestroy"); - _callOnChange = lifecycleInterfaceNames.contains("OnChanges"); - _callDoCheck = lifecycleInterfaceNames.contains("DoCheck"); - _callOnInit = lifecycleInterfaceNames.contains("OnInit"); - _callAfterContentInit = - lifecycleInterfaceNames.contains("AfterContentInit"); - _callAfterContentChecked = - lifecycleInterfaceNames.contains("AfterContentChecked"); - _callAfterViewInit = lifecycleInterfaceNames.contains("AfterViewInit"); - _callAfterViewChecked = - lifecycleInterfaceNames.contains("AfterViewChecked"); - } - void _populateEvents(Expression eventsValue) { _checkMeta(); - _populateList(eventsValue, _outputs, 'Directive#events'); + _populateList(eventsValue, _events, 'Directive#events'); } void _populateChangeDetection(Expression value) { _checkMeta(); - _changeDetection = changeDetectionStrategies[value.toSource()]; + _changeDetection = _changeDetectionStrategies[value.toSource()]; + } + + static final Map _changeDetectionStrategies = + new Map.fromIterable(ChangeDetectionStrategy.values, + key: (v) => v.toString()); +} + +/// Visitor responsible for parsing an [ImplementsClause] and returning a +/// [List] that the [Directive] subscribes to. +class _LifecycleHookVisitor extends SimpleAstVisitor> { + /// Tests [Identifier]s of implemented interfaces to determine if they + /// correspond to [LifecycleHooks] values. + final InterfaceMatcher _ifaceMatcher; + + /// The [AssetId] we are currently processing. + AssetId _assetId; + + _LifecycleHookVisitor(this._ifaceMatcher); + + void reset(AssetId assetId) { + _assetId = assetId; + } + + @override + List visitImplementsClause(ImplementsClause node) { + if (node == null || node.interfaces == null) return const []; + + return node.interfaces.map((TypeName ifaceTypeName) { + var id = ifaceTypeName.name; + if (_ifaceMatcher.isAfterContentChecked(id, _assetId)) { + return LifecycleHooks.AfterContentChecked; + } else if (_ifaceMatcher.isAfterContentInit(id, _assetId)) { + return LifecycleHooks.AfterContentInit; + } else if (_ifaceMatcher.isAfterViewChecked(id, _assetId)) { + return LifecycleHooks.AfterViewChecked; + } else if (_ifaceMatcher.isAfterViewInit(id, _assetId)) { + return LifecycleHooks.AfterViewInit; + } else if (_ifaceMatcher.isDoCheck(id, _assetId)) { + return LifecycleHooks.DoCheck; + } else if (_ifaceMatcher.isOnChange(id, _assetId)) { + return LifecycleHooks.OnChanges; + } else if (_ifaceMatcher.isOnDestroy(id, _assetId)) { + return LifecycleHooks.OnDestroy; + } else if (_ifaceMatcher.isOnInit(id, _assetId)) { + return LifecycleHooks.OnInit; + } + return null; + }).where((e) => e != null).toList(growable: false); } } -final Map changeDetectionStrategies = - new Map.fromIterable(ChangeDetectionStrategy.values, - key: (v) => v.toString()); +/// Visitor responsible for parsing a @View [Annotation] and producing a +/// [CompileTemplateMetadata]. +class _CompileTemplateMetadataVisitor + extends RecursiveAstVisitor { + ViewEncapsulation _encapsulation = ViewEncapsulation.Emulated; + String _template = null; + String _templateUrl = null; + List _styles = null; + List _styleUrls = null; + + @override + CompileTemplateMetadata visitAnnotation(Annotation node) { + super.visitAnnotation(node); + + return new CompileTemplateMetadata( + encapsulation: _encapsulation, + template: _template, + templateUrl: _templateUrl, + styles: _styles, + styleUrls: _styleUrls); + } + + @override + CompileTemplateMetadata visitNamedExpression(NamedExpression node) { + // TODO(kegluneq): Remove this limitation. + if (node.name is! Label || node.name.label is! SimpleIdentifier) { + throw new FormatException( + 'Angular 2 currently only supports simple identifiers in directives.', + '$node' /* source */); + } + var keyString = '${node.name.label}'; + switch (keyString) { + case 'encapsulation': + _populateEncapsulation(node.expression); + break; + case 'template': + _populateTemplate(node.expression); + break; + case 'templateUrl': + _populateTemplateUrl(node.expression); + break; + case 'styles': + _populateStyles(node.expression); + break; + case 'styleUrls': + _populateStyleUrls(node.expression); + break; + } + return null; + } + + void _populateTemplate(Expression value) { + _template = _expressionToString(value, 'View#template'); + } + + void _populateTemplateUrl(Expression value) { + _templateUrl = _expressionToString(value, 'View#templateUrl'); + } + + void _populateStyles(Expression value) { + _styles = []; + _populateList(value, _styles, 'View#styles'); + } + + void _populateStyleUrls(Expression value) { + _styleUrls = []; + _populateList(value, _styleUrls, 'View#styleUrls'); + } + + void _populateEncapsulation(Expression value) { + _encapsulation = _viewEncapsulationMap[value.toSource()]; + } + + static final _viewEncapsulationMap = + new Map.fromIterable(ViewEncapsulation.values, key: (v) => v.toString()); +} diff --git a/modules_dart/transform/lib/src/transform/common/model/ng_deps_model.pb.dart b/modules_dart/transform/lib/src/transform/common/model/ng_deps_model.pb.dart index 8211c181ef..556bb8b132 100644 --- a/modules_dart/transform/lib/src/transform/common/model/ng_deps_model.pb.dart +++ b/modules_dart/transform/lib/src/transform/common/model/ng_deps_model.pb.dart @@ -11,14 +11,21 @@ class NgDepsModel extends GeneratedMessage { static final BuilderInfo _i = new BuilderInfo('NgDepsModel') ..a(1, 'libraryUri', PbFieldType.OS) ..p(2, 'partUris', PbFieldType.PS) - ..pp(3, 'imports', PbFieldType.PM, ImportModel.$checkItem, ImportModel.create) - ..pp(4, 'exports', PbFieldType.PM, ExportModel.$checkItem, ExportModel.create) - ..pp(5, 'reflectables', PbFieldType.PM, ReflectionInfoModel.$checkItem, ReflectionInfoModel.create) - ; + ..pp(3, 'imports', PbFieldType.PM, ImportModel.$checkItem, + ImportModel.create) + ..pp(4, 'exports', PbFieldType.PM, ExportModel.$checkItem, + ExportModel.create) + ..pp(5, 'reflectables', PbFieldType.PM, ReflectionInfoModel.$checkItem, + ReflectionInfoModel.create) + ..a(6, 'sourceFile', PbFieldType.OS); NgDepsModel() : super(); - NgDepsModel.fromBuffer(List i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromBuffer(i, r); - NgDepsModel.fromJson(String i, [ExtensionRegistry r = ExtensionRegistry.EMPTY]) : super.fromJson(i, r); + NgDepsModel.fromBuffer(List i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) + : super.fromBuffer(i, r); + NgDepsModel.fromJson(String i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) + : super.fromJson(i, r); NgDepsModel clone() => new NgDepsModel()..mergeFromMessage(this); BuilderInfo get info_ => _i; static NgDepsModel create() => new NgDepsModel(); @@ -27,13 +34,17 @@ class NgDepsModel extends GeneratedMessage { if (_defaultInstance == null) _defaultInstance = new _ReadonlyNgDepsModel(); return _defaultInstance; } + static NgDepsModel _defaultInstance; static void $checkItem(NgDepsModel v) { - if (v is !NgDepsModel) checkItemFailed(v, 'NgDepsModel'); + if (v is! NgDepsModel) checkItemFailed(v, 'NgDepsModel'); } String get libraryUri => getField(1); - void set libraryUri(String v) { setField(1, v); } + void set libraryUri(String v) { + setField(1, v); + } + bool hasLibraryUri() => hasField(1); void clearLibraryUri() => clearField(1); @@ -44,6 +55,14 @@ class NgDepsModel extends GeneratedMessage { List get exports => getField(4); List get reflectables => getField(5); + + String get sourceFile => getField(6); + void set sourceFile(String v) { + setField(6, v); + } + + bool hasSourceFile() => hasField(6); + void clearSourceFile() => clearField(6); } class _ReadonlyNgDepsModel extends NgDepsModel with ReadonlyMessageMixin {} @@ -53,15 +72,34 @@ const NgDepsModel$json = const { '2': const [ const {'1': 'library_uri', '3': 1, '4': 1, '5': 9}, const {'1': 'part_uris', '3': 2, '4': 3, '5': 9}, - const {'1': 'imports', '3': 3, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.ImportModel'}, - const {'1': 'exports', '3': 4, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.ExportModel'}, - const {'1': 'reflectables', '3': 5, '4': 3, '5': 11, '6': '.angular2.src.transform.common.model.proto.ReflectionInfoModel'}, + const { + '1': 'imports', + '3': 3, + '4': 3, + '5': 11, + '6': '.angular2.src.transform.common.model.proto.ImportModel' + }, + const { + '1': 'exports', + '3': 4, + '4': 3, + '5': 11, + '6': '.angular2.src.transform.common.model.proto.ExportModel' + }, + const { + '1': 'reflectables', + '3': 5, + '4': 3, + '5': 11, + '6': '.angular2.src.transform.common.model.proto.ReflectionInfoModel' + }, + const {'1': 'source_file', '3': 6, '4': 1, '5': 9}, ], }; /** * Generated with: - * ng_deps_model.proto (c84f449fc55ef46e38a652f65449c6645b9fe6cb) + * ng_deps_model.proto (83fe43a087fdd0a7ebee360cd6b669570df4d216) * libprotoc 2.5.0 * dart-protoc-plugin (cc35f743de982a4916588b9c505dd21c7fe87d17) */ diff --git a/modules_dart/transform/lib/src/transform/common/model/ng_deps_model.proto b/modules_dart/transform/lib/src/transform/common/model/ng_deps_model.proto index 3b7d5350f8..0efe0daaec 100644 --- a/modules_dart/transform/lib/src/transform/common/model/ng_deps_model.proto +++ b/modules_dart/transform/lib/src/transform/common/model/ng_deps_model.proto @@ -14,5 +14,10 @@ message NgDepsModel { repeated ExportModel exports = 4; + // All classes in `source_file` marked with @Injectable or a known subclass. repeated ReflectionInfoModel reflectables = 5; + + // The basename of the file from which the ng_deps were generated. + // Example: component.dart + optional string source_file = 6; } diff --git a/modules_dart/transform/lib/src/transform/common/names.dart b/modules_dart/transform/lib/src/transform/common/names.dart index 0d410f4198..09efe11320 100644 --- a/modules_dart/transform/lib/src/transform/common/names.dart +++ b/modules_dart/transform/lib/src/transform/common/names.dart @@ -4,12 +4,13 @@ const BOOTSTRAP_NAME = 'bootstrap'; const SETUP_METHOD_NAME = 'initReflector'; const REFLECTOR_VAR_NAME = 'reflector'; const TRANSFORM_DYNAMIC_MODE = 'transform_dynamic'; +const CSS_EXTENSION = '.css'; +const SHIMMED_STYLESHEET_EXTENSION = '.css.shim.dart'; +const NON_SHIMMED_STYLESHEET_EXTENSION = '.css.dart'; const DEPS_EXTENSION = '.ng_deps.dart'; const DEPS_JSON_EXTENSION = '.ng_deps.json'; const META_EXTENSION = '.ng_meta.json'; -// TODO(sigmund): consider merging into .ng_meta by generating local metadata -// upfront (rather than extracting it from ng_deps). -const ALIAS_EXTENSION = '.aliases.json'; +const TEMPLATE_EXTENSION = '.template.dart'; const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities'; const REFLECTOR_IMPORT = 'package:angular2/src/core/reflection/reflection.dart'; const REFLECTOR_PREFIX = '_ngRef'; @@ -18,20 +19,40 @@ const REGISTER_GETTERS_METHOD_NAME = 'registerGetters'; const REGISTER_SETTERS_METHOD_NAME = 'registerSetters'; const REGISTER_METHODS_METHOD_NAME = 'registerMethods'; +/// Note that due to the implementation of `_toExtension`, ordering is +/// important. For example, putting '.dart' first in this list will cause +/// incorrect behavior. +const ALL_EXTENSIONS = const [ + DEPS_EXTENSION, + DEPS_JSON_EXTENSION, + META_EXTENSION, + TEMPLATE_EXTENSION, + '.dart' +]; + /// Returns `uri` with its extension updated to [META_EXTENSION]. String toMetaExtension(String uri) => - _toExtension(uri, const [DEPS_EXTENSION, DEPS_JSON_EXTENSION, '.dart'], META_EXTENSION); + _toExtension(uri, ALL_EXTENSIONS, META_EXTENSION); /// Returns `uri` with its extension updated to [DEPS_EXTENSION]. String toDepsExtension(String uri) => - _toExtension(uri, const [META_EXTENSION, DEPS_JSON_EXTENSION, '.dart'], DEPS_EXTENSION); - -/// Returns `uri` with its extension updated to [ALIAS_EXTENSION]. -String toAliasExtension(String uri) => - _toExtension(uri, const [DEPS_EXTENSION, '.dart'], ALIAS_EXTENSION); + _toExtension(uri, ALL_EXTENSIONS, DEPS_EXTENSION); +/// Returns `uri` with its extension updated to [DEPS_JSON_EXTENSION]. String toJsonExtension(String uri) => - _toExtension(uri, const [DEPS_EXTENSION, '.dart'], DEPS_JSON_EXTENSION); + _toExtension(uri, ALL_EXTENSIONS, DEPS_JSON_EXTENSION); + +/// Returns `uri` with its extension updated to [TEMPLATES_EXTENSION]. +String toTemplateExtension(String uri) => + _toExtension(uri, ALL_EXTENSIONS, TEMPLATE_EXTENSION); + +/// Returns `uri` with its extension updated to [SHIMMED_STYLESHEET_EXTENSION]. +String toShimmedStylesheetExtension(String uri) => + _toExtension(uri, const [CSS_EXTENSION], SHIMMED_STYLESHEET_EXTENSION); + +/// Returns `uri` with its extension updated to [NON_SHIMMED_STYLESHEET_EXTENSION]. +String toNonShimmedStylesheetExtension(String uri) => + _toExtension(uri, const [CSS_EXTENSION], NON_SHIMMED_STYLESHEET_EXTENSION); /// Returns `uri` with its extension updated to `toExtension` if its /// extension is currently in `fromExtension`. diff --git a/modules_dart/transform/lib/src/transform/common/ng_compiler.dart b/modules_dart/transform/lib/src/transform/common/ng_compiler.dart new file mode 100644 index 0000000000..769cfd89ce --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/ng_compiler.dart @@ -0,0 +1,40 @@ +library angular2.transform.template_compiler.xhr_impl; + +import 'package:angular2/src/compiler/command_compiler.dart'; +import 'package:angular2/src/compiler/html_parser.dart'; +import 'package:angular2/src/compiler/style_compiler.dart'; +import 'package:angular2/src/compiler/template_compiler.dart'; +import 'package:angular2/src/compiler/template_normalizer.dart'; +import 'package:angular2/src/compiler/template_parser.dart'; +import 'package:angular2/src/core/change_detection/parser/lexer.dart' as ng; +import 'package:angular2/src/core/change_detection/parser/parser.dart' as ng; +import 'package:angular2/src/core/render/dom/schema/dom_element_schema_registry.dart'; +import 'package:angular2/src/transform/common/asset_reader.dart'; +import 'package:angular2/src/core/change_detection/interfaces.dart'; +import 'package:angular2/src/compiler/change_detector_compiler.dart'; + +import 'xhr_impl.dart'; +import 'url_resolver.dart'; + +TemplateCompiler createTemplateCompiler(AssetReader reader, + {ChangeDetectorGenConfig changeDetectionConfig}) { + var _xhr = new XhrImpl(reader); + var _htmlParser = new HtmlParser(); + var _urlResolver = const TransformerUrlResolver(); + + var templateParser = new TemplateParser(new ng.Parser(new ng.Lexer()), + new DomElementSchemaRegistry(), _htmlParser); + + var cdCompiler = changeDetectionConfig != null + ? new ChangeDetectionCompiler(changeDetectionConfig) + : null; + + return new TemplateCompiler( + null /* RuntimeMetadataResolver */, + new TemplateNormalizer(_xhr, _urlResolver, _htmlParser), + templateParser, + new StyleCompiler(_xhr, _urlResolver), + new CommandCompiler(), + cdCompiler, + null /* appId */); +} diff --git a/modules_dart/transform/lib/src/transform/common/ng_meta.dart b/modules_dart/transform/lib/src/transform/common/ng_meta.dart index 101176781f..11880e353b 100644 --- a/modules_dart/transform/lib/src/transform/common/ng_meta.dart +++ b/modules_dart/transform/lib/src/transform/common/ng_meta.dart @@ -1,7 +1,6 @@ library angular2.transform.common.ng_meta; -import 'package:angular2/src/core/render/api.dart'; -import 'convert.dart'; +import 'package:angular2/src/compiler/directive_metadata.dart'; import 'logging.dart'; /// Metadata about directives and directive aliases. @@ -20,37 +19,47 @@ import 'logging.dart'; /// easier. class NgMeta { /// Directive metadata for each type annotated as a directive. - final Map types; + final Map types; /// List of other types and names associated with a given name. final Map> aliases; - NgMeta(this.types, this.aliases); + /// TODO(kegluneq): Once merged with NgDepsModel, use its exports. + final List exports; - NgMeta.empty() : this({}, {}); + NgMeta(this.types, this.aliases, this.exports); - bool get isEmpty => types.isEmpty && aliases.isEmpty; + NgMeta.empty() : this({}, {}, []); + + bool get isEmpty => types.isEmpty && aliases.isEmpty && exports.isEmpty; /// Parse from the serialized form produced by [toJson]. factory NgMeta.fromJson(Map json) { + var exports = []; var types = {}; var aliases = {}; for (var key in json.keys) { - var entry = json[key]; - if (entry['kind'] == 'type') { - types[key] = directiveMetadataFromMap(entry['value']); - } else if (entry['kind'] == 'alias') { - aliases[key] = entry['value']; + if (key == '__exports__') { + exports = json[key]; + } else { + var entry = json[key]; + if (entry['kind'] == 'type') { + types[key] = CompileDirectiveMetadata.fromJson(entry['value']); + } else if (entry['kind'] == 'alias') { + aliases[key] = entry['value']; + } } } - return new NgMeta(types, aliases); + return new NgMeta(types, aliases, exports); } /// Serialized representation of this instance. Map toJson() { var result = {}; + result['__exports__'] = exports; + types.forEach((k, v) { - result[k] = {'kind': 'type', 'value': directiveMetadataToMap(v)}; + result[k] = {'kind': 'type', 'value': v.toJson()}; }); aliases.forEach((k, v) { @@ -60,14 +69,15 @@ class NgMeta { } /// Merge into this instance all information from [other]. + /// This does not include `exports`. void addAll(NgMeta other) { types.addAll(other.types); aliases.addAll(other.aliases); } /// Returns the metadata for every type associated with the given [alias]. - List flatten(String alias) { - var result = []; + List flatten(String alias) { + var result = []; var seen = new Set(); helper(name) { if (!seen.add(name)) { diff --git a/modules_dart/transform/lib/src/transform/common/options.dart b/modules_dart/transform/lib/src/transform/common/options.dart index ffdb833fbc..f02f0ce32c 100644 --- a/modules_dart/transform/lib/src/transform/common/options.dart +++ b/modules_dart/transform/lib/src/transform/common/options.dart @@ -11,12 +11,15 @@ const DEFAULT_OPTIMIZATION_PHASES = 5; const CUSTOM_ANNOTATIONS_PARAM = 'custom_annotations'; const ENTRY_POINT_PARAM = 'entry_points'; const FORMAT_CODE_PARAM = 'format_code'; +// TODO(kegluenq): Remove this after 30 Oct (i/4433). const GENERATE_CHANGE_DETECTORS_PARAM = 'generate_change_detectors'; const REFLECT_PROPERTIES_AS_ATTRIBUTES = 'reflectPropertiesAsAttributes'; const INIT_REFLECTOR_PARAM = 'init_reflector'; +// TODO(kegluenq): Remove this after 30 Oct (i/4433). const INLINE_VIEWS_PARAM = 'inline_views'; const MIRROR_MODE_PARAM = 'mirror_mode'; const OPTIMIZATION_PHASES_PARAM = 'optimization_phases'; +const PRECOMPILE_PARAM = 'precompile'; const REFLECTION_ENTRY_POINT_PARAM = 'reflection_entry_points'; /// Provides information necessary to transform an Angular2 app. @@ -35,15 +38,9 @@ class TransformerOptions { /// Whether to generate calls to our generated `initReflector` code final bool initReflector; - /// Whether to inline html/css urls into the View directive - final bool inlineViews; - /// The [AnnotationMatcher] which is used to identify angular annotations. final AnnotationMatcher annotationMatcher; - /// Whether to create change detector classes for discovered `@View`s. - final bool generateChangeDetectors; - final bool reflectPropertiesAsAttributes; /// The number of phases to spend optimizing output size. @@ -68,9 +65,7 @@ class TransformerOptions { this.initReflector, this.annotationMatcher, this.optimizationPhases, - {this.generateChangeDetectors, - this.reflectPropertiesAsAttributes, - this.inlineViews, + {this.reflectPropertiesAsAttributes, this.formatCode}); factory TransformerOptions(List entryPoints, @@ -80,7 +75,6 @@ class TransformerOptions { List customAnnotationDescriptors: const [], int optimizationPhases: DEFAULT_OPTIMIZATION_PHASES, bool inlineViews: true, - bool generateChangeDetectors: true, bool reflectPropertiesAsAttributes: true, bool formatCode: false}) { var annotationMatcher = new AnnotationMatcher() @@ -97,9 +91,7 @@ class TransformerOptions { initReflector, annotationMatcher, optimizationPhases, - generateChangeDetectors: generateChangeDetectors, reflectPropertiesAsAttributes: reflectPropertiesAsAttributes, - inlineViews: inlineViews, formatCode: formatCode); } } diff --git a/modules_dart/transform/lib/src/transform/common/options_reader.dart b/modules_dart/transform/lib/src/transform/common/options_reader.dart index 28f125d1c2..5ed060beb5 100644 --- a/modules_dart/transform/lib/src/transform/common/options_reader.dart +++ b/modules_dart/transform/lib/src/transform/common/options_reader.dart @@ -11,9 +11,6 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) { var entryPoints = _readFileList(config, ENTRY_POINT_PARAM); var initReflector = _readBool(config, INIT_REFLECTOR_PARAM, defaultValue: true); - var inlineViews = _readBool(config, INLINE_VIEWS_PARAM, defaultValue: true); - var generateChangeDetectors = - _readBool(config, GENERATE_CHANGE_DETECTORS_PARAM, defaultValue: true); var reflectPropertiesAsAttributes = _readBool(config, REFLECT_PROPERTIES_AS_ATTRIBUTES, defaultValue: false); var formatCode = _readBool(config, FORMAT_CODE_PARAM, defaultValue: false); @@ -37,10 +34,8 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) { modeName: settings.mode.name, mirrorMode: mirrorMode, initReflector: initReflector, - inlineViews: inlineViews, customAnnotationDescriptors: _readCustomAnnotations(config), optimizationPhases: optimizationPhases, - generateChangeDetectors: generateChangeDetectors, reflectPropertiesAsAttributes: reflectPropertiesAsAttributes, formatCode: formatCode); } @@ -136,4 +131,14 @@ void _warnDeprecated(Map config) { print('${REFLECTION_ENTRY_POINT_PARAM} is no longer necessary for ' 'Angular 2 apps. Please remove it from your pubspec.'); } + if (config.containsKey(GENERATE_CHANGE_DETECTORS_PARAM)) { + print('${GENERATE_CHANGE_DETECTORS_PARAM} is no longer necessary for ' + 'Angular 2 apps. Please remove it from your pubspec.'); + } + if (config.containsKey(INLINE_VIEWS_PARAM)) { + print('Parameter "${INLINE_VIEWS_PARAM}" no longer has any effect on the ' + 'Angular2 transformer. Inlining of views is only needed for tests that ' + 'manipulate component metadata. For this purpose, use transformer ' + 'angular2/src/transform/inliner_for_test.'); + } } diff --git a/modules_dart/transform/lib/src/transform/common/registered_type.dart b/modules_dart/transform/lib/src/transform/common/registered_type.dart index cd37d6a0f3..1573e4b3db 100644 --- a/modules_dart/transform/lib/src/transform/common/registered_type.dart +++ b/modules_dart/transform/lib/src/transform/common/registered_type.dart @@ -2,8 +2,6 @@ library angular2.transform.common.registered_type; import 'package:analyzer/analyzer.dart'; import 'package:angular2/src/core/render/api.dart'; -import 'package:angular2/src/transform/common/directive_metadata_reader.dart'; -import 'package:angular2/src/transform/common/logging.dart'; import 'package:angular2/src/transform/common/names.dart'; /// A call to `Reflector#registerType` generated by `DirectiveProcessor`. @@ -29,8 +27,6 @@ class RegisteredType { /// The property metadata registered. final Expression propMetadata; - RenderDirectiveMetadata _directiveMetadata = null; - RegisteredType._( this.typeName, this.registerMethod, @@ -49,20 +45,7 @@ class RegisteredType { visitor.factoryFn, visitor.parameters, visitor.annotations, visitor.propMetadata); } - RenderDirectiveMetadata get directiveMetadata { - if (_directiveMetadata == null) { - try { - /// TODO(kegluneq): Allow passing a lifecycle interface matcher. - _directiveMetadata = readDirectiveMetadata(reflectionInfoCreate); - if (_directiveMetadata != null) { - _directiveMetadata.id = '$typeName'; - } - } on FormatException catch (ex) { - logger.error(ex.message); - } - } - return _directiveMetadata; - } + RenderDirectiveMetadata get directiveMetadata => null; } class _ParseRegisterTypeVisitor extends Object diff --git a/modules_dart/transform/lib/src/transform/common/url_resolver.dart b/modules_dart/transform/lib/src/transform/common/url_resolver.dart new file mode 100644 index 0000000000..b5497a293a --- /dev/null +++ b/modules_dart/transform/lib/src/transform/common/url_resolver.dart @@ -0,0 +1,57 @@ +library angular2.transform.template_compiler.url_resolver; + +import 'package:angular2/src/core/services/url_resolver.dart'; + +class TransformerUrlResolver implements UrlResolver { + const TransformerUrlResolver(); + + @override + String resolve(String baseUrl, String url) { + Uri uri = Uri.parse(url); + + if (!uri.isAbsolute) { + uri = Uri.parse(baseUrl).resolveUri(uri); + } + + return toAssetScheme(uri).toString(); + } + + /// Converts `absoluteUri` to use the 'asset' scheme used in the Angular 2 + /// template compiler. + /// + /// The `scheme` of `absoluteUri` is expected to be either 'package' or + /// 'asset'. + Uri toAssetScheme(Uri absoluteUri) { + if (absoluteUri == null) return null; + + if (!absoluteUri.isAbsolute) { + throw new ArgumentError.value( + absoluteUri, 'absoluteUri', 'Value passed must be an absolute uri'); + } + if (absoluteUri.scheme == 'asset') { + if (absoluteUri.pathSegments.length < 3) { + throw new FormatException( + 'An asset: URI must have at least 3 path ' + 'segments, for example ' + 'asset://.', + absoluteUri); + } + return absoluteUri; + } + if (absoluteUri.scheme != 'package') { + throw new ArgumentError.value( + absoluteUri, 'absoluteUri', 'Unsupported URI scheme encountered'); + } + + if (absoluteUri.pathSegments.length < 2) { + throw new FormatException( + 'A package: URI must have at least 2 path ' + 'segments, for example ' + 'package:/', + absoluteUri); + } + + var pathSegments = absoluteUri.pathSegments.toList()..insert(1, 'lib'); + return new Uri(scheme: 'asset', pathSegments: pathSegments); + } +} diff --git a/modules_dart/transform/lib/src/transform/common/xhr_impl.dart b/modules_dart/transform/lib/src/transform/common/xhr_impl.dart index d1d23f422f..bb76d477e3 100644 --- a/modules_dart/transform/lib/src/transform/common/xhr_impl.dart +++ b/modules_dart/transform/lib/src/transform/common/xhr_impl.dart @@ -3,29 +3,24 @@ library angular2.transform.template_compiler.xhr_impl; import 'dart:async'; import 'package:angular2/src/core/render/xhr.dart' show XHR; import 'package:angular2/src/transform/common/asset_reader.dart'; -import 'package:angular2/src/transform/common/logging.dart'; import 'package:barback/barback.dart'; -import 'package:code_transformers/assets.dart'; class XhrImpl implements XHR { final AssetReader _reader; - final AssetId _entryPoint; - XhrImpl(this._reader, this._entryPoint); + XhrImpl(this._reader); Future get(String url) async { - var assetId = uriToAssetId(_entryPoint, url, logger, null /* span */, - errorOnAbsolute: false); - if (assetId == null) { - logger.error( - 'Uri $url not supported from $_entryPoint, could not build AssetId'); - return null; + final uri = Uri.parse(url); + if (uri.scheme != 'asset') { + throw new FormatException('Unsupported uri encountered: $uri', url); } - var templateExists = await _reader.hasInput(assetId); - if (!templateExists) { - logger.error('Could not read asset at uri $url from $_entryPoint'); - return null; + final assetId = + new AssetId(uri.pathSegments.first, uri.pathSegments.skip(1).join('/')); + + if (!await _reader.hasInput(assetId)) { + throw new ArgumentError.value('Could not read asset at uri $url', 'url'); } - return await _reader.readAsString(assetId); + return _reader.readAsString(assetId); } } diff --git a/modules_dart/transform/lib/src/transform/di_transformer.dart b/modules_dart/transform/lib/src/transform/di_transformer.dart deleted file mode 100644 index ae432c5bd3..0000000000 --- a/modules_dart/transform/lib/src/transform/di_transformer.dart +++ /dev/null @@ -1,36 +0,0 @@ -library angular2.src.transform.di_transformer; - -import 'package:barback/barback.dart'; -import 'package:dart_style/dart_style.dart'; - -import 'directive_linker/transformer.dart'; -import 'directive_processor/transformer.dart'; -import 'reflection_remover/transformer.dart'; -import 'common/formatter.dart' as formatter; -import 'common/options.dart'; -import 'common/options_reader.dart'; - -export 'common/options.dart'; - -/// Removes the mirror-based initialization logic and replaces it with static -/// logic. -class DiTransformerGroup extends TransformerGroup { - DiTransformerGroup._(phases) : super(phases) { - formatter.init(new DartFormatter()); - } - - factory DiTransformerGroup(TransformerOptions options) { - var phases = [ - [new ReflectionRemover(options)], - [new DirectiveProcessor(null)] - ]; - phases.addAll(new List.generate( - options.optimizationPhases, (_) => [new EmptyNgDepsRemover()])); - phases.add([new DirectiveLinker()]); - return new DiTransformerGroup._(phases); - } - - factory DiTransformerGroup.asPlugin(BarbackSettings settings) { - return new DiTransformerGroup(parseBarbackSettings(settings)); - } -} diff --git a/modules_dart/transform/lib/src/transform/directive_linker/transformer.dart b/modules_dart/transform/lib/src/transform/directive_linker/transformer.dart index eed6d14bf8..4c60683d4a 100644 --- a/modules_dart/transform/lib/src/transform/directive_linker/transformer.dart +++ b/modules_dart/transform/lib/src/transform/directive_linker/transformer.dart @@ -32,16 +32,16 @@ class DirectiveLinker extends Transformer implements DeclaringTransformer { Future apply(Transform transform) async { await log.initZoned(transform, () async { var reader = new AssetReader.fromTransform(transform); - var assetId = transform.primaryInput.id; - var ngDepsModel = await linkNgDeps(reader, assetId); + var primaryId = transform.primaryInput.id; + var ngDepsModel = await linkNgDeps(reader, primaryId); // See above // transform.consumePrimary(); - var outputAssetId = _depsAssetId(assetId); + var outputAssetId = _depsAssetId(primaryId); if (ngDepsModel != null) { var buf = new StringBuffer(); var writer = new NgDepsWriter(buf); writer.writeNgDepsModel(ngDepsModel); - var formattedCode = formatter.format('$buf', uri: assetId.path); + var formattedCode = formatter.format('$buf', uri: primaryId.path); transform.addOutput(new Asset.fromString(outputAssetId, formattedCode)); } else { transform.addOutput(new Asset.fromString(outputAssetId, '')); diff --git a/modules_dart/transform/lib/src/transform/directive_metadata_extractor/extractor.dart b/modules_dart/transform/lib/src/transform/directive_metadata_extractor/extractor.dart deleted file mode 100644 index 1dc047ba54..0000000000 --- a/modules_dart/transform/lib/src/transform/directive_metadata_extractor/extractor.dart +++ /dev/null @@ -1,74 +0,0 @@ -library angular2.transform.directive_metadata_extractor.extractor; - -import 'dart:async'; -import 'dart:convert'; - -import 'package:analyzer/analyzer.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/ng_deps.dart'; -import 'package:angular2/src/transform/common/ng_meta.dart'; -import 'package:barback/barback.dart'; -import 'package:code_transformers/assets.dart'; - -/// Returns [NgMeta] associated with [entryPoint]. -/// -/// This includes entries for every `Directive`-annotated classes and -/// constants that match the directive-aliases pattern, which are visible in a -/// file importing `entryPoint`. That is, this includes all `Directive` -/// annotated public classes in `entryPoint`, all `DirectiveAlias` annotated -/// public variables, and any assets which it `export`s. Returns an empty -/// [NgMeta] if there are no `Directive`-annotated classes in `entryPoint`. -Future extractDirectiveMetadata( - AssetReader reader, AssetId entryPoint) { - return _extractDirectiveMetadataRecursive( - reader, entryPoint, new Set()); -} - -final _nullFuture = new Future.value(null); - -Future _extractDirectiveMetadataRecursive( - AssetReader reader, AssetId entryPoint, Set seen) async { - if (seen.contains(entryPoint)) return _nullFuture; - seen.add(entryPoint); - var ngMeta = new NgMeta.empty(); - if (!(await reader.hasInput(entryPoint))) return ngMeta; - - var ngDeps = await NgDeps.parse(reader, entryPoint); - _extractMetadata(ngDeps, ngMeta); - - var aliasesFile = - new AssetId(entryPoint.package, toAliasExtension(entryPoint.path)); - - if (await reader.hasInput(aliasesFile)) { - ngMeta.addAll(new NgMeta.fromJson( - JSON.decode(await reader.readAsString(aliasesFile)))); - } - - await Future.wait(ngDeps.exports.map((export) { - var uri = stringLiteralToString(export.uri); - if (uri.startsWith('dart:')) return _nullFuture; - - uri = toDepsExtension(uri); - var assetId = uriToAssetId(entryPoint, uri, logger, null /* span */, - errorOnAbsolute: false); - if (assetId == entryPoint) return _nullFuture; - return _extractDirectiveMetadataRecursive(reader, assetId, seen) - .then((exportedNgMeta) { - if (exportedNgMeta != null) { - ngMeta.addAll(exportedNgMeta); - } - }); - })); - return ngMeta; -} - -// TODO(sigmund): rather than having to parse it from generated code. we should -// be able to produce directly all information we need for ngMeta. -void _extractMetadata(NgDeps ngDeps, NgMeta ngMeta) { - if (ngDeps == null) return; - ngDeps.registeredTypes.forEach((type) { - ngMeta.types[type.typeName.name] = type.directiveMetadata; - }); -} diff --git a/modules_dart/transform/lib/src/transform/directive_metadata_extractor/transformer.dart b/modules_dart/transform/lib/src/transform/directive_metadata_extractor/transformer.dart deleted file mode 100644 index 92fb662102..0000000000 --- a/modules_dart/transform/lib/src/transform/directive_metadata_extractor/transformer.dart +++ /dev/null @@ -1,49 +0,0 @@ -library angular2.transform.directive_metadata_extractor.transformer; - -import 'dart:async'; -import 'dart:convert'; - -import 'package:angular2/src/transform/common/asset_reader.dart'; -import 'package:angular2/src/transform/common/logging.dart' as log; -import 'package:angular2/src/transform/common/names.dart'; -import 'package:barback/barback.dart'; - -import 'extractor.dart'; - -/// Transformer responsible for processing .ng_deps.dart files created by -/// {@link DirectiveProcessor} and creating associated `.ng_meta.dart` files. -/// These files contain commented Json-formatted representations of all -/// `Directive`s in the associated file. -class DirectiveMetadataExtractor extends Transformer - implements DeclaringTransformer { - final _encoder = const JsonEncoder.withIndent(' '); - - DirectiveMetadataExtractor(); - - @override - bool isPrimary(AssetId id) => id.path.endsWith(DEPS_EXTENSION); - - @override - declareOutputs(DeclaringTransform transform) { - transform.declareOutput(_outputAssetId(transform.primaryId)); - } - - @override - Future apply(Transform transform) async { - await log.initZoned(transform, () async { - var reader = new AssetReader.fromTransform(transform); - var fromAssetId = transform.primaryInput.id; - - var ngMeta = await extractDirectiveMetadata(reader, fromAssetId); - if (ngMeta != null && !ngMeta.isEmpty) { - transform.addOutput(new Asset.fromString( - _outputAssetId(fromAssetId), _encoder.convert(ngMeta.toJson()))); - } - }); - } -} - -AssetId _outputAssetId(AssetId inputAssetId) { - assert(inputAssetId.path.endsWith(DEPS_EXTENSION)); - return new AssetId(inputAssetId.package, toMetaExtension(inputAssetId.path)); -} diff --git a/modules_dart/transform/lib/src/transform/directive_metadata_linker/linker.dart b/modules_dart/transform/lib/src/transform/directive_metadata_linker/linker.dart new file mode 100644 index 0000000000..06a66f1194 --- /dev/null +++ b/modules_dart/transform/lib/src/transform/directive_metadata_linker/linker.dart @@ -0,0 +1,78 @@ +library angular2.transform.directive_metadata_linker.linker; + +import 'dart:async'; +import 'dart:convert'; + +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/ng_meta.dart'; +import 'package:barback/barback.dart'; +import 'package:code_transformers/assets.dart'; +import 'package:path/path.dart' as path; + +/// Returns [NgMeta] associated with [entryPoint] combined with the [NgMeta] of +/// all files `export`ed from the original file. +/// +/// This includes entries for every `Directive`-annotated class and +/// constants that match the directive-aliases pattern. +/// +/// There are entries for each of these which is visible from a file importing +/// the original .dart file that produced `entryPoint`. That is, this includes +/// all `Directive` annotated public classes in that file, all `DirectiveAlias` +/// annotated public variables, and any of those entries which are visible from +/// files which the .dart file `export`ed. +/// +/// Returns an empty [NgMeta] if there are no `Directive`-annotated classes or +/// `DirectiveAlias` annotated constants in `entryPoint`. +Future linkDirectiveMetadata(AssetReader reader, AssetId entryPoint) { + return _linkDirectiveMetadataRecursive( + reader, entryPoint, new Set()); +} + +final _nullFuture = new Future.value(null); + +// TODO(kegluneq): Don't reinvent the wheel? Centalize? +AssetId _fromPackageUri(String packageUri) { + var pathParts = path.url.split(packageUri); + return new AssetId(pathParts[0].substring('package:'.length), + 'lib/${pathParts.getRange(1, pathParts.length).join('/')}'); +} + +Future _linkDirectiveMetadataRecursive( + AssetReader reader, AssetId entryPoint, Set seen) async { + if (entryPoint == null) { + return new NgMeta.empty(); + } + // Break cycles, if they exist. + if (seen.contains(entryPoint)) return _nullFuture; + seen.add(entryPoint); + if (!(await reader.hasInput(entryPoint))) return new NgMeta.empty(); + + var ngMetaJson = await reader.readAsString(entryPoint); + if (ngMetaJson == null || ngMetaJson.isEmpty) return new NgMeta.empty(); + + var ngMeta = new NgMeta.fromJson(JSON.decode(ngMetaJson)); + + if (ngMeta.exports == null) return ngMeta; + + // Recursively add NgMeta files from `exports`. + return Future.wait(ngMeta.exports.map((uri) { + if (uri.startsWith('dart:')) return _nullFuture; + var metaUri = toMetaExtension(uri); + var assetId; + if (uri.startsWith('package:')) { + assetId = _fromPackageUri(metaUri); + } else { + assetId = uriToAssetId(entryPoint, metaUri, logger, null /* span */, + errorOnAbsolute: false); + } + + return _linkDirectiveMetadataRecursive(reader, assetId, seen) + .then((exportedNgMeta) { + if (exportedNgMeta != null) { + ngMeta.addAll(exportedNgMeta); + } + }); + })).then((_) => ngMeta); +} diff --git a/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart b/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart new file mode 100644 index 0000000000..eb4975ba4f --- /dev/null +++ b/modules_dart/transform/lib/src/transform/directive_metadata_linker/transformer.dart @@ -0,0 +1,56 @@ +library angular2.transform.directive_metadata_linker.transformer; + +import 'dart:async'; +import 'dart:convert'; + +import 'package:angular2/src/transform/common/asset_reader.dart'; +import 'package:angular2/src/transform/common/logging.dart' as log; +import 'package:angular2/src/transform/common/names.dart'; +import 'package:barback/barback.dart'; + +import 'linker.dart'; + +/// Transformer responsible for processing .ng_meta.json files created by +/// {@link DirectiveProcessor} and "linking" them. +/// +/// This step ensures that for libraries that export, all `Directive`s reachable +/// from that library are declared in its associated .ng_meta.json file. +/// +/// See `common/ng_meta.dart` for the JSON format of these files are serialized +/// to. +class DirectiveMetadataLinker extends Transformer + implements DeclaringTransformer { + final _encoder = const JsonEncoder.withIndent(' '); + + @override + bool isPrimary(AssetId id) => id.path.endsWith(META_EXTENSION); + + @override + declareOutputs(DeclaringTransform transform) { + // TODO(kegluenq): We should consume this, but doing so causes barback to + // incorrectly determine what assets are available in this phase. + // transform.consumePrimary(); + transform.declareOutput(transform.primaryId); + } + + @override + Future apply(Transform transform) { + return log.initZoned(transform, () { + var primaryId = transform.primaryInput.id; + + return linkDirectiveMetadata( + new AssetReader.fromTransform(transform), primaryId).then((ngMeta) { + // See above + // transform.consumePrimary(); + if (ngMeta != null && !ngMeta.isEmpty) { + transform.addOutput(new Asset.fromString( + primaryId, _encoder.convert(ngMeta.toJson()))); + } else { + // Not outputting an asset could confuse barback, so output an + // empty one. + transform.addOutput(transform.primaryInput); + } + }); + }); + } +} diff --git a/modules_dart/transform/lib/src/transform/directive_processor/inliner.dart b/modules_dart/transform/lib/src/transform/directive_processor/inliner.dart index 1f7989a86c..e664e5e241 100644 --- a/modules_dart/transform/lib/src/transform/directive_processor/inliner.dart +++ b/modules_dart/transform/lib/src/transform/directive_processor/inliner.dart @@ -4,140 +4,102 @@ import 'dart:async'; import 'package:analyzer/analyzer.dart'; import 'package:analyzer/src/generated/ast.dart'; -import 'package:analyzer/src/generated/error.dart'; -import 'package:analyzer/src/generated/parser.dart'; -import 'package:analyzer/src/generated/scanner.dart'; -import 'package:analyzer/src/string_source.dart'; -import 'package:angular2/src/core/render/xhr.dart' show XHR; import 'package:angular2/src/transform/common/async_string_writer.dart'; import 'package:angular2/src/transform/common/logging.dart'; -import 'package:angular2/src/transform/common/model/annotation_model.pb.dart'; -import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart'; +import 'package:code_transformers/assets.dart'; +import 'package:angular2/src/transform/common/asset_reader.dart'; +import 'package:barback/barback.dart' show AssetId; +import 'package:source_span/source_span.dart'; +import 'package:path/path.dart' as path; -Future inlineViewProps(XHR xhr, NgDepsModel model) { - var toWait = []; - for (var reflectable in model.reflectables) { - for (var annotation in reflectable.annotations) { - if (annotation.isView) { - var rawTemplateUrl = _getTemplateUrlValue(annotation); - if (rawTemplateUrl != null) { - if (_hasTemplateValue(annotation)) { - logger.warning('Both template url and template are specified. ' - 'Ignoring `templateUrl` value.'); - } else { - var url = _dumbEval(rawTemplateUrl); - if (url is String) { - toWait.add(_readOrEmptyString(xhr, url).then((templateText) { - _setTemplateValue(annotation, "r'''$templateText'''"); - })); - } else { - logger.warning('template url is not a String ($rawTemplateUrl)'); - } - } - } - var rawStyleUrls = _getStyleUrlsValue(annotation); - if (rawStyleUrls != null) { - if (_hasStylesValue(annotation)) { - logger.warning('Both styleUrls and styles are specified. ' - 'Ignoring `styleUrls` value.'); - } else { - var urls = _dumbEval(rawStyleUrls); - if (urls is List) { - var writer = new AsyncStringWriter(); - for (var url in urls) { - if (url is String) { - writer.print("r'''"); - writer.asyncPrint(_readOrEmptyString(xhr, url)); - writer.print("''', "); - } else { - logger.warning('style url is not a String (${url})'); - } - } - toWait.add(writer.asyncToString().then((styleUrlText) { - _setStylesValue(annotation, 'const [$styleUrlText]'); - _removeStyleUrlsValue(annotation); - })); - } else { - logger.warning( - 'styleUrls is not a List of strings ($rawStyleUrls)'); - } - } - } +/// Reads the code at `assetId`, inlining any `part` directives in that code. +/// +/// Returns `null` if the code represented by `assetId` is a `part`. +/// +/// Order of `part`s is preserved. That is, if in the main library we have +/// ``` +/// library main; +/// +/// part 'lib1.dart' +/// part 'lib2.dart' +/// ``` +/// The output will first have the contents of lib1 followed by the contents of +/// lib2.dart, followed by the original code in the library. +Future inlineParts(AssetReader reader, AssetId assetId) async { + var code = await reader.readAsString(assetId); + + var directivesVisitor = new _NgDepsDirectivesVisitor(); + parseDirectives(code, name: assetId.path) + .directives + .accept(directivesVisitor); + + // If this is part of another library, its contents will be processed by its + // parent, so it does not need its own `.ng_deps.dart` file. + if (directivesVisitor.isPart) return null; + + return _getAllDeclarations(reader, assetId, code, directivesVisitor); +} + +/// Processes `visitor.parts`, reading and appending their contents to the +/// original `code`. +Future _getAllDeclarations(AssetReader reader, AssetId assetId, + String code, _NgDepsDirectivesVisitor visitor) { + if (visitor.parts.isEmpty) return new Future.value(code); + + var partsStart = visitor.parts.first.offset, + partsEnd = visitor.parts.last.end; + + var asyncWriter = new AsyncStringWriter(code.substring(0, partsStart)); + visitor.parts.forEach((partDirective) { + var uri = stringLiteralToString(partDirective.uri); + var partAssetId = uriToAssetId(assetId, uri, logger, null /* span */, + errorOnAbsolute: false); + asyncWriter.asyncPrint(reader.readAsString(partAssetId).then((partCode) { + if (partCode == null || partCode.isEmpty) { + logger.warning('Empty part at "${partDirective.uri}. Ignoring.', + asset: partAssetId); + return ''; } - } + // Remove any directives -- we just want declarations. + var parsedDirectives = parseDirectives(partCode, name: uri).directives; + return partCode.substring(parsedDirectives.last.end); + }).catchError((err, stackTrace) { + logger.warning( + 'Failed while reading part at ${partDirective.uri}. Ignoring.\n' + 'Error: $err\n' + 'Stack Trace: $stackTrace', + asset: partAssetId, + span: new SourceFile(code, url: path.basename(assetId.path)) + .span(partDirective.offset, partDirective.end)); + })); + }); + asyncWriter.print(code.substring(partsEnd)); + + return asyncWriter.asyncToString(); +} + +/// Visitor responsible for reading the `part` files of the visited AST and +/// determining if it is a part of another library. +class _NgDepsDirectivesVisitor extends Object with SimpleAstVisitor { + /// Whether the file we are processing is a part, that is, whether we have + /// visited a `part of` directive. + bool _isPart = false; + + final List _parts = []; + bool get isPart => _isPart; + + /// In the order encountered in the source. + Iterable get parts => _parts; + + @override + Object visitPartDirective(PartDirective node) { + _parts.add(node); + return null; } - return Future.wait(toWait); -} -String _getNamedArgValue(AnnotationModel model, String argName) { - var value = null; - if (model.namedParameters != null) { - var match = model.namedParameters - .firstWhere((p) => p.name == argName, orElse: () => null); - value = match != null ? match.value : null; + @override + Object visitPartOfDirective(PartOfDirective node) { + _isPart = true; + return null; } - return value; -} - -String _getTemplateUrlValue(AnnotationModel model) => - _getNamedArgValue(model, 'templateUrl'); -String _getStyleUrlsValue(AnnotationModel model) => - _getNamedArgValue(model, 'styleUrls'); - -bool _hasTemplateValue(AnnotationModel model) => - _getNamedArgValue(model, 'template') != null; -bool _hasStylesValue(AnnotationModel model) => - _getNamedArgValue(model, 'styles') != null; - -void _setNamedArgValue(AnnotationModel model, String argName, String argValue) { - var matchedArg = model.namedParameters - .firstWhere((p) => p.name == argName, orElse: () => null); - if (matchedArg == null) { - matchedArg = new NamedParameter()..name = argName; - model.namedParameters.add(matchedArg); - } - matchedArg.value = argValue; -} - -void _setTemplateValue(AnnotationModel model, String template) => - _setNamedArgValue(model, 'template', template); -void _setStylesValue(AnnotationModel model, String styles) => - _setNamedArgValue(model, 'styles', styles); - -void _removeNamedArg(AnnotationModel model, String argName) { - model.namedParameters.removeWhere((p) => p.name == argName); -} - -void _removeStyleUrlsValue(AnnotationModel model) => - _removeNamedArg(model, 'styleUrls'); - -final _constantEvaluator = new ConstantEvaluator(); - -/// Attempts to read the content from {@link url}, if it returns null then -/// just return the empty string. -Future _readOrEmptyString(XHR xhr, String url) async { - var content = await xhr.get(url); - if (content == null) { - content = ''; - } - return content; -} - -dynamic _dumbEval(String code) { - var source = new StringSource(code, code); - // TODO(kegluneq): Report errors. - var errorCollector = AnalysisErrorListener.NULL_LISTENER; - - var reader = new CharSequenceReader(code); - var scanner = new Scanner(source, reader, errorCollector); - var parser = new Parser(source, errorCollector) - ..currentToken = scanner.tokenize(); - var expr = parser.parseExpression2(); - var val = null; - if (expr is SimpleStringLiteral) { - val = stringLiteralToString(expr); - } else { - val = expr.accept(_constantEvaluator); - } - return val != ConstantEvaluator.NOT_A_CONSTANT ? val : null; } diff --git a/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart b/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart index b98641e6b1..da89e38fa9 100644 --- a/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart +++ b/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart @@ -5,16 +5,15 @@ import 'dart:async'; import 'package:analyzer/analyzer.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/async_string_writer.dart'; import 'package:angular2/src/transform/common/code/ng_deps_code.dart'; +import 'package:angular2/src/transform/common/directive_metadata_reader.dart'; +import 'package:angular2/src/transform/common/interface_matcher.dart'; import 'package:angular2/src/transform/common/logging.dart'; import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart'; -import 'package:angular2/src/transform/common/xhr_impl.dart'; +import 'package:angular2/src/transform/common/ng_compiler.dart'; import 'package:angular2/src/transform/common/ng_meta.dart'; import 'package:barback/barback.dart' show AssetId; -import 'package:code_transformers/assets.dart'; -import 'package:path/path.dart' as path; -import 'package:source_span/source_span.dart'; +import 'package:angular2/src/compiler/template_compiler.dart'; import 'inliner.dart'; @@ -26,136 +25,44 @@ import 'inliner.dart'; /// string unless `forceGenerate` is true, in which case an empty ngDeps /// file is created. Future createNgDeps(AssetReader reader, AssetId assetId, - AnnotationMatcher annotationMatcher, NgMeta ngMeta, - {bool inlineViews}) async { + AnnotationMatcher annotationMatcher, NgMeta ngMeta) async { // TODO(kegluneq): Shortcut if we can determine that there are no // [Directive]s present, taking into account `export`s. - var code = await reader.readAsString(assetId); + var codeWithParts = await inlineParts(reader, assetId); + if (codeWithParts == null || codeWithParts.isEmpty) return null; - var directivesVisitor = new _NgDepsDirectivesVisitor(); - parseDirectives(code, name: assetId.path) - .directives - .accept(directivesVisitor); - - // If this is part of another library, its contents will be processed by its - // parent, so it does not need its own `.ng_deps.dart` file. - if (directivesVisitor.isPart) return null; - - var codeWithParts = - await _getAllDeclarations(reader, assetId, code, directivesVisitor); var parsedCode = parseCompilationUnit(codeWithParts, name: '${assetId.path} and parts'); var ngDepsVisitor = new NgDepsVisitor(assetId, annotationMatcher); - // TODO(kegluneq): Parse `declarations` in the NgDepsModel as well. parsedCode.accept(ngDepsVisitor); var ngDepsModel = ngDepsVisitor.model; - var ngMetaVisitor = new _NgMetaVisitor(ngMeta); + var templateCompiler = createTemplateCompiler(reader); + var ngMetaVisitor = new _NgMetaVisitor( + ngMeta, assetId, annotationMatcher, _interfaceMatcher, templateCompiler); parsedCode.accept(ngMetaVisitor); + await ngMetaVisitor.whenDone(); // If this file imports only dart: libraries and does not define any // reflectables of its own, it doesn't need a .ng_deps.dart file. - if (!directivesVisitor.usesNonLangLibs && - (ngDepsModel.reflectables == null || ngDepsModel.reflectables.isEmpty)) { - return null; - } - - if (inlineViews) { - await inlineViewProps(new XhrImpl(reader, assetId), ngDepsModel); + if (ngDepsModel.reflectables == null || ngDepsModel.reflectables.isEmpty) { + if (ngDepsModel.imports.every(_isDartImport) && + ngDepsModel.exports.every(_isDartImport)) { + return null; + } } return ngDepsModel; } -/// Processes `visitor.parts`, reading and appending their contents to the -/// original `code`. -/// Order of `part`s is preserved. That is, if in the main library we have -/// ``` -/// library main; -/// -/// part 'lib1.dart' -/// part 'lib2.dart' -/// ``` -/// The output will first have the contents of lib1 followed by the contents of -/// lib2.dart, followed by the original code in the library. -Future _getAllDeclarations(AssetReader reader, AssetId assetId, - String code, _NgDepsDirectivesVisitor visitor) { - if (visitor.parts.isEmpty) return new Future.value(code); +// `model` can be an [ImportModel] or [ExportModel]. +bool _isDartImport(dynamic model) => model.uri.startsWith('dart:'); - var partsStart = visitor.parts.first.offset, - partsEnd = visitor.parts.last.end; +// TODO(kegluneq): Allow the caller to provide an InterfaceMatcher. +final _interfaceMatcher = new InterfaceMatcher(); - var asyncWriter = new AsyncStringWriter(code.substring(0, partsStart)); - visitor.parts.forEach((partDirective) { - var uri = stringLiteralToString(partDirective.uri); - var partAssetId = uriToAssetId(assetId, uri, logger, null /* span */, - errorOnAbsolute: false); - asyncWriter.asyncPrint(reader.readAsString(partAssetId).then((partCode) { - if (partCode == null || partCode.isEmpty) { - logger.warning('Empty part at "${partDirective.uri}. Ignoring.', - asset: partAssetId); - return ''; - } - // Remove any directives -- we just want declarations. - var parsedDirectives = parseDirectives(partCode, name: uri).directives; - return partCode.substring(parsedDirectives.last.end); - }).catchError((err, stackTrace) { - logger.warning( - 'Failed while reading part at ${partDirective.uri}. Ignoring.\n' - 'Error: $err\n' - 'Stack Trace: $stackTrace', - asset: partAssetId, - span: new SourceFile(code, url: path.basename(assetId.path)) - .span(partDirective.offset, partDirective.end)); - })); - }); - asyncWriter.print(code.substring(partsEnd)); - - return asyncWriter.asyncToString(); -} - -/// Visitor responsible for flattening directives passed to it. -/// Once this has visited an Ast, use [#writeTo] to write out the directives -/// for the .ng_deps.dart file. See [#writeTo] for details. -class _NgDepsDirectivesVisitor extends Object with SimpleAstVisitor { - /// Whether this library `imports` or `exports` any non-'dart:' libraries. - bool _usesNonLangLibs = false; - - /// Whether the file we are processing is a part, that is, whether we have - /// visited a `part of` directive. - bool _isPart = false; - - final List _parts = []; - - bool get usesNonLangLibs => _usesNonLangLibs; - bool get isPart => _isPart; - - /// In the order encountered in the source. - Iterable get parts => _parts; - - Object _updateUsesNonLangLibs(UriBasedDirective directive) { - _usesNonLangLibs = _usesNonLangLibs || - !stringLiteralToString(directive.uri).startsWith('dart:'); - return null; - } - - @override - Object visitExportDirective(ExportDirective node) => - _updateUsesNonLangLibs(node); - - @override - Object visitImportDirective(ImportDirective node) => - _updateUsesNonLangLibs(node); - - @override - Object visitPartDirective(PartDirective node) { - _parts.add(node); - return null; - } -} - -/// Visitor responsible for visiting a file's [Declaration]s and outputting the +/// Visitor responsible for visiting a file and outputting the /// code necessary to register the file with the Angular 2 system. class _NgMetaVisitor extends Object with SimpleAstVisitor { /// Output ngMeta information about aliases. @@ -164,14 +71,52 @@ class _NgMetaVisitor extends Object with SimpleAstVisitor { // parsing the ngdeps files later. final NgMeta ngMeta; - _NgMetaVisitor(this.ngMeta); + /// The [AssetId] we are currently processing. + final AssetId assetId; + + final DirectiveMetadataReader _reader; + final _normalizations = []; + + _NgMetaVisitor(this.ngMeta, this.assetId, AnnotationMatcher annotationMatcher, + InterfaceMatcher interfaceMatcher, TemplateCompiler templateCompiler) + : _reader = new DirectiveMetadataReader( + annotationMatcher, interfaceMatcher, templateCompiler); + + Future whenDone() { + return Future.wait(_normalizations); + } @override Object visitCompilationUnit(CompilationUnit node) { - if (node == null || node.declarations == null) return null; + if (node == null || + (node.directives == null && node.declarations == null)) { + return null; + } + node.directives.accept(this); return node.declarations.accept(this); } + @override + Object visitExportDirective(ExportDirective node) { + ngMeta.exports.add(stringLiteralToString(node.uri)); + return null; + } + + @override + Object visitClassDeclaration(ClassDeclaration node) { + _normalizations.add(_reader + .readDirectiveMetadata(node, assetId) + .then((compileDirectiveMetadata) { + if (compileDirectiveMetadata != null) { + ngMeta.types[compileDirectiveMetadata.type.name] = + compileDirectiveMetadata; + } + }).catchError((err) { + logger.error('ERROR: $err'); + })); + return null; + } + @override Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { // We process any top-level declaration that fits the directive-alias diff --git a/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart b/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart index c7f6abba09..be8e253e9c 100644 --- a/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart +++ b/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart @@ -3,6 +3,7 @@ library angular2.transform.directive_processor.transformer; import 'dart:async'; import 'dart:convert'; +import 'package:angular2/src/core/dom/html_adapter.dart'; import 'package:angular2/src/transform/common/asset_reader.dart'; import 'package:angular2/src/transform/common/logging.dart' as log; import 'package:angular2/src/transform/common/names.dart'; @@ -23,6 +24,7 @@ import 'rewriter.dart'; /// be followed by {@link DirectiveLinker}. class DirectiveProcessor extends Transformer implements DeclaringTransformer { final TransformerOptions options; + final _encoder = const JsonEncoder.withIndent(' '); DirectiveProcessor(this.options); @@ -34,33 +36,40 @@ class DirectiveProcessor extends Transformer implements DeclaringTransformer { /// determine that one or the other will not be emitted. @override declareOutputs(DeclaringTransform transform) { - transform.declareOutput(_depsOutputId(transform.primaryId)); - transform.declareOutput(_metaOutputId(transform.primaryId)); + transform.declareOutput(_ngMetaAssetId(transform.primaryId)); + transform.declareOutput(_ngDepsAssetId(transform.primaryId)); } @override Future apply(Transform transform) async { + Html5LibDomAdapter.makeCurrent(); await log.initZoned(transform, () async { - var assetId = transform.primaryInput.id; + var primaryId = transform.primaryInput.id; var reader = new AssetReader.fromTransform(transform); var ngMeta = new NgMeta.empty(); var ngDepsModel = await createNgDeps( - reader, assetId, options.annotationMatcher, ngMeta, - inlineViews: options.inlineViews); + reader, primaryId, options.annotationMatcher, ngMeta); + // TODO(kegluneq): Combine NgDepsModel with NgMeta in a single .json file. if (ngDepsModel != null) { + var ngDepsAssetId = _ngDepsAssetId(primaryId); transform.addOutput(new Asset.fromString( - _depsOutputId(assetId), ngDepsModel.writeToJson())); + ngDepsAssetId, _encoder.convert(ngDepsModel.writeToJsonMap()))); } - var metaOutputId = _metaOutputId(assetId); + var metaOutputId = _ngMetaAssetId(primaryId); if (!ngMeta.isEmpty) { - transform.addOutput(new Asset.fromString(metaOutputId, - new JsonEncoder.withIndent(" ").convert(ngMeta.toJson()))); + transform.addOutput(new Asset.fromString( + metaOutputId, _encoder.convert(ngMeta.toJson()))); } }); } } -AssetId _depsOutputId(AssetId primaryId) => - primaryId.changeExtension(DEPS_JSON_EXTENSION); -AssetId _metaOutputId(AssetId primaryId) => - primaryId.changeExtension(ALIAS_EXTENSION); +AssetId _ngMetaAssetId(AssetId primaryInputId) { + return new AssetId( + primaryInputId.package, toMetaExtension(primaryInputId.path)); +} + +AssetId _ngDepsAssetId(AssetId primaryInputId) { + return new AssetId( + primaryInputId.package, toJsonExtension(primaryInputId.path)); +} diff --git a/modules_dart/transform/lib/src/transform/inliner_for_test.dart b/modules_dart/transform/lib/src/transform/inliner_for_test.dart new file mode 100644 index 0000000000..1c6fb4fb81 --- /dev/null +++ b/modules_dart/transform/lib/src/transform/inliner_for_test.dart @@ -0,0 +1,151 @@ +library angular2.src.transform.transform_for_test; + +import 'dart:async'; + +import 'package:analyzer/analyzer.dart'; +import 'package:analyzer/src/generated/ast.dart'; +import 'package:angular2/src/core/render/xhr.dart' show XHR; +import 'package:angular2/src/transform/common/asset_reader.dart'; +import 'package:barback/barback.dart'; + +import 'common/options_reader.dart'; +import 'common/asset_reader.dart'; +import 'common/async_string_writer.dart'; +import 'common/logging.dart'; +import 'common/url_resolver.dart'; +import 'common/xhr_impl.dart'; +import 'directive_processor/inliner.dart'; + +/// Processes .dart files and inlines `templateUrl` and styleUrls` values. +class InlinerForTest extends Transformer implements DeclaringTransformer { + InlinerForTest(); + + @override + bool isPrimary(AssetId id) => id.extension.endsWith('dart'); + + @override + declareOutputs(DeclaringTransform transform) { + transform.consumePrimary(); + transform.declareOutput(transform.primaryId); + } + + @override + Future apply(Transform transform) async { + return log.initZoned(transform, () async { + var primaryId = transform.primaryInput.id; + transform.consumePrimary(); + var inlinedCode = + await inline(new AssetReader.fromTransform(transform), primaryId); + if (inlinedCode == null || inlinedCode.isEmpty) { + transform.addOutput(transform.primaryInput); + } else { + transform.addOutput(new Asset.fromString(primaryId, inlinedCode)); + } + }); + } + + factory InlinerForTest.asPlugin(BarbackSettings settings) { + return new InlinerForTest(parseBarbackSettings(settings)); + } +} + +Future inline(AssetReader reader, AssetId assetId) async { + var codeWithParts = await inlineParts(reader, assetId); + if (codeWithParts == null) return null; + var parsedCode = + parseCompilationUnit(codeWithParts, name: '${assetId.path} and parts'); + var writer = new AsyncStringWriter(); + var visitor = new _ViewPropInliner(assetId, writer, new XhrImpl(reader)); + parsedCode.accept(visitor); + return writer.asyncToString(); +} + +final _urlResolver = const TransformerUrlResolver(); + +class _ViewPropInliner extends ToSourceVisitor { + final Uri _baseUri; + final AsyncStringWriter _writer; + final XHR _xhr; + + _ViewPropInliner._(this._baseUri, AsyncStringWriter writer, this._xhr) + : _writer = writer, + super(writer); + + factory _ViewPropInliner(AssetId assetId, AsyncStringWriter writer, XHR xhr) { + var baseUri = + new Uri(scheme: 'asset', path: '${assetId.package}/${assetId.path}'); + return new _ViewPropInliner._(baseUri, writer, xhr); + } + + @override + Object visitNamedExpression(NamedExpression node) { + if (node.name is! Label || node.name.label is! SimpleIdentifier) { + throw new FormatException( + 'Angular 2 currently only supports simple identifiers in directives.', + '$node' /* source */); + } + var keyString = '${node.name.label}'; + switch (keyString) { + case 'templateUrl': + _populateTemplateUrl(node.expression); + break; + case 'styleUrls': + _populateStyleUrls(node.expression); + break; + } + return super.visitNamedExpression(node); + } + + void _populateStyleUrls(Expression value) { + var urls = _dumbEval(value); + if (urls is! List) { + logger.warning('styleUrls is not a List of Strings ($value)'); + return; + } + _writer.print('styles: const ['); + for (var url in urls) { + if (url is String) { + _writer.print("r'''"); + _writer.asyncPrint(_readOrEmptyString(url)); + _writer.print("''', "); + } else { + logger.warning('style url is not a String (${url})'); + } + } + _writer.println('],'); + } + + void _populateTemplateUrl(Expression value) { + var url = _dumbEval(value); + if (url is! String) { + logger.warning('template url is not a String ($value)'); + return; + } + _writer.print("template: r'''"); + _writer.asyncPrint(_readOrEmptyString(url)); + _writer.println("''',"); + } + + /// Attempts to read the content from [url]. If [url] is relative, uses + /// [_baseUri] as resolution base. + Future _readOrEmptyString(String url) async { + final resolvedUri = _urlResolver.resolve(_baseUri.toString(), url); + + return _xhr.get(resolvedUri).catchError((_) { + logger.error('$_rootAssetId: could not read $url'); + return ''; + }); + } +} + +final _constantEvaluator = new ConstantEvaluator(); + +dynamic _dumbEval(Expression expr) { + var val; + if (expr is SimpleStringLiteral) { + val = stringLiteralToString(expr); + } else { + val = expr.accept(_constantEvaluator); + } + return val != ConstantEvaluator.NOT_A_CONSTANT ? val : null; +} diff --git a/modules_dart/transform/lib/src/transform/template_compiler/change_detector_codegen.dart b/modules_dart/transform/lib/src/transform/template_compiler/change_detector_codegen.dart index 5b6fcd46c3..e6002daae1 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/change_detector_codegen.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/change_detector_codegen.dart @@ -11,7 +11,8 @@ import 'package:angular2/src/core/change_detection/proto_change_detector.dart'; import 'package:angular2/src/core/change_detection/proto_record.dart'; import 'package:angular2/src/core/change_detection/event_binding.dart'; import 'package:angular2/src/core/change_detection/binding_record.dart'; -import 'package:angular2/src/core/change_detection/codegen_facade.dart' show codify; +import 'package:angular2/src/core/change_detection/codegen_facade.dart' + show codify; import 'package:angular2/src/core/facade/exceptions.dart' show BaseException; /// Responsible for generating change detector classes for Angular 2. @@ -90,8 +91,9 @@ class _CodegenState { final ChangeDetectorGenConfig _genConfig; final List _propertyBindingTargets; - String get _changeDetectionStrategyAsCode => - _changeDetectionStrategy == null ? 'null' : '${_genPrefix}${_changeDetectionStrategy}'; + String get _changeDetectionStrategyAsCode => _changeDetectionStrategy == null + ? 'null' + : '${_genPrefix}${_changeDetectionStrategy}'; /// The module prefix for pregen_proto_change_detector final String _genPrefix; @@ -110,13 +112,15 @@ class _CodegenState { this._names, this._genConfig); - factory _CodegenState(String genPrefix, String typeName, String changeDetectorTypeName, - ChangeDetectorDefinition def) { + factory _CodegenState(String genPrefix, String typeName, + String changeDetectorTypeName, ChangeDetectorDefinition def) { var protoRecords = createPropertyRecords(def); var eventBindings = createEventRecords(def); - var propertyBindingTargets = def.bindingRecords.map((b) => b.target).toList(); + var propertyBindingTargets = + def.bindingRecords.map((b) => b.target).toList(); - var names = new CodegenNameUtil(protoRecords, eventBindings, def.directiveRecords, '$genPrefix$_UTIL'); + var names = new CodegenNameUtil( + protoRecords, eventBindings, def.directiveRecords, '$genPrefix$_UTIL'); var logic = new CodegenLogicUtil(names, '$genPrefix$_UTIL', def.strategy); return new _CodegenState._( genPrefix, @@ -141,8 +145,8 @@ class _CodegenState { $_changeDetectorTypeName(dispatcher) : super(${codify(_changeDetectorDefId)}, dispatcher, ${_records.length}, - ${_changeDetectorTypeName}.gen_propertyBindingTargets, - ${_changeDetectorTypeName}.gen_directiveIndices, + ${_changeDetectorTypeName}.${_GEN_PROPERTY_BINDING_TARGETS_NAME}, + ${_changeDetectorTypeName}.${_GEN_DIRECTIVE_INDICES_NAME}, ${_changeDetectionStrategyAsCode}) { dehydrateDirectives(false); } @@ -183,18 +187,20 @@ class _CodegenState { } String _genPropertyBindingTargets() { - var targets = _logic.genPropertyBindingTargets(_propertyBindingTargets, this._genConfig.genDebugInfo); - return "static var gen_propertyBindingTargets = ${targets}"; + var targets = _logic.genPropertyBindingTargets( + _propertyBindingTargets, this._genConfig.genDebugInfo); + return "static final ${_GEN_PROPERTY_BINDING_TARGETS_NAME} = ${targets}"; } String _genDirectiveIndices() { var indices = _logic.genDirectiveIndices(_directiveRecords); - return "static var gen_directiveIndices = ${indices}"; + return "static final ${_GEN_DIRECTIVE_INDICES_NAME} = ${indices}"; } String _maybeGenHandleEventInternal() { if (_eventBindings.length > 0) { - var handlers = _eventBindings.map((eb) => _genEventBinding(eb)).join("\n"); + var handlers = + _eventBindings.map((eb) => _genEventBinding(eb)).join("\n"); return ''' handleEventInternal(eventName, elIndex, locals) { var ${this._names.getPreventDefaultAccesor()} = false; @@ -216,7 +222,7 @@ class _CodegenState { }'''; } - String _genEventBindingEval(EventBinding eb, ProtoRecord r){ + String _genEventBindingEval(EventBinding eb, ProtoRecord r) { if (r.lastInBinding) { var evalRecord = _logic.genEventBindingEvalValue(eb, r); var markPath = _genMarkPathToRootAsCheckOnce(r); @@ -271,7 +277,8 @@ class _CodegenState { } String _maybeGenAfterContentLifecycleCallbacks() { - var directiveNotifications = _logic.genContentLifecycleCallbacks(_directiveRecords); + var directiveNotifications = + _logic.genContentLifecycleCallbacks(_directiveRecords); if (directiveNotifications.isNotEmpty) { return ''' void afterContentLifecycleCallbacksInternal() { @@ -284,7 +291,8 @@ class _CodegenState { } String _maybeGenAfterViewLifecycleCallbacks() { - var directiveNotifications = _logic.genViewLifecycleCallbacks(_directiveRecords); + var directiveNotifications = + _logic.genViewLifecycleCallbacks(_directiveRecords); if (directiveNotifications.isNotEmpty) { return ''' void afterViewLifecycleCallbacksInternal() { @@ -420,7 +428,9 @@ class _CodegenState { var newValue = _names.getLocalName(r.selfIndex); var oldValue = _names.getFieldName(r.selfIndex); - var notifyDebug = _genConfig.logBindingUpdate ? "this.logBindingUpdate(${newValue});" : ""; + var notifyDebug = _genConfig.logBindingUpdate + ? "this.logBindingUpdate(${newValue});" + : ""; var br = r.bindingRecord; if (br.target.isDirective()) { @@ -527,4 +537,7 @@ const _NOT_IDENTICAL_CHECK_FN = 'looseNotIdentical'; const _IS_CHANGED_LOCAL = 'isChanged'; const _PREGEN_PROTO_CHANGE_DETECTOR_IMPORT = 'package:angular2/src/core/change_detection/pregen_proto_change_detector.dart'; +const _GEN_PROPERTY_BINDING_TARGETS_NAME = + '${_GEN_PREFIX}_propertyBindingTargets'; +const _GEN_DIRECTIVE_INDICES_NAME = '${_GEN_PREFIX}_directiveIndices'; const _UTIL = 'ChangeDetectionUtil'; diff --git a/modules_dart/transform/lib/src/transform/template_compiler/view_definition_creator.dart b/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart similarity index 63% rename from modules_dart/transform/lib/src/transform/template_compiler/view_definition_creator.dart rename to modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart index a54578e399..2dd1cc8ae5 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/view_definition_creator.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart @@ -1,9 +1,11 @@ -library angular2.transform.template_compiler.view_definition_creator; +library angular2.transform.template_compiler.compile_data_creator; import 'dart:async'; import 'dart:convert'; import 'package:analyzer/analyzer.dart'; +import 'package:angular2/src/compiler/directive_metadata.dart'; +import 'package:angular2/src/compiler/template_compiler.dart'; import 'package:angular2/src/core/render/api.dart'; import 'package:angular2/src/transform/common/asset_reader.dart'; import 'package:angular2/src/transform/common/logging.dart'; @@ -13,28 +15,24 @@ import 'package:angular2/src/transform/common/ng_meta.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( +/// Creates [NormalizedComponentWithViewDirectives] objects for all `View` +/// `Directive`s defined in `entryPoint`. +/// +/// The returned value wraps the [NgDeps] at `entryPoint` as well as these +/// created objects. +Future createCompileData( AssetReader reader, AssetId entryPoint) async { - return await new _ViewDefinitionCreator(reader, entryPoint).createViewDefs(); + return new _CompileDataCreator(reader, entryPoint).createCompileData(); } -class ViewDefinitionResults { +class CompileDataResults { final NgDeps ngDeps; - final Map viewDefinitions; - ViewDefinitionResults._(this.ngDeps, this.viewDefinitions); + final Map viewDefinitions; + + CompileDataResults._(this.ngDeps, this.viewDefinitions); } -class ViewDefinitionEntry { - final RenderDirectiveMetadata hostMetadata; - final ViewDefinition viewDef; - - ViewDefinitionEntry._(this.hostMetadata, this.viewDef); -} - -String _getComponentId(AssetId assetId, String className) => '$className'; - // TODO(kegluenq): Improve this test. bool _isViewAnnotation(InstanceCreationExpression node) { var constructorName = node.constructorName.type.name; @@ -46,42 +44,38 @@ bool _isViewAnnotation(InstanceCreationExpression node) { /// Creates [ViewDefinition] objects for all `View` `Directive`s defined in /// `entryPoint`. -class _ViewDefinitionCreator { +class _CompileDataCreator { final AssetReader reader; final AssetId entryPoint; final Future ngDepsFuture; - _ViewDefinitionCreator(AssetReader reader, AssetId entryPoint) + _CompileDataCreator(AssetReader reader, AssetId entryPoint) : this.reader = reader, this.entryPoint = entryPoint, ngDepsFuture = NgDeps.parse(reader, entryPoint); - Future createViewDefs() async { + Future createCompileData() async { var ngDeps = await ngDepsFuture; - var retVal = {}; - var visitor = new _TemplateExtractVisitor(await _extractNgMeta()); + var retVal = {}; + var visitor = new _DirectiveDependenciesVisitor(await _extractNgMeta()); ngDeps.registeredTypes.forEach((rType) { visitor.reset(); rType.annotations.accept(visitor); - if (visitor.viewDef != null) { + if (visitor.compileData != null) { // Note: we use '' because the current file maps to the default prefix. var ngMeta = visitor._metadataMap['']; var typeName = '${rType.typeName}'; - var hostMetadata = null; if (ngMeta.types.containsKey(typeName)) { - hostMetadata = ngMeta.types[typeName]; - visitor.viewDef.componentId = hostMetadata.id; + visitor.compileData.component = ngMeta.types[typeName]; } else { logger.warning('Missing component "$typeName" in metadata map', asset: entryPoint); - visitor.viewDef.componentId = _getComponentId(entryPoint, typeName); } - retVal[rType] = - new ViewDefinitionEntry._(hostMetadata, visitor.viewDef); + retVal[rType] = visitor.compileData; } }); - return new ViewDefinitionResults._(ngDeps, retVal); + return new CompileDataResults._(ngDeps, retVal); } /// Creates a map from [AssetId] to import prefix for `.dart` libraries @@ -89,13 +83,11 @@ class _ViewDefinitionCreator { /// 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.json` file associated with `entryPoint`. - importAssetToPrefix[new AssetId( - entryPoint.package, toMetaExtension(entryPoint.path))] = null; + var importAssetToPrefix = { + entryPoint: null + }; for (ImportDirective node in ngDeps.imports) { var uri = stringLiteralToString(node.uri); @@ -113,7 +105,7 @@ class _ViewDefinitionCreator { /// 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 [RenderDirectiveMetadata]. + /// associated [CompileDirectiveMetadata]. /// /// For example, if in `entryPoint` we have: /// @@ -129,13 +121,13 @@ class _ViewDefinitionCreator { /// ``` /// /// This method will look for `component.ng_meta.json`to contain the - /// serialized [RenderDirectiveMetadata] for `MyComponent` and any other + /// serialized [CompileDirectiveMetadata] for `MyComponent` and any other /// `Directive`s declared in `component.dart`. We use this information to /// build a map: /// /// ``` /// { - /// "prefix.MyComponent": [RenderDirectiveMetadata for MyComponent], + /// "prefix.MyComponent": [CompileDirectiveMetadata for MyComponent], /// ...... /// } /// ``` @@ -153,9 +145,6 @@ class _ViewDefinitionCreator { try { var json = JSON.decode(await reader.readAsString(metaAssetId)); var newMetadata = new NgMeta.fromJson(json); - newMetadata.types.forEach((className, metadata) { - metadata.id = _getComponentId(importAssetId, className); - }); ngMeta.addAll(newMetadata); } catch (ex, stackTrace) { logger.warning('Failed to decode: $ex, $stackTrace', @@ -168,23 +157,33 @@ class _ViewDefinitionCreator { } /// Visitor responsible for processing the `annotations` property of a -/// [RegisterType] object and pulling out [ViewDefinition] information. -class _TemplateExtractVisitor extends Object with RecursiveAstVisitor { - ViewDefinition viewDef = null; +/// [RegisterType] object, extracting the `directives` dependencies, and adding +/// their associated [CompileDirectiveMetadata] to the `directives` of a +/// created [NormalizedComponentWithViewDirectives] object. +/// +/// The `component` property of the created +/// [NormalizedComponentWithViewDirectives] will be null. +/// +/// If no `View` annotation is found, `compileData` will be null. +class _DirectiveDependenciesVisitor extends Object + with RecursiveAstVisitor { + NormalizedComponentWithViewDirectives compileData = null; final Map _metadataMap; - final ConstantEvaluator _evaluator = new ConstantEvaluator(); - _TemplateExtractVisitor(this._metadataMap); + _DirectiveDependenciesVisitor(this._metadataMap); void reset() { - viewDef = null; + compileData = null; } - /// These correspond to the annotations themselves. + /// These correspond to the annotations themselves, which are converted into + /// const instance creation expressions so they can be stored in the + /// reflector. @override Object visitInstanceCreationExpression(InstanceCreationExpression node) { if (_isViewAnnotation(node)) { - viewDef = new ViewDefinition(directives: []); + compileData = new NormalizedComponentWithViewDirectives( + null, []); node.visitChildren(this); } return null; @@ -200,43 +199,16 @@ class _TemplateExtractVisitor extends Object with RecursiveAstVisitor { ' Source: ${node}'); return null; } - var keyString = '${node.name.label}'; - if (keyString == 'directives') { + if ('${node.name.label}' == 'directives') { _readDirectives(node.expression); } - if (keyString == 'template' || keyString == 'templateUrl') { - // This could happen in a non-View annotation with a `template` or - // `templateUrl` property. - if (viewDef == null) return null; - - var valueString = node.expression.accept(_evaluator); - if (valueString is! String) { - logger.error( - 'Angular 2 currently only supports string literals in directives.' - ' Source: ${node}'); - return null; - } - if (keyString == 'templateUrl') { - if (viewDef.templateAbsUrl != null) { - logger.error( - 'Found multiple values for "templateUrl". Source: ${node}'); - } - viewDef.templateAbsUrl = 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) { // This could happen in a non-View annotation with a `directives` // parameter. - if (viewDef == null) return; + if (compileData == null) return; if (node is! ListLiteral) { logger.error('Angular 2 currently only supports list literals as values ' @@ -252,7 +224,7 @@ class _TemplateExtractVisitor extends Object with RecursiveAstVisitor { name = node.name; } else if (node is PrefixedIdentifier) { ngMeta = _metadataMap[node.prefix.name]; - name = node.name; + name = node.identifier.name; } else { logger.error( 'Angular 2 currently only supports simple and prefixed identifiers ' @@ -260,9 +232,9 @@ class _TemplateExtractVisitor extends Object with RecursiveAstVisitor { return; } if (ngMeta.types.containsKey(name)) { - viewDef.directives.add(ngMeta.types[name]); + compileData.directives.add(ngMeta.types[name]); } else if (ngMeta.aliases.containsKey(name)) { - viewDef.directives.addAll(ngMeta.flatten(name)); + compileData.directives.addAll(ngMeta.flatten(name)); } else { logger.warning('Could not find Directive entry for $node. ' 'Please be aware that Dart transformers have limited support for ' diff --git a/modules_dart/transform/lib/src/transform/template_compiler/compile_step_factory.dart b/modules_dart/transform/lib/src/transform/template_compiler/compile_step_factory.dart deleted file mode 100644 index 90a79ac88f..0000000000 --- a/modules_dart/transform/lib/src/transform/template_compiler/compile_step_factory.dart +++ /dev/null @@ -1,25 +0,0 @@ -library angular2.transform.template_compiler.compile_step_factory; - -import 'package:angular2/src/core/change_detection/parser/parser.dart' as ng; -import 'package:angular2/src/core/render/api.dart'; -import 'package:angular2/src/core/render/dom/compiler/compile_step.dart'; -import 'package:angular2/src/core/render/dom/compiler/compile_step_factory.dart' - as base; -import 'package:angular2/src/core/render/dom/compiler/directive_parser.dart'; -import 'package:angular2/src/core/render/dom/compiler/property_binding_parser.dart'; -import 'package:angular2/src/core/render/dom/compiler/text_interpolation_parser.dart'; -import 'package:angular2/src/core/render/dom/compiler/view_splitter.dart'; - -class CompileStepFactory implements base.CompileStepFactory { - final ng.Parser _parser; - CompileStepFactory(this._parser); - - List createSteps(ViewDefinition template) { - return [ - new ViewSplitter(_parser), - new PropertyBindingParser(_parser), - new DirectiveParser(_parser, template.directives), - new TextInterpolationParser(_parser) - ]; - } -} diff --git a/modules_dart/transform/lib/src/transform/template_compiler/generator.dart b/modules_dart/transform/lib/src/transform/template_compiler/generator.dart index 09f9a2065c..d3857eb2b6 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/generator.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/generator.dart @@ -2,138 +2,135 @@ library angular2.transform.template_compiler.generator; import 'dart:async'; -import 'package:angular2/src/core/change_detection/parser/lexer.dart' as ng; -import 'package:angular2/src/core/change_detection/parser/parser.dart' as ng; +import 'package:analyzer/analyzer.dart'; +import 'package:angular2/src/compiler/source_module.dart'; +import 'package:angular2/src/compiler/template_compiler.dart'; import 'package:angular2/src/core/change_detection/interfaces.dart'; -import 'package:angular2/src/core/compiler/proto_view_factory.dart'; -import 'package:angular2/src/core/dom/dom_adapter.dart'; -import 'package:angular2/src/core/render/api.dart'; -import 'package:angular2/src/core/render/dom/compiler/compile_pipeline.dart'; -import 'package:angular2/src/core/render/dom/compiler/style_inliner.dart'; -import 'package:angular2/src/core/render/dom/compiler/style_url_resolver.dart'; -import 'package:angular2/src/core/render/dom/compiler/view_loader.dart'; -import 'package:angular2/src/core/render/dom/schema/element_schema_registry.dart'; -import 'package:angular2/src/core/render/dom/schema/dom_element_schema_registry.dart'; -import 'package:angular2/src/core/render/dom/template_cloner.dart'; -import 'package:angular2/src/core/render/xhr.dart' show XHR; -import 'package:angular2/src/core/reflection/reflection.dart'; -import 'package:angular2/src/core/services/url_resolver.dart'; -import 'package:angular2/src/transform/common/asset_reader.dart'; -import 'package:angular2/src/transform/common/xhr_impl.dart'; import 'package:angular2/src/core/facade/lang.dart'; +import 'package:angular2/src/core/reflection/reflection.dart'; +import 'package:angular2/src/transform/common/asset_reader.dart'; +import 'package:angular2/src/transform/common/code/source_module.dart'; +import 'package:angular2/src/transform/common/names.dart'; +import 'package:angular2/src/transform/common/ng_compiler.dart'; +import 'package:angular2/src/transform/common/ng_deps.dart'; import 'package:barback/barback.dart'; +import 'package:path/path.dart' as path; -import 'change_detector_codegen.dart' as change; -import 'compile_step_factory.dart'; import 'reflection/codegen.dart' as reg; import 'reflection/processor.dart' as reg; import 'reflection/reflection_capabilities.dart'; -import 'view_definition_creator.dart'; +import 'compile_data_creator.dart'; /// Reads the `.ng_deps.dart` file represented by `entryPoint` and parses any /// Angular 2 `View` annotations it declares to generate `getter`s, /// `setter`s, and `method`s that would otherwise be reflectively accessed. /// /// This method assumes a {@link DomAdapter} has been registered. -Future processTemplates(AssetReader reader, AssetId entryPoint, - {bool generateRegistrations: true, - bool generateChangeDetectors: true, bool reflectPropertiesAsAttributes: false}) async { - var viewDefResults = await createViewDefinitions(reader, entryPoint); - // Note: TemplateCloner(-1) never serializes Nodes into strings. - // we might want to change this to TemplateCloner(0) to force the serialization - // later when the transformer also stores the proto view template. - var extractor = new _TemplateExtractor(new DomElementSchemaRegistry(), - new TemplateCloner(-1), new XhrImpl(reader, entryPoint)); +Future processTemplates(AssetReader reader, AssetId entryPoint, + {bool reflectPropertiesAsAttributes: false}) async { + var viewDefResults = await createCompileData(reader, entryPoint); - final processor = new reg.Processor(); + var templateCompiler = createTemplateCompiler(reader, + changeDetectionConfig: new ChangeDetectorGenConfig(assertionsEnabled(), + assertionsEnabled(), reflectPropertiesAsAttributes, false)); - var changeDetectorClasses = new change.Codegen(); - for (var rType in viewDefResults.viewDefinitions.keys) { - var viewDefEntry = viewDefResults.viewDefinitions[rType]; - var protoView = await extractor.extractTemplates(viewDefEntry.viewDef); - if (protoView == null) continue; + var ngDeps = viewDefResults.ngDeps; + var compileData = + viewDefResults.viewDefinitions.values.toList(growable: false); + if (compileData.isEmpty) { + return new Outputs(entryPoint, ngDeps, null, null, null); + } - if (generateRegistrations) { - processor.process(viewDefEntry, protoView); - } - if (generateChangeDetectors) { - var saved = reflector.reflectionCapabilities; - var genConfig = new ChangeDetectorGenConfig(assertionsEnabled(), assertionsEnabled(), reflectPropertiesAsAttributes, false); + var savedReflectionCapabilities = reflector.reflectionCapabilities; + reflector.reflectionCapabilities = const NullReflectionCapabilities(); + var compiledTemplates = templateCompiler.compileTemplatesCodeGen(compileData); + reflector.reflectionCapabilities = savedReflectionCapabilities; - reflector.reflectionCapabilities = const NullReflectionCapabilities(); - var defs = getChangeDetectorDefinitions(viewDefEntry.hostMetadata, - protoView, viewDefEntry.viewDef.directives, genConfig); - for (var i = 0; i < defs.length; ++i) { - changeDetectorClasses.generate('${rType.typeName}', - '_${rType.typeName}_ChangeDetector$i', defs[i]); + var processor = new reg.Processor(); + compileData + .map((withDirectives) => withDirectives.component) + .forEach(processor.process); + var codegen = new reg.Codegen(); + + codegen.generate(processor); + + return new Outputs(entryPoint, ngDeps, codegen, + viewDefResults.viewDefinitions, compiledTemplates); +} + +AssetId templatesAssetId(AssetId ngDepsAssetId) => + new AssetId(ngDepsAssetId.package, toTemplateExtension(ngDepsAssetId.path)); + +class Outputs { + final String ngDepsCode; + final String templatesCode; + + Outputs._(this.ngDepsCode, this.templatesCode); + + factory Outputs( + AssetId assetId, + NgDeps ngDeps, + reg.Codegen accessors, + Map compileDataMap, + SourceModule templatesSource) { + var libraryName = + ngDeps != null && ngDeps.lib != null ? '${ngDeps.lib.name}' : null; + return new Outputs._( + _generateNgDepsCode(assetId, ngDeps, accessors, compileDataMap), + writeSourceModule(templatesSource, libraryName: libraryName)); + } + + // Updates the NgDeps code with an additional `CompiledTemplate` annotation + // for each Directive we generated one for. + // + // Also adds an import to the `.template.dart` file that we will generate. + static String _generateNgDepsCode( + AssetId id, + NgDeps ngDeps, + reg.Codegen accessors, + Map compileDataMap) { + var code = ngDeps.code; + if (compileDataMap == null || compileDataMap.isEmpty) return code; + + if (ngDeps.registeredTypes.isEmpty) return code; + var beginRegistrationsIdx = + ngDeps.registeredTypes.first.registerMethod.offset; + var endRegistratationsIdx = ngDeps.registeredTypes.last.registerMethod.end; + var importInjectIdx = ngDeps.lib != null ? ngDeps.lib.end : 0; + + // Add everything up to the point where we begin registering classes with + // the reflector, injecting an import to the generated template code. + var buf = new StringBuffer('${code.substring(0, importInjectIdx)}' + 'import \'${toTemplateExtension(path.basename(id.path))}\' as _templates;' + '${code.substring(importInjectIdx, beginRegistrationsIdx)}'); + + for (var registeredType in ngDeps.registeredTypes) { + if (compileDataMap.containsKey(registeredType)) { + // We generated a template for this type, so add the generated + // `CompiledTemplate` value as the final annotation in the list. + var annotations = registeredType.annotations as ListLiteral; + if (annotations.length == 0) { + throw new FormatException('Unexpected format - attempting to codegen ' + 'a class with no Component annotation ${registeredType.typeName}'); + } + buf.write(code.substring(registeredType.registerMethod.offset, + annotations.elements.last.end)); + buf.write(', _templates.Host${registeredType.typeName}Template]'); + buf.writeln(code.substring( + registeredType.annotations.end, registeredType.registerMethod.end)); + } else { + // There is no compiled template for this type, write it out without any + // changes. + buf.writeln(code.substring(registeredType.registerMethod.offset, + registeredType.registerMethod.end)); } - reflector.reflectionCapabilities = saved; } - } - // TODO(kegluneq): Do not hard-code `false` here once i/3436 is fixed. - final registrations = new reg.Codegen(generateChangeDetectors: false); - registrations.generate(processor); + buf.writeln(accessors.toString()); - var code = viewDefResults.ngDeps.code; - if (registrations.isEmpty && changeDetectorClasses.isEmpty) return code; - var importInjectIdx = - viewDefResults.ngDeps.lib != null ? viewDefResults.ngDeps.lib.end : 0; - var codeInjectIdx = - viewDefResults.ngDeps.registeredTypes.last.registerMethod.end; - var initInjectIdx = viewDefResults.ngDeps.setupMethod.end - 1; - return '${code.substring(0, importInjectIdx)}' - '${changeDetectorClasses.imports}' - '${code.substring(importInjectIdx, codeInjectIdx)}' - '${registrations}' - '${code.substring(codeInjectIdx, initInjectIdx)}' - '${changeDetectorClasses.initialize}' - '${code.substring(initInjectIdx)}' - '$changeDetectorClasses'; -} - -/// Extracts `template` and `url` values from `View` annotations, reads -/// template code if necessary, and determines what values will be -/// reflectively accessed from that template. -class _TemplateExtractor { - final CompileStepFactory _factory; - ViewLoader _loader; - ElementSchemaRegistry _schemaRegistry; - TemplateCloner _templateCloner; - - _TemplateExtractor(this._schemaRegistry, this._templateCloner, XHR xhr) - : _factory = new CompileStepFactory(new ng.Parser(new ng.Lexer())) { - var urlResolver = new UrlResolver(); - var styleUrlResolver = new StyleUrlResolver(urlResolver); - var styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver); - - _loader = new ViewLoader(xhr, styleInliner, styleUrlResolver); - } - - Future extractTemplates(ViewDefinition viewDef) async { - // Check for "imperative views". - if (viewDef.template == null && viewDef.templateAbsUrl == null) return null; - - var templateAndStyles = await _loader.load(viewDef); - - // NOTE(kegluneq): Since this is a global, we must not have any async - // operations between saving and restoring it, otherwise we can get into - // a bad state. See issue #2359 for additional context. - var savedReflectionCapabilities = reflector.reflectionCapabilities; - reflector.reflectionCapabilities = const NullReflectionCapabilities(); - - var pipeline = new CompilePipeline(_factory.createSteps(viewDef)); - - var compileElements = pipeline.processElements( - DOM.createTemplate(templateAndStyles.template), - ViewType.COMPONENT, - viewDef); - var protoViewDto = compileElements[0] - .inheritedProtoView - .build(_schemaRegistry, _templateCloner); - - reflector.reflectionCapabilities = savedReflectionCapabilities; - - return protoViewDto; + // Add everything after the final registration. + buf.writeln(code.substring(endRegistratationsIdx)); + return buf.toString(); } } diff --git a/modules_dart/transform/lib/src/transform/template_compiler/reflection/codegen.dart b/modules_dart/transform/lib/src/transform/template_compiler/reflection/codegen.dart index ba13b8f3a5..21b621ebd6 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/reflection/codegen.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/reflection/codegen.dart @@ -8,12 +8,11 @@ import 'model.dart'; class Codegen { final StringBuffer _buf = new StringBuffer(); - /// Whether we are pre-generating change detectors. - /// If we have pre-generated change detectors, we need - final bool generateChangeDetectors; - - Codegen({this.generateChangeDetectors}); - + /// Generates code to register all getters, setters, and methods stored by + /// `model`. + /// + /// The code takes the form of zero or more cascaded calls. The receiver of + /// these calls is expected to be an Angular 2 reflector object. void generate(CodegenModel model) { if (model != null) { var calls = _generateGetters(_extractNames(model.getterNames)); @@ -35,9 +34,7 @@ class Codegen { } Iterable _extractNames(Iterable accessors) { - var names = accessors.where((accessor) { - return accessor.isStaticallyNecessary || !generateChangeDetectors; - }).map((accessor) => accessor.sanitizedName); + var names = accessors.map((accessor) => accessor.sanitizedName); var nameList = names.toList(); nameList.sort(); return nameList; diff --git a/modules_dart/transform/lib/src/transform/template_compiler/reflection/model.dart b/modules_dart/transform/lib/src/transform/template_compiler/reflection/model.dart index 7277ae8fc4..d0fd4aae0b 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/reflection/model.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/reflection/model.dart @@ -27,11 +27,7 @@ class ReflectiveAccessor { /// setter, or method on the `Component`. final String sanitizedName; - /// Whether this getter, setter, or method is still necessary when we have - /// pre-generated change detectors. - final bool isStaticallyNecessary; - - ReflectiveAccessor(String astValue, {this.isStaticallyNecessary}) + ReflectiveAccessor(String astValue) : this.astValue = astValue, this.sanitizedName = sanitizePropertyName(astValue); diff --git a/modules_dart/transform/lib/src/transform/template_compiler/reflection/processor.dart b/modules_dart/transform/lib/src/transform/template_compiler/reflection/processor.dart index bf1926f63d..0d245b0159 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/reflection/processor.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/reflection/processor.dart @@ -1,8 +1,6 @@ library angular2.transform.template_compiler.reflection.processor; -import 'package:angular2/src/core/change_detection/parser/ast.dart'; -import 'package:angular2/src/core/render/api.dart'; -import 'package:angular2/src/transform/template_compiler/view_definition_creator.dart'; +import 'package:angular2/src/compiler/directive_metadata.dart'; import 'model.dart'; @@ -16,109 +14,9 @@ class Processor implements CodegenModel { /// The names of all requested `method`s. final Set methodNames = new Set(); - _NgAstVisitor _visitor; - - Processor() { - _visitor = new _NgAstVisitor(this); - } - - void process(ViewDefinitionEntry viewDefEntry, ProtoViewDto protoViewDto) { - _processViewDefinition(viewDefEntry); - _processProtoViewDto(protoViewDto); - } - - /// Extracts the names of necessary getters from the events in host and - /// dependent [DirectiveMetadata]. - void _processViewDefinition(ViewDefinitionEntry viewDefEntry) { - // These are necessary even with generated change detectors. - if (viewDefEntry.hostMetadata != null && - viewDefEntry.hostMetadata.outputs != null) { - viewDefEntry.hostMetadata.outputs.forEach((eventName) { - getterNames.add( - new ReflectiveAccessor(eventName, isStaticallyNecessary: true)); - }); - } - } - - void _processProtoViewDto(ProtoViewDto protoViewDto) { - _visitor.isStaticallyNecessary = false; - - protoViewDto.textBindings.forEach((ast) => ast.visit(_visitor)); - protoViewDto.elementBinders.forEach((binder) { - binder.propertyBindings.forEach((binding) { - binding.astWithSource.visit(_visitor); - setterNames.add(new ReflectiveAccessor(binding.property, - isStaticallyNecessary: false)); - }); - - binder.directives.forEach((directiveBinding) { - directiveBinding.propertyBindings.values - .forEach((propBinding) => propBinding.visit(_visitor)); - directiveBinding.propertyBindings.keys.forEach((bindingName) { - setterNames.add(new ReflectiveAccessor(bindingName, - isStaticallyNecessary: false)); - }); - - directiveBinding.hostPropertyBindings.forEach((elementBinding) { - elementBinding.astWithSource.visit(_visitor); - setterNames.add(new ReflectiveAccessor(elementBinding.property, - isStaticallyNecessary: false)); - }); - }); - - binder.eventBindings - .forEach((eventBinding) => eventBinding.source.visit(_visitor)); - - binder.directives.forEach((directiveBinding) { - directiveBinding.eventBindings - .forEach((eventBinding) => eventBinding.source.visit(_visitor)); - }); - - if (binder.nestedProtoView != null) { - _processProtoViewDto(binder.nestedProtoView); - } + void process(CompileDirectiveMetadata meta) { + meta.events.keys.forEach((eventName) { + getterNames.add(new ReflectiveAccessor(eventName)); }); } } - -class _NgAstVisitor extends RecursiveAstVisitor { - final Processor _result; - - /// Whether any getters or setters recorded are necessary when running - /// statically. A getter or setter that is necessary only for change detection - /// is not necessary when running statically because all accesses are handled - /// by the dedicated change detector classes. - bool isStaticallyNecessary = false; - - _NgAstVisitor(this._result); - - visitMethodCall(MethodCall ast) { - _result.methodNames - .add(new ReflectiveAccessor(ast.name, isStaticallyNecessary: true)); - super.visitMethodCall(ast); - } - - visitPropertyRead(PropertyRead ast) { - _result.getterNames.add(new ReflectiveAccessor(ast.name, - isStaticallyNecessary: isStaticallyNecessary)); - super.visitPropertyRead(ast); - } - - visitPropertyWrite(PropertyWrite ast) { - _result.setterNames.add(new ReflectiveAccessor(ast.name, - isStaticallyNecessary: isStaticallyNecessary)); - super.visitPropertyWrite(ast); - } - - visitSafeMethodCall(SafeMethodCall ast) { - _result.methodNames - .add(new ReflectiveAccessor(ast.name, isStaticallyNecessary: true)); - super.visitSafeMethodCall(ast); - } - - visitSafePropertyRead(SafePropertyRead ast) { - _result.getterNames.add(new ReflectiveAccessor(ast.name, - isStaticallyNecessary: isStaticallyNecessary)); - super.visitSafePropertyRead(ast); - } -} diff --git a/modules_dart/transform/lib/src/transform/template_compiler/reflection/reflection_capabilities.dart b/modules_dart/transform/lib/src/transform/template_compiler/reflection/reflection_capabilities.dart index a7d8708de1..76fd1ab53e 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/reflection/reflection_capabilities.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/reflection/reflection_capabilities.dart @@ -29,8 +29,6 @@ class NullReflectionCapabilities implements ReflectionCapabilities { MethodFn method(String name) => _nullMethod; String importUri(Type type) => './'; - - String moduleId(Type type) => null; } _nullGetter(Object p) => null; diff --git a/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart b/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart index e938cb8aab..158a4758b4 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/transformer.dart @@ -30,6 +30,7 @@ class TemplateCompiler extends Transformer implements DeclaringTransformer { declareOutputs(DeclaringTransform transform) { transform.consumePrimary(); transform.declareOutput(transform.primaryId); + transform.declareOutput(templatesAssetId(transform.primaryId)); } @override @@ -38,13 +39,22 @@ class TemplateCompiler extends Transformer implements DeclaringTransformer { Html5LibDomAdapter.makeCurrent(); var primaryId = transform.primaryInput.id; var reader = new AssetReader.fromTransform(transform); - var transformedCode = formatter.format(await processTemplates( - reader, primaryId, - generateChangeDetectors: options.generateChangeDetectors, - reflectPropertiesAsAttributes: - options.reflectPropertiesAsAttributes)); + var outputs = await processTemplates(reader, primaryId, + reflectPropertiesAsAttributes: options.reflectPropertiesAsAttributes); transform.consumePrimary(); - transform.addOutput(new Asset.fromString(primaryId, transformedCode)); + var ngDepsCode = ''; + var templatesCode = ''; + if (outputs != null) { + if (outputs.ngDepsCode != null) { + ngDepsCode = formatter.format(outputs.ngDepsCode); + } + if (outputs.templatesCode != null) { + templatesCode = formatter.format(outputs.templatesCode); + } + } + transform.addOutput(new Asset.fromString(primaryId, ngDepsCode)); + transform.addOutput( + new Asset.fromString(templatesAssetId(primaryId), templatesCode)); }); } } diff --git a/modules_dart/transform/lib/src/transform/transformer.dart b/modules_dart/transform/lib/src/transform/transformer.dart index bcb55c478d..045e194d1a 100644 --- a/modules_dart/transform/lib/src/transform/transformer.dart +++ b/modules_dart/transform/lib/src/transform/transformer.dart @@ -1,14 +1,15 @@ -library angular2.transform; +library angular2.src.transform.transformer; import 'package:barback/barback.dart'; import 'package:dart_style/dart_style.dart'; import 'deferred_rewriter/transformer.dart'; import 'directive_linker/transformer.dart'; -import 'directive_metadata_extractor/transformer.dart'; +import 'directive_metadata_linker/transformer.dart'; import 'directive_processor/transformer.dart'; import 'bind_generator/transformer.dart'; import 'reflection_remover/transformer.dart'; +import 'stylesheet_compiler/transformer.dart'; import 'template_compiler/transformer.dart'; import 'common/formatter.dart' as formatter; import 'common/options.dart'; @@ -32,10 +33,14 @@ class AngularTransformerGroup extends TransformerGroup { phases.addAll(new List.generate( options.optimizationPhases, (_) => [new EmptyNgDepsRemover()])); phases.addAll([ - [new DirectiveLinker(), new DeferredRewriter(options)], - [new DirectiveMetadataExtractor()], + [ + new DeferredRewriter(options), + new DirectiveLinker(), + new DirectiveMetadataLinker() + ], [new BindGenerator(options)], - [new TemplateCompiler(options)] + [new TemplateCompiler(options)], + [new StylesheetCompiler()], ]); return new AngularTransformerGroup._(phases, formatCode: options.formatCode); diff --git a/modules_dart/transform/test/transform/bind_generator/all_tests.dart b/modules_dart/transform/test/transform/bind_generator/all_tests.dart index 0c6f8fdb93..3ec481d7a0 100644 --- a/modules_dart/transform/test/transform/bind_generator/all_tests.dart +++ b/modules_dart/transform/test/transform/bind_generator/all_tests.dart @@ -38,22 +38,12 @@ void allTests() { expect(output).toEqual(expected); }); - it('should generate a getter for a `events` property in an annotation.', - () async { - var inputPath = 'bind_generator/events_files/bar.ng_deps.dart'; - var expected = formatter.format( - readFile('bind_generator/events_files/expected/bar.ng_deps.dart')); - - var output = formatter.format( - await createNgSettersAndGetters(reader, new AssetId('a', inputPath))); - expect(output).toEqual(expected); - }); - it('should generate setters for queries defined in the class annotation.', () async { - var inputPath = 'bind_generator/queries_class_annotation_files/bar.ng_deps.dart'; - var expected = formatter.format( - readFile('bind_generator/queries_class_annotation_files/expected/bar.ng_deps.dart')); + var inputPath = + 'bind_generator/queries_class_annotation_files/bar.ng_deps.dart'; + var expected = formatter.format(readFile( + 'bind_generator/queries_class_annotation_files/expected/bar.ng_deps.dart')); var output = formatter.format( await createNgSettersAndGetters(reader, new AssetId('a', inputPath))); @@ -62,9 +52,10 @@ void allTests() { it('should generate setters for queries defined via prop annotations.', () async { - var inputPath = 'bind_generator/queries_prop_annotations_files/bar.ng_deps.dart'; - var expected = formatter.format( - readFile('bind_generator/queries_prop_annotations_files/expected/bar.ng_deps.dart')); + var inputPath = + 'bind_generator/queries_prop_annotations_files/bar.ng_deps.dart'; + var expected = formatter.format(readFile( + 'bind_generator/queries_prop_annotations_files/expected/bar.ng_deps.dart')); var output = formatter.format( await createNgSettersAndGetters(reader, new AssetId('a', inputPath))); diff --git a/modules_dart/transform/test/transform/bind_generator/events_files/bar.ng_deps.dart b/modules_dart/transform/test/transform/bind_generator/events_files/bar.ng_deps.dart deleted file mode 100644 index f13c4e686d..0000000000 --- a/modules_dart/transform/test/transform/bind_generator/events_files/bar.ng_deps.dart +++ /dev/null @@ -1,18 +0,0 @@ -library bar.ng_deps.dart; - -import 'bar.dart'; -import 'package:angular2/src/core/metadata.dart'; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - ToolTip, - new ReflectionInfo(const [ - const Directive( - selector: '[tool-tip]', - outputs: const ['onOpen', 'close: onClose']) - ], const [], () => new ToolTip())); -} diff --git a/modules_dart/transform/test/transform/bind_generator/events_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/bind_generator/events_files/expected/bar.ng_deps.dart deleted file mode 100644 index 70bf6c5ae2..0000000000 --- a/modules_dart/transform/test/transform/bind_generator/events_files/expected/bar.ng_deps.dart +++ /dev/null @@ -1,19 +0,0 @@ -library bar.ng_deps.dart; - -import 'bar.dart'; -import 'package:angular2/src/core/metadata.dart'; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - ToolTip, - new ReflectionInfo(const [ - const Directive( - selector: '[tool-tip]', - outputs: const ['onOpen', 'close: onClose']) - ], const [], () => new ToolTip())) - ..registerGetters({'onOpen': (o) => o.onOpen, 'close': (o) => o.close}); -} diff --git a/modules_dart/transform/test/transform/common/compile_directive_metadata/ng_for.ng_meta.dart b/modules_dart/transform/test/transform/common/compile_directive_metadata/ng_for.ng_meta.dart new file mode 100644 index 0000000000..2101fd35fe --- /dev/null +++ b/modules_dart/transform/test/transform/common/compile_directive_metadata/ng_for.ng_meta.dart @@ -0,0 +1,26 @@ +library angular2.test.transform.common.compile_directive_metadata; + +final ngFor = { + "NgFor": { + "kind": "type", + "value": { + "isComponent": false, + "dynamicLoadable": true, + "selector": "[ng-for][ng-for-of]", + "exportAs": null, + "type": { + "id": 9999, + "name": "NgFor", + "moduleUrl": "asset:angular2/lib/src/core/directives/ng_for.dart" + }, + "changeDetection": null, + "properties": {"ngForOf": "ngForOf"}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [2], + "template": null + } + } +}; diff --git a/modules_dart/transform/test/transform/common/ng_meta_test.dart b/modules_dart/transform/test/transform/common/ng_meta_test.dart index fca70c75a9..d7f5c1051f 100644 --- a/modules_dart/transform/test/transform/common/ng_meta_test.dart +++ b/modules_dart/transform/test/transform/common/ng_meta_test.dart @@ -1,6 +1,7 @@ library angular2.test.transform.common.annotation_matcher_test; import 'package:angular2/src/core/render/api.dart'; +import 'package:angular2/src/compiler/directive_metadata.dart'; import 'package:angular2/src/transform/common/ng_meta.dart'; import 'package:guinness/guinness.dart'; @@ -8,10 +9,10 @@ main() => allTests(); void allTests() { var mockData = [ - new RenderDirectiveMetadata(id: 'm1'), - new RenderDirectiveMetadata(id: 'm2'), - new RenderDirectiveMetadata(id: 'm3'), - new RenderDirectiveMetadata(id: 'm4') + CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N1')), + CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N2')), + CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N3')), + CompileDirectiveMetadata.create(type: new CompileTypeMetadata(name: 'N4')) ]; it('should allow empty data.', () { @@ -92,7 +93,7 @@ _checkSimilar(NgMeta a, NgMeta b) { expect(b.types).toContain(k); var at = a.types[k]; var bt = b.types[k]; - expect(at.id).toEqual(bt.id); + expect(at.type.name).toEqual(bt.type.name); } for (var k in a.aliases.keys) { expect(b.aliases).toContain(k); diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/adjacent_strings_files/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/adjacent_strings_files/foo.ng_deps.dart deleted file mode 100644 index 8503402ed6..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/adjacent_strings_files/foo.ng_deps.dart +++ /dev/null @@ -1,15 +0,0 @@ -library bar.ng_deps.dart; - -import 'foo.dart'; -import 'package:angular2/src/core/metadata.dart'; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - FooComponent, - new ReflectionInfo(const [const Component(selector: '[fo' 'o]')], - const [], () => new FooComponent())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/all_tests.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/all_tests.dart deleted file mode 100644 index d9b0a2c24b..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/all_tests.dart +++ /dev/null @@ -1,246 +0,0 @@ -library angular2.test.transform.directive_metadata_extractor.all_tests; - -import 'dart:async'; -import 'package:angular2/src/core/render/api.dart'; -import 'package:angular2/src/core/change_detection/change_detection.dart'; -import 'package:angular2/src/transform/common/convert.dart'; -import 'package:angular2/src/transform/common/directive_metadata_reader.dart'; -import 'package:angular2/src/transform/common/logging.dart'; -import 'package:angular2/src/transform/common/ng_deps.dart'; -import 'package:angular2/src/transform/directive_metadata_extractor/' - 'extractor.dart'; -import 'package:barback/barback.dart'; -import 'package:dart_style/dart_style.dart'; -import 'package:guinness/guinness.dart'; - -import '../common/read_file.dart'; - -var formatter = new DartFormatter(); - -main() => allTests(); - -void allTests() { - TestAssetReader reader = null; - - beforeEach(() { - reader = new TestAssetReader(); - }); - - Future readMetadata(inputPath) async { - var ngDeps = await NgDeps.parse(reader, new AssetId('a', inputPath)); - return ngDeps.registeredTypes.first.directiveMetadata; - } - - describe('readMetadata', () { - it('should parse selectors', () async { - var metadata = await readMetadata( - 'directive_metadata_extractor/directive_metadata_files/' - 'selector.ng_deps.dart'); - expect(metadata.selector).toEqual('hello-app'); - }); - - it('should parse compile children values', () async { - var ngDeps = await NgDeps.parse( - reader, - new AssetId( - 'a', - 'directive_metadata_extractor/' - 'directive_metadata_files/compile_children.ng_deps.dart')); - var it = ngDeps.registeredTypes.iterator; - - // Unset value defaults to `true`. - it.moveNext(); - expect('${it.current.typeName}').toEqual('UnsetComp'); - var unsetComp = it.current.directiveMetadata; - expect(unsetComp.compileChildren).toBeTrue(); - - it.moveNext(); - expect('${it.current.typeName}').toEqual('FalseComp'); - var falseComp = it.current.directiveMetadata; - expect(falseComp.compileChildren).toBeFalse(); - - it.moveNext(); - expect('${it.current.typeName}').toEqual('TrueComp'); - var trueComp = it.current.directiveMetadata; - expect(trueComp.compileChildren).toBeTrue(); - }); - - it('should parse inputs.', () async { - var metadata = await readMetadata('directive_metadata_extractor/' - 'directive_metadata_files/properties.ng_deps.dart'); - expect(metadata.inputs).toBeNotNull(); - expect(metadata.inputs.length).toBe(2); - expect(metadata.inputs).toContain('key1: val1'); - expect(metadata.inputs).toContain('key2: val2'); - }); - - it('should parse exportAs.', () async { - var metadata = await readMetadata('directive_metadata_extractor/' - 'directive_metadata_files/directive_export_as.ng_deps.dart'); - expect(metadata.exportAs).toEqual('exportAsName'); - }); - - it('should parse host.', () async { - var metadata = await readMetadata('directive_metadata_extractor/' - 'directive_metadata_files/host_listeners.ng_deps.dart'); - expect(metadata.hostListeners).toBeNotNull(); - expect(metadata.hostListeners.length).toBe(1); - expect(metadata.hostListeners).toContain('change'); - expect(metadata.hostListeners['change']).toEqual('onChange(\$event)'); - - expect(metadata.hostProperties).toBeNotNull(); - expect(metadata.hostProperties.length).toBe(1); - expect(metadata.hostProperties).toContain('value'); - expect(metadata.hostProperties['value']).toEqual('value'); - - expect(metadata.hostAttributes).toBeNotNull(); - expect(metadata.hostAttributes.length).toBe(1); - expect(metadata.hostAttributes).toContain('attName'); - expect(metadata.hostAttributes['attName']).toEqual('attValue'); - }); - - it('should parse lifecycle events.', () async { - var metadata = await readMetadata('directive_metadata_extractor/' - 'directive_metadata_files/lifecycle.ng_deps.dart'); - expect(metadata.callOnDestroy).toBe(true); - expect(metadata.callOnChanges).toBe(true); - expect(metadata.callDoCheck).toBe(true); - expect(metadata.callOnInit).toBe(true); - expect(metadata.callAfterContentInit).toBe(true); - expect(metadata.callAfterContentChecked).toBe(true); - expect(metadata.callAfterViewInit).toBe(true); - expect(metadata.callAfterViewChecked).toBe(true); - }); - - it('should parse outputs.', () async { - var metadata = await readMetadata('directive_metadata_extractor/' - 'directive_metadata_files/events.ng_deps.dart'); - expect(metadata.outputs).toEqual(['onFoo', 'onBar']); - }); - - it('should parse changeDetection.', () async { - var metadata = await readMetadata('directive_metadata_extractor/' - 'directive_metadata_files/changeDetection.ng_deps.dart'); - expect(metadata.changeDetection) - .toEqual(ChangeDetectionStrategy.CheckOnce); - }); - - it('should fail when a class is annotated with multiple Directives.', - () async { - var ngDeps = await NgDeps.parse( - reader, - new AssetId( - 'a', - 'directive_metadata_extractor/' - 'directive_metadata_files/too_many_directives.ng_deps.dart')); - expect(() => ngDeps.registeredTypes.first.directiveMetadata) - .toThrowWith(anInstanceOf: PrintLoggerError); - }); - }); - - describe('extractMetadata', () { - it('should generate `DirectiveMetadata` from .ng_deps.dart files.', - () async { - var extracted = await extractDirectiveMetadata( - reader, - new AssetId('a', - 'directive_metadata_extractor/simple_files/foo.ng_deps.dart')); - expect(extracted.types).toContain('FooComponent'); - - var extractedMeta = extracted.types['FooComponent']; - expect(extractedMeta.selector).toEqual('[foo]'); - }); - - it( - 'should generate `DirectiveMetadata` from .ng_deps.dart files that use ' - 'automatic adjacent string concatenation.', () async { - var extracted = await extractDirectiveMetadata( - reader, - new AssetId( - 'a', - 'directive_metadata_extractor/adjacent_strings_files/' - 'foo.ng_deps.dart')); - expect(extracted.types).toContain('FooComponent'); - - var extractedMeta = extracted.types['FooComponent']; - expect(extractedMeta.selector).toEqual('[foo]'); - }); - - it('should include `DirectiveMetadata` from exported files.', () async { - var extracted = await extractDirectiveMetadata( - reader, - new AssetId('a', - 'directive_metadata_extractor/export_files/foo.ng_deps.dart')); - expect(extracted.types).toContain('FooComponent'); - expect(extracted.types).toContain('BarComponent'); - - expect(extracted.types['FooComponent'].selector).toEqual('[foo]'); - expect(extracted.types['BarComponent'].selector).toEqual('[bar]'); - }); - - it('should include `DirectiveMetadata` recursively from exported files.', - () async { - var extracted = await extractDirectiveMetadata( - reader, - new AssetId('a', - 'directive_metadata_extractor/recursive_export_files/foo.ng_deps.dart')); - expect(extracted.types).toContain('FooComponent'); - expect(extracted.types).toContain('BarComponent'); - expect(extracted.types).toContain('BazComponent'); - - expect(extracted.types['FooComponent'].selector).toEqual('[foo]'); - expect(extracted.types['BarComponent'].selector).toEqual('[bar]'); - expect(extracted.types['BazComponent'].selector).toEqual('[baz]'); - }); - - it('should handle `DirectiveMetadata` export cycles gracefully.', () async { - var extracted = await extractDirectiveMetadata( - reader, - new AssetId('a', - 'directive_metadata_extractor/export_cycle_files/baz.ng_deps.dart')); - expect(extracted.types).toContain('FooComponent'); - expect(extracted.types).toContain('BarComponent'); - expect(extracted.types).toContain('BazComponent'); - - expect(extracted.types['FooComponent'].selector).toEqual('[foo]'); - expect(extracted.types['BarComponent'].selector).toEqual('[bar]'); - expect(extracted.types['BazComponent'].selector).toEqual('[baz]'); - }); - - it( - 'should include `DirectiveMetadata` from exported files ' - 'expressed as absolute uris', () async { - reader.addAsset( - new AssetId('bar', 'lib/bar.ng_deps.dart'), - readFile( - 'directive_metadata_extractor/absolute_export_files/bar.ng_deps.dart')); - - var extracted = await extractDirectiveMetadata( - reader, - new AssetId('a', - 'directive_metadata_extractor/absolute_export_files/foo.ng_deps.dart')); - expect(extracted.types).toContain('FooComponent'); - expect(extracted.types).toContain('BarComponent'); - - expect(extracted.types['FooComponent'].selector).toEqual('[foo]'); - expect(extracted.types['BarComponent'].selector).toEqual('[bar]'); - }); - - it('should include directive aliases', () async { - reader.addAsset( - new AssetId('bar', 'lib/bar.ng_deps.dart'), - readFile( - 'directive_metadata_extractor/directive_aliases_files/bar.ng_deps.dart')); - - var extracted = await extractDirectiveMetadata( - reader, - new AssetId('a', - 'directive_metadata_extractor/directive_aliases_files/foo.ng_deps.dart')); - expect(extracted.aliases).toContain('alias1'); - expect(extracted.aliases).toContain('alias2'); - expect(extracted.aliases['alias1']).toContain('BarComponent'); - expect(extracted.aliases['alias2']).toContain('FooComponent'); - expect(extracted.aliases['alias2']).toContain('alias1'); - }); - }); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/bar.aliases.json b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/bar.aliases.json deleted file mode 100644 index 3db1b66e68..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/bar.aliases.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "alias1": { - "kind": "alias", - "value": [ - "BarComponent" - ] - } -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/foo.aliases.json b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/foo.aliases.json deleted file mode 100644 index 3e205d4acc..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/foo.aliases.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "alias2": { - "kind": "alias", - "value": [ - "FooComponent", - "alias1" - ] - } -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/changeDetection.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/changeDetection.ng_deps.dart deleted file mode 100644 index 1cc03c2dbb..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/changeDetection.ng_deps.dart +++ /dev/null @@ -1,19 +0,0 @@ -library examples.hello_world.index_common_dart.ng_deps.dart; - -import 'hello.dart'; -import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement, ChangeDetectionStrategy; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - HelloCmp, - new ReflectionInfo(const [ - const Component(changeDetection: ChangeDetectionStrategy.CheckOnce) - ], const [ - const [] - ], () => new HelloCmp())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/compile_children.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/compile_children.ng_deps.dart deleted file mode 100644 index 737a09c413..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/compile_children.ng_deps.dart +++ /dev/null @@ -1,23 +0,0 @@ -library examples.hello_world.index_common_dart.ng_deps.dart; - -import 'hello.dart'; -import 'package:angular2/angular2.dart'; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - UnsetComp, - new ReflectionInfo( - const [const Directive()], const [const []], () => new UnsetComp())) - ..registerType( - FalseComp, - new ReflectionInfo(const [const Directive(compileChildren: false)], - const [const []], () => new FalseComp())) - ..registerType( - TrueComp, - new ReflectionInfo(const [const Directive(compileChildren: true)], - const [const []], () => new TrueComp())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/directive_export_as.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/directive_export_as.ng_deps.dart deleted file mode 100644 index f6dadffb46..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/directive_export_as.ng_deps.dart +++ /dev/null @@ -1,16 +0,0 @@ -library examples.hello_world.index_common_dart.ng_deps.dart; - -import 'hello.dart'; -import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - HelloCmp, - new ReflectionInfo(const [const Directive(exportAs: 'exportAsName')], - const [const []], () => new HelloCmp())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/events.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/events.ng_deps.dart deleted file mode 100644 index 155e1950f3..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/events.ng_deps.dart +++ /dev/null @@ -1,19 +0,0 @@ -library examples.hello_world.index_common_dart.ng_deps.dart; - -import 'hello.dart'; -import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - HelloCmp, - new ReflectionInfo(const [ - const Component(outputs: const ['onFoo', 'onBar']) - ], const [ - const [] - ], () => new HelloCmp())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/host_listeners.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/host_listeners.ng_deps.dart deleted file mode 100644 index cdf2116132..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/host_listeners.ng_deps.dart +++ /dev/null @@ -1,23 +0,0 @@ -library examples.hello_world.index_common_dart.ng_deps.dart; - -import 'hello.dart'; -import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - HelloCmp, - new ReflectionInfo(const [ - const Component(host: const { - '(change)': 'onChange(\$event)', - '[value]': 'value', - 'attName': 'attValue' - }) - ], const [ - const [] - ], () => new HelloCmp())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/lifecycle.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/lifecycle.ng_deps.dart deleted file mode 100644 index 20b0483fe9..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/lifecycle.ng_deps.dart +++ /dev/null @@ -1,40 +0,0 @@ -library examples.hello_world.index_common_dart.ng_deps.dart; - -import 'hello.dart'; -import 'package:angular2/angular2.dart' - show - Component, - Directive, - View, - NgElement, - OnChanges, - OnDestroy, - OnInit, - DoCheck, - AfterContentInit, - AfterContentChecked, - AfterViewInit, - AfterViewChecked; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - HelloCmp, - new ReflectionInfo( - const [const Component()], - const [const []], - () => new HelloCmp(), - const [ - OnChanges, - OnDestroy, - OnInit, - DoCheck, - AfterContentInit, - AfterContentChecked, - AfterViewInit, - AfterViewChecked - ])); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/properties.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/properties.ng_deps.dart deleted file mode 100644 index 335a1c43e5..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/properties.ng_deps.dart +++ /dev/null @@ -1,19 +0,0 @@ -library examples.hello_world.index_common_dart.ng_deps.dart; - -import 'hello.dart'; -import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - HelloCmp, - new ReflectionInfo(const [ - const Component(inputs: const ['key1: val1', 'key2: val2']) - ], const [ - const [] - ], () => new HelloCmp())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/selector.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/selector.ng_deps.dart deleted file mode 100644 index fb87b628e9..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/selector.ng_deps.dart +++ /dev/null @@ -1,16 +0,0 @@ -library examples.hello_world.index_common_dart.ng_deps.dart; - -import 'hello.dart'; -import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - HelloCmp, - new ReflectionInfo(const [const Component(selector: 'hello-app')], - const [const []], () => new HelloCmp())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/too_many_directives.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/too_many_directives.ng_deps.dart deleted file mode 100644 index 1103ff4124..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_metadata_files/too_many_directives.ng_deps.dart +++ /dev/null @@ -1,20 +0,0 @@ -library examples.hello_world.index_common_dart.ng_deps.dart; - -import 'hello.dart'; -import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - HelloCmp, - new ReflectionInfo(const [ - const Component(selector: 'hello-app'), - const Component(selector: 'goodbye-app') - ], const [ - const [] - ], () => new HelloCmp())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/export_files/bar.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/export_files/bar.ng_deps.dart deleted file mode 100644 index 9a4a5d0cad..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/export_files/bar.ng_deps.dart +++ /dev/null @@ -1,15 +0,0 @@ -library foo.ng_deps.dart; - -import 'bar.dart'; -import 'package:angular2/src/core/metadata.dart'; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - BarComponent, - new ReflectionInfo(const [const Component(selector: '[bar]')], const [], - () => new BarComponent())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/recursive_export_files/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/recursive_export_files/foo.ng_deps.dart deleted file mode 100644 index 542f008d16..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/recursive_export_files/foo.ng_deps.dart +++ /dev/null @@ -1,19 +0,0 @@ -library foo.ng_deps.dart; - -import 'foo.dart'; -import 'package:angular2/src/core/metadata.dart'; - -export 'bar.dart'; -import 'bar.ng_deps.dart' as i0; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - FooComponent, - new ReflectionInfo(const [const Component(selector: '[foo]')], const [], - () => new FooComponent())); - i0.initReflector(reflector); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/simple_files/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_extractor/simple_files/foo.ng_deps.dart deleted file mode 100644 index a69adeee64..0000000000 --- a/modules_dart/transform/test/transform/directive_metadata_extractor/simple_files/foo.ng_deps.dart +++ /dev/null @@ -1,15 +0,0 @@ -library bar.ng_deps.dart; - -import 'foo.dart'; -import 'package:angular2/src/core/metadata.dart'; - -var _visited = false; -void initReflector(reflector) { - if (_visited) return; - _visited = true; - reflector - ..registerType( - FooComponent, - new ReflectionInfo(const [const Component(selector: '[foo]')], const [], - () => new FooComponent())); -} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/absolute_export_files/bar.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/bar.ng_deps.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_metadata_extractor/absolute_export_files/bar.ng_deps.dart rename to modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/bar.ng_deps.dart diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/bar.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/bar.ng_meta.json new file mode 100644 index 0000000000..48da22d31c --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/bar.ng_meta.json @@ -0,0 +1,32 @@ +{ + "BarComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[bar]", + "exportAs": null, + "type": { + "id": 1, + "name": "BarComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/absolute_export_files/bar.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Bar", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/absolute_export_files/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/foo.ng_deps.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_metadata_extractor/absolute_export_files/foo.ng_deps.dart rename to modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/foo.ng_deps.dart diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/foo.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/foo.ng_meta.json new file mode 100644 index 0000000000..aa86cfbb12 --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/absolute_export_files/foo.ng_meta.json @@ -0,0 +1,33 @@ +{ + "__exports__": ["bar.dart"], + "FooComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[foo]", + "exportAs": null, + "type": { + "id": 1, + "name": "FooComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/absolute_export_files/foo.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Foo", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/all_tests.dart b/modules_dart/transform/test/transform/directive_metadata_linker/all_tests.dart new file mode 100644 index 0000000000..57f3c6a6be --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/all_tests.dart @@ -0,0 +1,79 @@ +library angular2.test.transform.directive_metadata_linker.all_tests; + +import 'dart:async'; +import 'package:angular2/src/core/render/api.dart'; +import 'package:angular2/src/core/change_detection/change_detection.dart'; +import 'package:angular2/src/transform/common/convert.dart'; +import 'package:angular2/src/transform/common/directive_metadata_reader.dart'; +import 'package:angular2/src/transform/common/logging.dart'; +import 'package:angular2/src/transform/common/ng_deps.dart'; +import 'package:angular2/src/transform/directive_metadata_linker/' + 'linker.dart'; +import 'package:barback/barback.dart'; +import 'package:dart_style/dart_style.dart'; +import 'package:guinness/guinness.dart'; + +import '../common/read_file.dart'; + +var formatter = new DartFormatter(); + +main() => allTests(); + +void allTests() { + TestAssetReader reader = null; + + beforeEach(() { + reader = new TestAssetReader(); + }); + + it('should include `DirectiveMetadata` from exported files.', () async { + var extracted = await linkDirectiveMetadata( + reader, + new AssetId( + 'a', 'directive_metadata_linker/export_files/foo.ng_meta.json')); + expect(extracted.types).toContain('FooComponent'); + expect(extracted.types).toContain('BarComponent'); + + expect(extracted.types['FooComponent'].selector).toEqual('[foo]'); + expect(extracted.types['BarComponent'].selector).toEqual('[bar]'); + }); + + it('should include `DirectiveMetadata` recursively from exported files.', + () async { + var extracted = await linkDirectiveMetadata( + reader, + new AssetId('a', + 'directive_metadata_linker/recursive_export_files/foo.ng_meta.json')); + expect(extracted.types).toContain('FooComponent'); + expect(extracted.types).toContain('BarComponent'); + expect(extracted.types).toContain('BazComponent'); + + expect(extracted.types['FooComponent'].selector).toEqual('[foo]'); + expect(extracted.types['BarComponent'].selector).toEqual('[bar]'); + expect(extracted.types['BazComponent'].selector).toEqual('[baz]'); + }); + + it('should handle `DirectiveMetadata` export cycles gracefully.', () async { + var extracted = await linkDirectiveMetadata( + reader, + new AssetId('a', + 'directive_metadata_linker/export_cycle_files/baz.ng_meta.json')); + expect(extracted.types).toContain('FooComponent'); + expect(extracted.types).toContain('BarComponent'); + expect(extracted.types).toContain('BazComponent'); + }); + + it( + 'should include `DirectiveMetadata` from exported files ' + 'expressed as absolute uris', () async { + var extracted = await linkDirectiveMetadata( + reader, + new AssetId('a', + 'directive_metadata_linker/absolute_export_files/foo.ng_meta.json')); + expect(extracted.types).toContain('FooComponent'); + expect(extracted.types).toContain('BarComponent'); + + expect(extracted.types['FooComponent'].selector).toEqual('[foo]'); + expect(extracted.types['BarComponent'].selector).toEqual('[bar]'); + }); +} diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/bar.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/bar.ng_meta.json new file mode 100644 index 0000000000..be82f3fbce --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/bar.ng_meta.json @@ -0,0 +1,33 @@ +{ + "__exports__": ["baz.dart"], + "BarComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[bar]", + "exportAs": null, + "type": { + "id": 1, + "name": "BarComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/export_cycle_files/bar.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Bar", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/baz.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/baz.ng_meta.json new file mode 100644 index 0000000000..9a3f4f90f7 --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/baz.ng_meta.json @@ -0,0 +1,33 @@ +{ + "__exports__": ["foo.dart"], + "BazComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[baz]", + "exportAs": null, + "type": { + "id": 1, + "name": "BazComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/export_cycle_files/baz.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Baz", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/foo.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/foo.ng_meta.json new file mode 100644 index 0000000000..ad35333bcb --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/export_cycle_files/foo.ng_meta.json @@ -0,0 +1,33 @@ +{ + "__exports__": ["bar.dart"], + "FooComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[foo]", + "exportAs": null, + "type": { + "id": 1, + "name": "FooComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/export_cycle_files/foo.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Foo", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/bar.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_linker/export_files/bar.ng_deps.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/bar.ng_deps.dart rename to modules_dart/transform/test/transform/directive_metadata_linker/export_files/bar.ng_deps.dart diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/export_files/bar.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/export_files/bar.ng_meta.json new file mode 100644 index 0000000000..5a4283cfa1 --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/export_files/bar.ng_meta.json @@ -0,0 +1,32 @@ +{ + "BarComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[bar]", + "exportAs": null, + "type": { + "id": 1, + "name": "BarComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/export_cycle_files/bar.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Bar", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_linker/export_files/foo.ng_deps.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_metadata_extractor/directive_aliases_files/foo.ng_deps.dart rename to modules_dart/transform/test/transform/directive_metadata_linker/export_files/foo.ng_deps.dart diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/export_files/foo.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/export_files/foo.ng_meta.json new file mode 100644 index 0000000000..ad35333bcb --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/export_files/foo.ng_meta.json @@ -0,0 +1,33 @@ +{ + "__exports__": ["bar.dart"], + "FooComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[foo]", + "exportAs": null, + "type": { + "id": 1, + "name": "FooComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/export_cycle_files/foo.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Foo", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/recursive_export_files/bar.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/bar.ng_deps.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_metadata_extractor/recursive_export_files/bar.ng_deps.dart rename to modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/bar.ng_deps.dart diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/bar.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/bar.ng_meta.json new file mode 100644 index 0000000000..7b758c2f7c --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/bar.ng_meta.json @@ -0,0 +1,33 @@ +{ + "__exports__": ["baz.dart"], + "BarComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[bar]", + "exportAs": null, + "type": { + "id": 1, + "name": "BarComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/recursive_export_files/bar.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Bar", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/recursive_export_files/baz.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/baz.ng_deps.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_metadata_extractor/recursive_export_files/baz.ng_deps.dart rename to modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/baz.ng_deps.dart diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/baz.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/baz.ng_meta.json new file mode 100644 index 0000000000..3500ba1494 --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/baz.ng_meta.json @@ -0,0 +1,32 @@ +{ + "BazComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[baz]", + "exportAs": null, + "type": { + "id": 1, + "name": "BazComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/recursive_export_files/baz.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Baz", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} diff --git a/modules_dart/transform/test/transform/directive_metadata_extractor/export_files/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/foo.ng_deps.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_metadata_extractor/export_files/foo.ng_deps.dart rename to modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/foo.ng_deps.dart diff --git a/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/foo.ng_meta.json b/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/foo.ng_meta.json new file mode 100644 index 0000000000..ae76ec6763 --- /dev/null +++ b/modules_dart/transform/test/transform/directive_metadata_linker/recursive_export_files/foo.ng_meta.json @@ -0,0 +1,33 @@ +{ + "__exports__": ["bar.dart"], + "FooComponent": + { + "kind": "type", + "value": { + "isComponent": true, + "dynamicLoadable": true, + "selector":"[foo]", + "exportAs": null, + "type": { + "id": 1, + "name": "FooComponent", + "moduleUrl": "asset:angular2/test/transform/directive_metadata_linker/recursive_export_files/foo.dart" + }, + "changeDetection": 5, + "properties": {}, + "events": {}, + "hostListeners": {}, + "hostProperties": {}, + "hostAttributes": {}, + "lifecycleHooks": [], + "template": { + "encapsulation": 0, + "template": "Foo", + "templateUrl": null, + "styles": null, + "styleUrls": null, + "ngContentSelectors": null + } + } + } +} 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 a87a486c3e..25ff2be434 100644 --- a/modules_dart/transform/test/transform/directive_processor/all_tests.dart +++ b/modules_dart/transform/test/transform/directive_processor/all_tests.dart @@ -4,6 +4,9 @@ import 'dart:async'; import 'dart:convert'; import 'package:barback/barback.dart'; +import 'package:angular2/src/core/change_detection/change_detection.dart'; +import 'package:angular2/src/core/compiler/interfaces.dart' show LifecycleHooks; +import 'package:angular2/src/core/dom/html_adapter.dart'; import 'package:angular2/src/transform/directive_processor/rewriter.dart'; import 'package:angular2/src/transform/common/annotation_matcher.dart'; import 'package:angular2/src/transform/common/asset_reader.dart'; @@ -14,13 +17,13 @@ import 'package:angular2/src/transform/common/ng_meta.dart'; import 'package:code_transformers/messages/build_logger.dart'; import 'package:dart_style/dart_style.dart'; import 'package:guinness/guinness.dart'; -import 'package:path/path.dart' as path; import 'package:source_span/source_span.dart'; import '../common/read_file.dart'; var formatter = new DartFormatter(); main() { + Html5LibDomAdapter.makeCurrent(); allTests(); } @@ -122,111 +125,6 @@ void allTests() { }); }); - describe('inliner', () { - var absoluteReader; - beforeEach(() { - absoluteReader = new TestAssetReader(); - }); - - it('should inline `templateUrl` values', () async { - var model = await _testCreateModel('url_expression_files/hello.dart'); - expect(model.reflectables.isNotEmpty).toBeTrue(); - var view = - model.reflectables.first.annotations.firstWhere((a) => a.isView); - expect(view.namedParameters - .firstWhere((p) => p.name == 'templateUrl') - .value).toContain('template.html'); - expect(view.namedParameters.firstWhere((p) => p.name == 'template').value) - .toContain('{{greeting}}'); - }); - - it( - 'should inline `templateUrl` and `styleUrls` values expressed as ' - 'absolute urls.', () async { - absoluteReader.addAsset( - new AssetId('other_package', 'lib/template.html'), - readFile( - 'directive_processor/absolute_url_expression_files/template.html')); - absoluteReader.addAsset( - new AssetId('other_package', 'lib/template.css'), - readFile( - 'directive_processor/absolute_url_expression_files/template.css')); - var model = await _testCreateModel( - 'absolute_url_expression_files/hello.dart', - reader: absoluteReader); - - expect(model.reflectables.length).toEqual(2); - var view = - model.reflectables.first.annotations.firstWhere((a) => a.isView); - expect(view.namedParameters - .firstWhere((p) => p.name == 'templateUrl') - .value).toContain('package:other_package/template.html'); - expect(view.namedParameters.firstWhere((p) => p.name == 'template').value) - .toContain('{{greeting}}'); - expect(view.namedParameters.firstWhere((p) => p.name == 'styles').value) - .toContain('.greeting { .color: blue; }'); - - // TODO(kegluneq): Split this test out, as it is logically very different. - expect(model.reflectables[1].isFunction).toBeTrue(); - expect(model.reflectables[1].name).toEqual('hello'); - }); - - it('should inline multiple `styleUrls` values expressed as absolute urls.', - () async { - var model = - await _testCreateModel('multiple_style_urls_files/hello.dart'); - - expect(model.reflectables.isNotEmpty).toBeTrue(); - var view = - model.reflectables.first.annotations.firstWhere((a) => a.isView); - var expectStyles = expect( - view.namedParameters.firstWhere((p) => p.name == 'styles').value); - expectStyles - ..toContain('.greeting { .color: blue; }') - ..toContain('.hello { .color: red; }'); - }); - - it( - 'should not inline multiple `styleUrls` values expressed as absolute ' - 'urls.', () async { - absoluteReader.addAsset( - new AssetId('a', 'lib/template.html'), - readFile( - 'directive_processor/multiple_style_urls_files/template.html')); - absoluteReader.addAsset( - new AssetId('a', 'lib/template.css'), - readFile( - 'directive_processor/multiple_style_urls_files/template.css')); - absoluteReader.addAsset( - new AssetId('a', 'lib/template_other.css'), - readFile( - 'directive_processor/multiple_style_urls_files/template_other.css')); - var model = await _testCreateModel( - 'multiple_style_urls_not_inlined_files/hello.dart', - inlineViews: false, - reader: absoluteReader); - expect(model.reflectables.isNotEmpty).toBeTrue(); - var view = - model.reflectables.first.annotations.firstWhere((a) => a.isView); - expect(view.namedParameters.firstWhere((p) => p.name == 'styles', - orElse: () => null)).toBeNull(); - expect( - view.namedParameters.firstWhere((p) => p.name == 'styleUrls').value) - ..toContain('package:a/template.css') - ..toContain('package:a/template_other.css'); - }); - - it('should inline `templateUrl`s expressed as adjacent strings.', () async { - var model = - await _testCreateModel('split_url_expression_files/hello.dart'); - expect(model.reflectables.isNotEmpty).toBeTrue(); - var view = - model.reflectables.first.annotations.firstWhere((a) => a.isView); - expect(view.namedParameters.firstWhere((p) => p.name == 'template').value) - .toContain('{{greeting}}'); - }); - }); - describe('interfaces', () { it('should include implemented types', () async { var model = await _testCreateModel('interfaces_files/soup.dart'); @@ -353,17 +251,8 @@ void allTests() { await _testCreateModel('invalid_url_files/hello.dart', logger: logger); expect(logger.hasErrors).toBeTrue(); expect(logger.logs) - ..toContain( - 'ERROR: Uri /bad/absolute/url.html not supported from angular2|test/' - 'transform/directive_processor/invalid_url_files/hello.dart, could not ' - 'build AssetId') - ..toContain( - 'ERROR: Could not read asset at uri package:invalid/package.css from ' - 'angular2|test/transform/directive_processor/invalid_url_files/' - 'hello.dart') - ..toContain( - 'ERROR: Could not read asset at uri bad_relative_url.css from angular2|' - 'test/transform/directive_processor/invalid_url_files/hello.dart'); + ..toContain('ERROR: ERROR: Invalid argument (url): ' + '"Could not read asset at uri asset:/bad/absolute/url.html"'); }); it('should find and register static functions.', () async { @@ -375,15 +264,16 @@ void allTests() { expect(functionReflectable.name).toEqual('getMessage'); }); - it('should find direcive aliases patterns.', () async { - var logger = new RecordingLogger(); - return log.setZoned(logger, () async { - var inputId = _assetIdForPath('directive_aliases_files/hello.dart'); - var reader = new TestAssetReader(); + describe('NgMeta', () { + var fakeReader; + beforeEach(() { + fakeReader = new TestAssetReader(); + }); + it('should find direcive aliases patterns.', () async { var ngMeta = new NgMeta.empty(); - await createNgDeps(reader, inputId, new AnnotationMatcher(), ngMeta, - inlineViews: true); + await _testCreateModel('directive_aliases_files/hello.dart', + ngMeta: ngMeta); expect(ngMeta.aliases).toContain('alias1'); expect(ngMeta.aliases['alias1']).toContain('HelloCmp'); @@ -391,6 +281,121 @@ void allTests() { expect(ngMeta.aliases).toContain('alias2'); expect(ngMeta.aliases['alias2'])..toContain('HelloCmp')..toContain('Foo'); }); + + it('should include hooks for implemented types (single)', () async { + var ngMeta = new NgMeta.empty(); + await _testCreateModel('interfaces_files/soup.dart', ngMeta: ngMeta); + + expect(ngMeta.types.isNotEmpty).toBeTrue(); + expect(ngMeta.types['ChangingSoupComponent']).toBeNotNull(); + expect(ngMeta.types['ChangingSoupComponent'].selector).toEqual('[soup]'); + expect(ngMeta.types['ChangingSoupComponent'].lifecycleHooks) + .toContain(LifecycleHooks.OnChanges); + }); + + it('should include hooks for implemented types (many)', () async { + var ngMeta = new NgMeta.empty(); + await _testCreateModel('multiple_interface_lifecycle_files/soup.dart', + ngMeta: ngMeta); + + expect(ngMeta.types.isNotEmpty).toBeTrue(); + expect(ngMeta.types['MultiSoupComponent']).toBeNotNull(); + expect(ngMeta.types['MultiSoupComponent'].selector).toEqual('[soup]'); + expect(ngMeta.types['MultiSoupComponent'].lifecycleHooks) + ..toContain(LifecycleHooks.OnChanges) + ..toContain(LifecycleHooks.OnDestroy) + ..toContain(LifecycleHooks.OnInit); + }); + + it('should create type entries for Directives', () async { + fakeReader + ..addAsset(new AssetId('other_package', 'lib/template.html'), '') + ..addAsset(new AssetId('other_package', 'lib/template.css'), ''); + var ngMeta = new NgMeta.empty(); + await _testCreateModel('absolute_url_expression_files/hello.dart', + ngMeta: ngMeta, reader: fakeReader); + + expect(ngMeta.types.isNotEmpty).toBeTrue(); + expect(ngMeta.types['HelloCmp']).toBeNotNull(); + expect(ngMeta.types['HelloCmp'].selector).toEqual('hello-app'); + }); + + it('should populate all provided values for Components & Directives', + () async { + var ngMeta = new NgMeta.empty(); + await _testCreateModel('unusual_component_files/hello.dart', + ngMeta: ngMeta); + + expect(ngMeta.types.isNotEmpty).toBeTrue(); + + var component = ngMeta.types['UnusualComp']; + expect(component).toBeNotNull(); + expect(component.selector).toEqual('unusual-comp'); + expect(component.isComponent).toBeTrue(); + expect(component.exportAs).toEqual('ComponentExportAsValue'); + expect(component.changeDetection) + .toEqual(ChangeDetectionStrategy.CheckAlways); + expect(component.properties).toContain('aProperty'); + expect(component.properties['aProperty']).toEqual('aProperty'); + expect(component.events).toContain('anEvent'); + expect(component.events['anEvent']).toEqual('anEvent'); + expect(component.hostAttributes).toContain('hostKey'); + expect(component.hostAttributes['hostKey']).toEqual('hostValue'); + + var directive = ngMeta.types['UnusualDirective']; + expect(directive).toBeNotNull(); + expect(directive.selector).toEqual('unusual-directive'); + expect(directive.isComponent).toBeFalse(); + expect(directive.exportAs).toEqual('DirectiveExportAsValue'); + expect(directive.properties).toContain('aDirectiveProperty'); + expect(directive.properties['aDirectiveProperty']) + .toEqual('aDirectiveProperty'); + expect(directive.events).toContain('aDirectiveEvent'); + expect(directive.events['aDirectiveEvent']).toEqual('aDirectiveEvent'); + expect(directive.hostAttributes).toContain('directiveHostKey'); + expect(directive.hostAttributes['directiveHostKey']) + .toEqual('directiveHostValue'); + }); + + it('should include hooks for implemented types (single)', () async { + var ngMeta = new NgMeta.empty(); + await _testCreateModel('interfaces_files/soup.dart', ngMeta: ngMeta); + + expect(ngMeta.types.isNotEmpty).toBeTrue(); + expect(ngMeta.types['ChangingSoupComponent']).toBeNotNull(); + expect(ngMeta.types['ChangingSoupComponent'].selector).toEqual('[soup]'); + expect(ngMeta.types['ChangingSoupComponent'].lifecycleHooks) + .toContain(LifecycleHooks.OnChanges); + }); + + it('should include hooks for implemented types (many)', () async { + var ngMeta = new NgMeta.empty(); + await _testCreateModel('multiple_interface_lifecycle_files/soup.dart', + ngMeta: ngMeta); + + expect(ngMeta.types.isNotEmpty).toBeTrue(); + expect(ngMeta.types['MultiSoupComponent']).toBeNotNull(); + expect(ngMeta.types['MultiSoupComponent'].selector).toEqual('[soup]'); + expect(ngMeta.types['MultiSoupComponent'].lifecycleHooks) + ..toContain(LifecycleHooks.OnChanges) + ..toContain(LifecycleHooks.OnDestroy) + ..toContain(LifecycleHooks.OnInit); + }); + + it('should parse templates from View annotations', () async { + fakeReader + ..addAsset(new AssetId('other_package', 'lib/template.html'), '') + ..addAsset(new AssetId('other_package', 'lib/template.css'), ''); + var ngMeta = new NgMeta.empty(); + await _testCreateModel('absolute_url_expression_files/hello.dart', + ngMeta: ngMeta, reader: fakeReader); + + expect(ngMeta.types.isNotEmpty).toBeTrue(); + expect(ngMeta.types['HelloCmp']).toBeNotNull(); + expect(ngMeta.types['HelloCmp'].template).toBeNotNull(); + expect(ngMeta.types['HelloCmp'].template.templateUrl) + .toEqual('asset:other_package/lib/template.html'); + }); }); } @@ -399,7 +404,7 @@ Future _testCreateModel(String inputPath, AssetId assetId, AssetReader reader, BuildLogger logger, - bool inlineViews: true}) { + NgMeta ngMeta}) { if (logger == null) logger = new RecordingLogger(); return log.setZoned(logger, () async { var inputId = _assetIdForPath(inputPath); @@ -410,11 +415,12 @@ Future _testCreateModel(String inputPath, reader.addAsset(assetId, await reader.readAsString(inputId)); inputId = assetId; } + if (ngMeta == null) { + ngMeta = new NgMeta.empty(); + } var annotationMatcher = new AnnotationMatcher()..addAll(customDescriptors); - var ngMeta = new NgMeta.empty(); - return createNgDeps(reader, inputId, annotationMatcher, ngMeta, - inlineViews: inlineViews); + return createNgDeps(reader, inputId, annotationMatcher, ngMeta); }); } diff --git a/modules_dart/transform/test/transform/directive_processor/custom_metadata/package_soup.dart b/modules_dart/transform/test/transform/directive_processor/custom_metadata/package_soup.dart index 3958e1d5c3..447d761bd0 100644 --- a/modules_dart/transform/test/transform/directive_processor/custom_metadata/package_soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/custom_metadata/package_soup.dart @@ -1,8 +1,10 @@ library dinner.package_soup; +import 'package:angular2/angular2.dart'; import 'package:soup/soup.dart'; @Soup() +@View(template: '') class PackageSoup { PackageSoup(); } diff --git a/modules_dart/transform/test/transform/directive_processor/custom_metadata/relative_soup.dart b/modules_dart/transform/test/transform/directive_processor/custom_metadata/relative_soup.dart index 39ef5553bb..522a15fee1 100644 --- a/modules_dart/transform/test/transform/directive_processor/custom_metadata/relative_soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/custom_metadata/relative_soup.dart @@ -1,8 +1,10 @@ library dinner.relative_soup; +import 'package:angular2/angular2.dart'; import 'annotations/soup.dart'; @Soup() +@View(template: '') class RelativeSoup { RelativeSoup(); } diff --git a/modules_dart/transform/test/transform/directive_processor/interface_chain_files/soup.dart b/modules_dart/transform/test/transform/directive_processor/interface_chain_files/soup.dart index 8ad2ae135b..3dad29afe7 100644 --- a/modules_dart/transform/test/transform/directive_processor/interface_chain_files/soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/interface_chain_files/soup.dart @@ -3,6 +3,7 @@ library dinner.soup; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[soup]') +@View(template: '') class ChangingSoupComponent implements PrimaryInterface {} class TernaryInterface {} diff --git a/modules_dart/transform/test/transform/directive_processor/interfaces_files/soup.dart b/modules_dart/transform/test/transform/directive_processor/interfaces_files/soup.dart index 6478194a42..0d33fa9c6e 100644 --- a/modules_dart/transform/test/transform/directive_processor/interfaces_files/soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/interfaces_files/soup.dart @@ -4,4 +4,5 @@ import 'package:angular2/src/core/metadata.dart'; import 'package:angular2/src/core/compiler.dart'; @Component(selector: '[soup]') +@View(template: '') class ChangingSoupComponent implements OnChanges, AnotherInterface {} diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_interface_lifecycle_files/soup.dart b/modules_dart/transform/test/transform/directive_processor/multiple_interface_lifecycle_files/soup.dart index e8002f7769..f62ae29d9b 100644 --- a/modules_dart/transform/test/transform/directive_processor/multiple_interface_lifecycle_files/soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/multiple_interface_lifecycle_files/soup.dart @@ -4,4 +4,5 @@ import 'package:angular2/src/core/metadata.dart'; import 'package:angular2/src/core/compiler.dart'; @Component(selector: '[soup]') +@View(template: '') class MultiSoupComponent implements OnChanges, OnDestroy, OnInit {} diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_part_files/main.dart b/modules_dart/transform/test/transform/directive_processor/multiple_part_files/main.dart index 82a2a6390e..86b4ba2787 100644 --- a/modules_dart/transform/test/transform/directive_processor/multiple_part_files/main.dart +++ b/modules_dart/transform/test/transform/directive_processor/multiple_part_files/main.dart @@ -6,6 +6,7 @@ part 'part1.dart'; part 'part2.dart'; @Component(selector: '[main]') +@View(template: '') class MainComponent { MainComponent(); } diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_part_files/part1.dart b/modules_dart/transform/test/transform/directive_processor/multiple_part_files/part1.dart index d3a65721a0..56f9c1bd38 100644 --- a/modules_dart/transform/test/transform/directive_processor/multiple_part_files/part1.dart +++ b/modules_dart/transform/test/transform/directive_processor/multiple_part_files/part1.dart @@ -1,6 +1,7 @@ part of main; @Component(selector: '[part1]') +@View(template: '') class Part1Component { Part1Component(); } diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_part_files/part2.dart b/modules_dart/transform/test/transform/directive_processor/multiple_part_files/part2.dart index a0c9289424..5a86818c34 100644 --- a/modules_dart/transform/test/transform/directive_processor/multiple_part_files/part2.dart +++ b/modules_dart/transform/test/transform/directive_processor/multiple_part_files/part2.dart @@ -1,6 +1,7 @@ part of main; @Component(selector: '[part2]') +@View(template: '') class Part2Component { Part2Component(); } diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/hello.dart b/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/hello.dart deleted file mode 100644 index 24dec9f18e..0000000000 --- a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/hello.dart +++ /dev/null @@ -1,10 +0,0 @@ -library examples.src.hello_world.multiple_style_urls_not_inlined_files; - -import 'package:angular2/angular2.dart' - show Component, Directive, View, NgElement; - -@Component(selector: 'hello-app') -@View( - templateUrl: 'package:a/template.html', - styleUrls: const ['package:a/template.css', 'package:a/template_other.css']) -class HelloCmp {} diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/template_other.css b/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/template_other.css deleted file mode 100644 index e461b8ddde..0000000000 --- a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/template_other.css +++ /dev/null @@ -1 +0,0 @@ -.hello { .color: red; } \ No newline at end of file diff --git a/modules_dart/transform/test/transform/directive_processor/parameter_metadata/soup.dart b/modules_dart/transform/test/transform/directive_processor/parameter_metadata/soup.dart index 077afbf388..e7b8c206a0 100644 --- a/modules_dart/transform/test/transform/directive_processor/parameter_metadata/soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/parameter_metadata/soup.dart @@ -3,6 +3,7 @@ library dinner.soup; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[soup]') +@View(template: '') class SoupComponent { SoupComponent(@Tasty() String description, @Inject(Salt) salt); } diff --git a/modules_dart/transform/test/transform/directive_processor/part_files/main.dart b/modules_dart/transform/test/transform/directive_processor/part_files/main.dart index 11d25cd684..cafbe51ad0 100644 --- a/modules_dart/transform/test/transform/directive_processor/part_files/main.dart +++ b/modules_dart/transform/test/transform/directive_processor/part_files/main.dart @@ -5,6 +5,7 @@ import 'package:angular2/src/core/metadata.dart'; part 'part.dart'; @Component(selector: '[main]') +@View(template: '') class MainComponent { MainComponent(); } diff --git a/modules_dart/transform/test/transform/directive_processor/part_files/part.dart b/modules_dart/transform/test/transform/directive_processor/part_files/part.dart index 4c04f4969a..f506a71f75 100644 --- a/modules_dart/transform/test/transform/directive_processor/part_files/part.dart +++ b/modules_dart/transform/test/transform/directive_processor/part_files/part.dart @@ -1,6 +1,7 @@ part of main; @Component(selector: '[part]') +@View(template: '') class PartComponent { PartComponent(); } diff --git a/modules_dart/transform/test/transform/directive_processor/prefixed_interface_lifecycle_files/soup.dart b/modules_dart/transform/test/transform/directive_processor/prefixed_interface_lifecycle_files/soup.dart index 0293f9f7e9..4b79c94d56 100644 --- a/modules_dart/transform/test/transform/directive_processor/prefixed_interface_lifecycle_files/soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/prefixed_interface_lifecycle_files/soup.dart @@ -4,4 +4,5 @@ import 'package:angular2/src/core/compiler.dart' as prefix; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[soup]') +@View(template: '') class OnChangeSoupComponent implements prefix.OnChanges {} diff --git a/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/fields.dart b/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/fields.dart index 6433e5c178..04438e3e5d 100644 --- a/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/fields.dart +++ b/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/fields.dart @@ -3,6 +3,7 @@ library fields; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[fields]') +@View(template: '') class FieldComponent { @FieldDecorator("field") String field; } diff --git a/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/getters.dart b/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/getters.dart index 02caa3bc8e..5ff6738e09 100644 --- a/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/getters.dart +++ b/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/getters.dart @@ -3,6 +3,7 @@ library fields; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[getters]') +@View(template: '') class FieldComponent { @GetDecorator("get") String get getVal => 'a'; } diff --git a/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/getters_and_setters.dart b/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/getters_and_setters.dart index 425523da9e..427b25abf1 100644 --- a/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/getters_and_setters.dart +++ b/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/getters_and_setters.dart @@ -3,6 +3,7 @@ library fields; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[getters-and-setters]') +@View(template: '') class FieldComponent { String _val; @GetDecorator("get") String get myVal => _val; diff --git a/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/setters.dart b/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/setters.dart index 88dd7f921f..92c051961c 100644 --- a/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/setters.dart +++ b/modules_dart/transform/test/transform/directive_processor/prop_metadata_files/setters.dart @@ -3,6 +3,7 @@ library fields; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[setters]') +@View(template: '') class FieldComponent { @SetDecorator("set") String set setVal(val) => null; } diff --git a/modules_dart/transform/test/transform/directive_processor/superclass_files/soup.dart b/modules_dart/transform/test/transform/directive_processor/superclass_files/soup.dart index 2ea09e3453..d0a38942bd 100644 --- a/modules_dart/transform/test/transform/directive_processor/superclass_files/soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/superclass_files/soup.dart @@ -3,6 +3,7 @@ library dinner.soup; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[soup]') +@View(template: '') class ChangingSoupComponent extends Super {} class Iface {} diff --git a/modules_dart/transform/test/transform/directive_processor/superclass_lifecycle_files/soup.dart b/modules_dart/transform/test/transform/directive_processor/superclass_lifecycle_files/soup.dart index cc2da37008..707870b4f8 100644 --- a/modules_dart/transform/test/transform/directive_processor/superclass_lifecycle_files/soup.dart +++ b/modules_dart/transform/test/transform/directive_processor/superclass_lifecycle_files/soup.dart @@ -4,4 +4,5 @@ import 'package:angular2/src/core/compiler.dart'; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[soup]') +@View(template: '') class OnChangeSoupComponent extends OnChanges {} diff --git a/modules_dart/transform/test/transform/directive_processor/template_files/property.dart b/modules_dart/transform/test/transform/directive_processor/template_files/property.dart new file mode 100644 index 0000000000..0aef40fc56 --- /dev/null +++ b/modules_dart/transform/test/transform/directive_processor/template_files/property.dart @@ -0,0 +1,8 @@ +library examples.src.hello_world.template_files.property; + +import 'package:angular2/angular2.dart' + show Component, Directive, View, NgElement; + +@Component(selector: 'property') +@View(template: '
Hi
') +class PropertyTestComponent {} diff --git a/modules_dart/transform/test/transform/directive_processor/unusual_component_files/hello.dart b/modules_dart/transform/test/transform/directive_processor/unusual_component_files/hello.dart new file mode 100644 index 0000000000..920d01ba94 --- /dev/null +++ b/modules_dart/transform/test/transform/directive_processor/unusual_component_files/hello.dart @@ -0,0 +1,22 @@ +library examples.src.hello_world.unusual_component_files; + +import 'package:angular2/angular2.dart' + show Component, Directive, View, NgElement; + +@Component( + selector: 'unusual-comp', + exportAs: 'ComponentExportAsValue', + changeDetection: ChangeDetectionStrategy.CheckAlways, + properties: const ['aProperty'], + host: const {'hostKey': 'hostValue'}, + events: const ['anEvent']) +@View(templateUrl: 'template.html') +class UnusualComp {} + +@Directive( + selector: 'unusual-directive', + exportAs: 'DirectiveExportAsValue', + properties: const ['aDirectiveProperty'], + host: const {'directiveHostKey': 'directiveHostValue'}, + events: const ['aDirectiveEvent']) +class UnusualDirective {} diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/template.html b/modules_dart/transform/test/transform/directive_processor/unusual_component_files/template.html similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/template.html rename to modules_dart/transform/test/transform/directive_processor/unusual_component_files/template.html diff --git a/modules_dart/transform/test/transform/inliner_for_test/absolute_url_expression_files/hello.dart b/modules_dart/transform/test/transform/inliner_for_test/absolute_url_expression_files/hello.dart new file mode 100644 index 0000000000..1015364625 --- /dev/null +++ b/modules_dart/transform/test/transform/inliner_for_test/absolute_url_expression_files/hello.dart @@ -0,0 +1,13 @@ +library examples.src.hello_world.absolute_url_expression_files; + +import 'package:angular2/angular2.dart' + show Component, Directive, View, NgElement; + +@Component(selector: 'hello-app') +@View( + templateUrl: 'package:other_package/template.html', + styleUrls: const ['package:other_package/template.css']) +class HelloCmp {} + +@Injectable() +hello() {} diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/template.css b/modules_dart/transform/test/transform/inliner_for_test/absolute_url_expression_files/template.css similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/template.css rename to modules_dart/transform/test/transform/inliner_for_test/absolute_url_expression_files/template.css diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/template.html b/modules_dart/transform/test/transform/inliner_for_test/absolute_url_expression_files/template.html similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/template.html rename to modules_dart/transform/test/transform/inliner_for_test/absolute_url_expression_files/template.html diff --git a/modules_dart/transform/test/transform/inliner_for_test/all_tests.dart b/modules_dart/transform/test/transform/inliner_for_test/all_tests.dart new file mode 100644 index 0000000000..902f3acbb6 --- /dev/null +++ b/modules_dart/transform/test/transform/inliner_for_test/all_tests.dart @@ -0,0 +1,84 @@ +library angular2.test.transform.inliner_for_test.all_tests; + +import 'dart:async'; +import 'dart:convert'; + +import 'package:angular2/src/transform/common/asset_reader.dart'; +import 'package:angular2/src/transform/inliner_for_test.dart'; +import 'package:barback/barback.dart'; +import 'package:guinness/guinness.dart'; +import 'package:dart_style/dart_style.dart'; + +import '../common/read_file.dart'; + +main() { + allTests(); +} + +allTests() { + AssetReader absoluteReader; + DartFormatter formatter = new DartFormatter(); + + beforeEach(() { + absoluteReader = new TestAssetReader(); + }); + + it('should inline `templateUrl` values', () async { + var output = await inline( + absoluteReader, _assetId('url_expression_files/hello.dart')); + expect(output).toBeNotNull(); + expect(() => formatter.format(output)).not.toThrow(); + expect(output).toContain("template: r'''{{greeting}}'''"); + }); + + it( + 'should inline `templateUrl` and `styleUrls` values expressed as ' + 'absolute urls.', () async { + absoluteReader.addAsset( + new AssetId('other_package', 'lib/template.html'), + readFile( + 'inliner_for_test/absolute_url_expression_files/template.html')); + absoluteReader.addAsset( + new AssetId('other_package', 'lib/template.css'), + readFile( + 'inliner_for_test/absolute_url_expression_files/template.css')); + + var output = await inline( + absoluteReader, _assetId('absolute_url_expression_files/hello.dart')); + + expect(output).toBeNotNull(); + expect(() => formatter.format(output)).not.toThrow(); + + expect(output).toContain("template: r'''{{greeting}}'''"); + expect(output).toContain("styles: const [" + "r'''.greeting { .color: blue; }''', ]"); + }); + + it('should inline multiple `styleUrls` values expressed as absolute urls.', + () async { + absoluteReader + ..addAsset(new AssetId('other_package', 'lib/template.html'), '') + ..addAsset(new AssetId('other_package', 'lib/template.css'), ''); + var output = await inline( + absoluteReader, _assetId('multiple_style_urls_files/hello.dart')); + + expect(output).toBeNotNull(); + expect(() => formatter.format(output)).not.toThrow(); + + expect(output) + ..toContain("r'''.greeting { .color: blue; }'''") + ..toContain("r'''.hello { .color: red; }'''"); + }); + + it('should inline `templateUrl`s expressed as adjacent strings.', () async { + var output = await inline( + absoluteReader, _assetId('split_url_expression_files/hello.dart')); + + expect(output).toBeNotNull(); + expect(() => formatter.format(output)).not.toThrow(); + + expect(output).toContain("{{greeting}}"); + }); +} + +AssetId _assetId(String path) => new AssetId('a', 'inliner_for_test/$path'); diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/hello.dart b/modules_dart/transform/test/transform/inliner_for_test/multiple_style_urls_files/hello.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/hello.dart rename to modules_dart/transform/test/transform/inliner_for_test/multiple_style_urls_files/hello.dart diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/template.css b/modules_dart/transform/test/transform/inliner_for_test/multiple_style_urls_files/template.css similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/multiple_style_urls_not_inlined_files/template.css rename to modules_dart/transform/test/transform/inliner_for_test/multiple_style_urls_files/template.css diff --git a/modules_dart/transform/test/transform/directive_processor/split_url_expression_files/template.html b/modules_dart/transform/test/transform/inliner_for_test/multiple_style_urls_files/template.html similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/split_url_expression_files/template.html rename to modules_dart/transform/test/transform/inliner_for_test/multiple_style_urls_files/template.html diff --git a/modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/template_other.css b/modules_dart/transform/test/transform/inliner_for_test/multiple_style_urls_files/template_other.css similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/multiple_style_urls_files/template_other.css rename to modules_dart/transform/test/transform/inliner_for_test/multiple_style_urls_files/template_other.css diff --git a/modules_dart/transform/test/transform/directive_processor/split_url_expression_files/hello.dart b/modules_dart/transform/test/transform/inliner_for_test/split_url_expression_files/hello.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/split_url_expression_files/hello.dart rename to modules_dart/transform/test/transform/inliner_for_test/split_url_expression_files/hello.dart diff --git a/modules_dart/transform/test/transform/directive_processor/url_expression_files/template.html b/modules_dart/transform/test/transform/inliner_for_test/split_url_expression_files/template.html similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/url_expression_files/template.html rename to modules_dart/transform/test/transform/inliner_for_test/split_url_expression_files/template.html diff --git a/modules_dart/transform/test/transform/directive_processor/url_expression_files/hello.dart b/modules_dart/transform/test/transform/inliner_for_test/url_expression_files/hello.dart similarity index 100% rename from modules_dart/transform/test/transform/directive_processor/url_expression_files/hello.dart rename to modules_dart/transform/test/transform/inliner_for_test/url_expression_files/hello.dart diff --git a/modules_dart/transform/test/transform/inliner_for_test/url_expression_files/template.html b/modules_dart/transform/test/transform/inliner_for_test/url_expression_files/template.html new file mode 100644 index 0000000000..d75013393f --- /dev/null +++ b/modules_dart/transform/test/transform/inliner_for_test/url_expression_files/template.html @@ -0,0 +1 @@ +{{greeting}} \ No newline at end of file diff --git a/modules_dart/transform/test/transform/integration/all_tests.dart b/modules_dart/transform/test/transform/integration/all_tests.dart index 5839cc8dbd..ce48053481 100644 --- a/modules_dart/transform/test/transform/integration/all_tests.dart +++ b/modules_dart/transform/test/transform/integration/all_tests.dart @@ -19,9 +19,12 @@ class IntegrationTestConfig { final String name; final Map assetPathToInputPath; final Map assetPathToExpectedOutputPath; + final bool isolate; IntegrationTestConfig(this.name, - {Map inputs, Map outputs}) + {Map inputs, + Map outputs, + this.isolate: false}) : this.assetPathToInputPath = inputs, this.assetPathToExpectedOutputPath = outputs; } @@ -57,8 +60,6 @@ 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' }), @@ -100,11 +101,43 @@ void allTests() { }, outputs: { 'a|web/bar.ng_deps.dart': 'two_annotations_files/expected/bar.ng_deps.dart' - }) + }), + new IntegrationTestConfig( + 'should generate getters for events defined on a Component.', + inputs: { + 'a|web/index.dart': 'event_getter_files/index.dart', + 'a|web/bar.dart': 'event_getter_files/bar.dart' + }, + outputs: { + 'a|web/bar.ng_deps.dart': 'event_getter_files/expected/bar.ng_deps.dart' + }), + new IntegrationTestConfig( + 'should handle Directive depenedencies declared on a View.', + inputs: { + 'a|web/index.dart': 'directive_dep_files/index.dart', + 'a|web/foo.dart': 'directive_dep_files/foo.dart', + 'a|web/bar.dart': 'directive_dep_files/bar.dart' + }, + outputs: { + 'a|web/bar.ng_deps.dart': 'directive_dep_files/expected/bar.ng_deps.dart' + }), + new IntegrationTestConfig( + 'should handle chained Directive dependencies declared on a View.', + inputs: { + 'a|web/index.dart': 'directive_chain_files/index.dart', + 'a|web/foo.dart': 'directive_chain_files/foo.dart', + 'a|web/bar.dart': 'directive_chain_files/bar.dart', + 'a|web/baz.dart': 'directive_chain_files/baz.dart' + }, + outputs: { + 'a|web/bar.ng_deps.dart': 'directive_chain_files/expected/bar.ng_deps.dart' + }) ]; var cache = {}; + var isolateAny = tests.any((t) => t.isolate); + for (var config in tests) { // Read in input & output files. config.assetPathToInputPath @@ -119,15 +152,17 @@ void allTests() { return value.endsWith('dart') ? formatter.format(code) : code; }); }); - testPhases( - config.name, - [ - [transform] - ], - config.assetPathToInputPath, - config.assetPathToExpectedOutputPath, - [], - StringFormatter.noNewlinesOrSurroundingWhitespace); + if (!isolateAny || config.isolate) { + testPhases( + config.name, + [ + [transform] + ], + config.assetPathToInputPath, + config.assetPathToExpectedOutputPath, + [], + StringFormatter.noNewlinesOrSurroundingWhitespace); + } } } diff --git a/modules_dart/transform/test/transform/integration/directive_chain_files/bar.dart b/modules_dart/transform/test/transform/integration/directive_chain_files/bar.dart new file mode 100644 index 0000000000..1282709fda --- /dev/null +++ b/modules_dart/transform/test/transform/integration/directive_chain_files/bar.dart @@ -0,0 +1,10 @@ +library bar; + +import 'package:angular2/src/core/metadata.dart'; +import 'baz.dart'; + +@Component(selector: 'soup') +@View(template: 'foo', directives: [Foo]) +class MyComponent { + MyComponent(); +} diff --git a/modules_dart/transform/test/transform/integration/directive_chain_files/baz.dart b/modules_dart/transform/test/transform/integration/directive_chain_files/baz.dart new file mode 100644 index 0000000000..946cb3f2a3 --- /dev/null +++ b/modules_dart/transform/test/transform/integration/directive_chain_files/baz.dart @@ -0,0 +1,3 @@ +library baz; + +export 'foo.dart'; diff --git a/modules_dart/transform/test/transform/integration/directive_chain_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/directive_chain_files/expected/bar.ng_deps.dart new file mode 100644 index 0000000000..bd9e3cd5a9 --- /dev/null +++ b/modules_dart/transform/test/transform/integration/directive_chain_files/expected/bar.ng_deps.dart @@ -0,0 +1,25 @@ +library bar.ng_deps.dart; + +import 'bar.template.dart' as _templates; + +import 'bar.dart'; +import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; +import 'package:angular2/src/core/metadata.dart'; +import 'baz.dart'; +import 'baz.ng_deps.dart' as i1; +export 'bar.dart'; + +var _visited = false; +void initReflector() { + if (_visited) return; + _visited = true; + _ngRef.reflector + ..registerType( + MyComponent, + new _ngRef.ReflectionInfo(const [ + const Component(selector: 'soup'), + const View(directives: [Foo], template: 'foo'), + _templates.HostMyComponentTemplate + ], const [], () => new MyComponent())); + i1.initReflector(); +} diff --git a/modules_dart/transform/test/transform/integration/directive_chain_files/foo.dart b/modules_dart/transform/test/transform/integration/directive_chain_files/foo.dart new file mode 100644 index 0000000000..681db2bebe --- /dev/null +++ b/modules_dart/transform/test/transform/integration/directive_chain_files/foo.dart @@ -0,0 +1,6 @@ +library foo; + +import 'package:angular2/src/core/metadata.dart'; + +@Directive(selector: 'foo') +class Foo {} diff --git a/modules_dart/transform/test/transform/integration/directive_chain_files/index.dart b/modules_dart/transform/test/transform/integration/directive_chain_files/index.dart new file mode 100644 index 0000000000..d37306e2ad --- /dev/null +++ b/modules_dart/transform/test/transform/integration/directive_chain_files/index.dart @@ -0,0 +1,10 @@ +library web_foo; + +import 'package:angular2/bootstrap.dart'; +import 'package:angular2/src/core/reflection/reflection_capabilities.dart'; +import 'bar.dart'; + +void main() { + reflector.reflectionCapabilities = new ReflectionCapabilities(); + bootstrap(MyComponent); +} diff --git a/modules_dart/transform/test/transform/integration/directive_dep_files/bar.dart b/modules_dart/transform/test/transform/integration/directive_dep_files/bar.dart new file mode 100644 index 0000000000..99c25ce160 --- /dev/null +++ b/modules_dart/transform/test/transform/integration/directive_dep_files/bar.dart @@ -0,0 +1,10 @@ +library bar; + +import 'package:angular2/src/core/metadata.dart'; +import 'foo.dart' as prefix; + +@Component(selector: 'soup') +@View(template: 'foo', directives: [prefix.Foo]) +class MyComponent { + MyComponent(); +} diff --git a/modules_dart/transform/test/transform/integration/directive_dep_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/directive_dep_files/expected/bar.ng_deps.dart new file mode 100644 index 0000000000..f3dfffe012 --- /dev/null +++ b/modules_dart/transform/test/transform/integration/directive_dep_files/expected/bar.ng_deps.dart @@ -0,0 +1,25 @@ +library bar.ng_deps.dart; + +import 'bar.template.dart' as _templates; + +import 'bar.dart'; +import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; +import 'package:angular2/src/core/metadata.dart'; +import 'foo.dart' as prefix; +import 'foo.ng_deps.dart' as i1; +export 'bar.dart'; + +var _visited = false; +void initReflector() { + if (_visited) return; + _visited = true; + _ngRef.reflector + ..registerType( + MyComponent, + new _ngRef.ReflectionInfo(const [ + const Component(selector: 'soup'), + const View(directives: [prefix.Foo], template: 'foo'), + _templates.HostMyComponentTemplate + ], const [], () => new MyComponent())); + i1.initReflector(); +} diff --git a/modules_dart/transform/test/transform/integration/directive_dep_files/foo.dart b/modules_dart/transform/test/transform/integration/directive_dep_files/foo.dart new file mode 100644 index 0000000000..681db2bebe --- /dev/null +++ b/modules_dart/transform/test/transform/integration/directive_dep_files/foo.dart @@ -0,0 +1,6 @@ +library foo; + +import 'package:angular2/src/core/metadata.dart'; + +@Directive(selector: 'foo') +class Foo {} diff --git a/modules_dart/transform/test/transform/integration/directive_dep_files/index.dart b/modules_dart/transform/test/transform/integration/directive_dep_files/index.dart new file mode 100644 index 0000000000..d37306e2ad --- /dev/null +++ b/modules_dart/transform/test/transform/integration/directive_dep_files/index.dart @@ -0,0 +1,10 @@ +library web_foo; + +import 'package:angular2/bootstrap.dart'; +import 'package:angular2/src/core/reflection/reflection_capabilities.dart'; +import 'bar.dart'; + +void main() { + reflector.reflectionCapabilities = new ReflectionCapabilities(); + bootstrap(MyComponent); +} diff --git a/modules_dart/transform/test/transform/integration/event_getter_files/bar.dart b/modules_dart/transform/test/transform/integration/event_getter_files/bar.dart new file mode 100644 index 0000000000..ea131f8095 --- /dev/null +++ b/modules_dart/transform/test/transform/integration/event_getter_files/bar.dart @@ -0,0 +1,9 @@ +library bar; + +import 'package:angular2/src/core/metadata.dart'; + +@Component(selector: '[soup]', events: ['eventName1', 'eventName2: propName2']) +@View(template: '') +class MyComponent { + MyComponent(); +} diff --git a/modules_dart/transform/test/transform/integration/event_getter_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/event_getter_files/expected/bar.ng_deps.dart new file mode 100644 index 0000000000..9bbef58b9e --- /dev/null +++ b/modules_dart/transform/test/transform/integration/event_getter_files/expected/bar.ng_deps.dart @@ -0,0 +1,26 @@ +library bar.ng_deps.dart; + +import 'bar.template.dart' as _templates; + +import 'bar.dart'; +import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; +import 'package:angular2/src/core/metadata.dart'; +export 'bar.dart'; + +var _visited = false; +void initReflector() { + if (_visited) return; + _visited = true; + _ngRef.reflector + ..registerType( + MyComponent, + new _ngRef.ReflectionInfo(const [ + const Component( + events: ['eventName1', 'eventName2: propName2'], + selector: '[soup]'), + const View(template: ''), + _templates.HostMyComponentTemplate + ], const [], () => new MyComponent())) + ..registerGetters( + {'eventName1': (o) => o.eventName1, 'eventName2': (o) => o.eventName2}); +} diff --git a/modules_dart/transform/test/transform/integration/event_getter_files/index.dart b/modules_dart/transform/test/transform/integration/event_getter_files/index.dart new file mode 100644 index 0000000000..069954df44 --- /dev/null +++ b/modules_dart/transform/test/transform/integration/event_getter_files/index.dart @@ -0,0 +1,11 @@ +library web_foo; + +import 'package:angular2/bootstrap.dart'; +import 'package:angular2/src/core/reflection/reflection.dart'; +import 'package:angular2/src/core/reflection/reflection_capabilities.dart'; +import 'bar.dart'; + +void main() { + reflector.reflectionCapabilities = new ReflectionCapabilities(); + bootstrap(MyComponent); +} diff --git a/modules_dart/transform/test/transform/integration/list_of_types_files/bar.dart b/modules_dart/transform/test/transform/integration/list_of_types_files/bar.dart index bc0ed87825..ab350b7641 100644 --- a/modules_dart/transform/test/transform/integration/list_of_types_files/bar.dart +++ b/modules_dart/transform/test/transform/integration/list_of_types_files/bar.dart @@ -4,6 +4,7 @@ import 'package:angular2/src/core/metadata.dart'; import 'foo.dart'; @Component(componentServices: const [MyContext]) +@View(template: '') class MyComponent { final MyContext c; MyComponent(this.c); diff --git a/modules_dart/transform/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart index 45c76dd7ff..2fa6fe61f0 100644 --- a/modules_dart/transform/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/list_of_types_files/expected/bar.ng_deps.dart @@ -1,5 +1,7 @@ library bar.ng_deps.dart; +import 'bar.template.dart' as _templates; + import 'bar.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; @@ -14,7 +16,9 @@ void initReflector() { ..registerType( MyComponent, new _ngRef.ReflectionInfo(const [ - const Component(componentServices: const [MyContext]) + const Component(componentServices: const [MyContext]), + const View(template: ''), + _templates.HostMyComponentTemplate ], const [ const [MyContext] ], (MyContext c) => new MyComponent(c))); diff --git a/modules_dart/transform/test/transform/integration/simple_annotation_files/bar.dart b/modules_dart/transform/test/transform/integration/simple_annotation_files/bar.dart index 1750721413..1883d5c3d3 100644 --- a/modules_dart/transform/test/transform/integration/simple_annotation_files/bar.dart +++ b/modules_dart/transform/test/transform/integration/simple_annotation_files/bar.dart @@ -3,6 +3,7 @@ library bar; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[soup]') +@View(template: '') class MyComponent { MyComponent(); } diff --git a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart index d2d5b35c27..6cd5eef3f8 100644 --- a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/bar.ng_deps.dart @@ -1,5 +1,7 @@ library bar.ng_deps.dart; +import 'bar.template.dart' as _templates; + import 'bar.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; @@ -12,6 +14,9 @@ void initReflector() { _ngRef.reflector ..registerType( MyComponent, - new _ngRef.ReflectionInfo(const [const Component(selector: '[soup]')], - const [], () => new MyComponent())); + new _ngRef.ReflectionInfo(const [ + const Component(selector: '[soup]'), + const View(template: ''), + _templates.HostMyComponentTemplate + ], const [], () => new MyComponent())); } diff --git a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart b/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart index 8571b732f1..4230272bd1 100644 --- a/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart @@ -6,12 +6,12 @@ import 'package:angular2/bootstrap_static.dart'; import 'index.ng_deps.dart' as ngStaticInit; import 'package:angular2/src/core/reflection/reflection.dart'; import 'bar.dart'; -import 'bar.ng_deps.dart' as i5; +import 'bar.ng_deps.dart' as i3; export 'index.dart'; var _visited = false; void initReflector() { if (_visited) return; _visited = true; - i5.initReflector(); + i3.initReflector(); } diff --git a/modules_dart/transform/test/transform/integration/synthetic_ctor_files/bar.dart b/modules_dart/transform/test/transform/integration/synthetic_ctor_files/bar.dart index c926a0f70b..fe8e864935 100644 --- a/modules_dart/transform/test/transform/integration/synthetic_ctor_files/bar.dart +++ b/modules_dart/transform/test/transform/integration/synthetic_ctor_files/bar.dart @@ -3,4 +3,5 @@ library bar; import 'package:angular2/src/core/metadata.dart'; @Component(selector: '[soup]') +@View(template: '') class MyComponent {} diff --git a/modules_dart/transform/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart index d2d5b35c27..6cd5eef3f8 100644 --- a/modules_dart/transform/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/synthetic_ctor_files/expected/bar.ng_deps.dart @@ -1,5 +1,7 @@ library bar.ng_deps.dart; +import 'bar.template.dart' as _templates; + import 'bar.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; import 'package:angular2/src/core/metadata.dart'; @@ -12,6 +14,9 @@ void initReflector() { _ngRef.reflector ..registerType( MyComponent, - new _ngRef.ReflectionInfo(const [const Component(selector: '[soup]')], - const [], () => new MyComponent())); + new _ngRef.ReflectionInfo(const [ + const Component(selector: '[soup]'), + const View(template: ''), + _templates.HostMyComponentTemplate + ], const [], () => new MyComponent())); } diff --git a/modules_dart/transform/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart index f64eb38b4d..61984d138a 100644 --- a/modules_dart/transform/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart +++ b/modules_dart/transform/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart @@ -1,7 +1,6 @@ library bar.ng_deps.dart; -import 'package:angular2/src/core/change_detection/pregen_proto_change_detector.dart' - as _gen; +import 'bar.template.dart' as _templates; import 'bar.dart'; import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; @@ -17,78 +16,7 @@ void initReflector() { MyComponent, new _ngRef.ReflectionInfo(const [ const Component(selector: '[soup]'), - const View(template: 'Salad: {{myNum}} is awesome') - ], const [], () => new MyComponent())) - ..registerGetters({'myNum': (o) => o.myNum}); - _gen.preGeneratedProtoDetectors['MyComponent_comp_0'] = - _MyComponent_ChangeDetector0.newProtoChangeDetector; -} - -class _MyComponent_ChangeDetector0 - extends _gen.AbstractChangeDetector { - var myNum0, interpolate1; - - _MyComponent_ChangeDetector0(dispatcher) - : super( - "MyComponent_comp_0", - dispatcher, - 2, - _MyComponent_ChangeDetector0.gen_propertyBindingTargets, - _MyComponent_ChangeDetector0.gen_directiveIndices, - null) { - dehydrateDirectives(false); - } - - void detectChangesInRecordsInternal(throwOnChange) { - var l_context = this.context, l_myNum0, c_myNum0, l_interpolate1; - c_myNum0 = false; - var isChanged = false; - var changes = null; - - this.propertyBindingIndex = 0; - l_myNum0 = l_context.myNum; - if (_gen.looseNotIdentical(l_myNum0, this.myNum0)) { - c_myNum0 = true; - - this.myNum0 = l_myNum0; - } - if (c_myNum0) { - l_interpolate1 = - "${"Salad: "}${_gen.ChangeDetectionUtil.s(l_myNum0)}${" is awesome"}"; - if (_gen.looseNotIdentical(l_interpolate1, this.interpolate1)) { - if (throwOnChange) { - this.throwOnChangeError(this.interpolate1, l_interpolate1); - } - - this.notifyDispatcher(l_interpolate1); - this.logBindingUpdate(l_interpolate1); - - this.interpolate1 = l_interpolate1; - } - } - changes = null; - - isChanged = false; - } - - void checkNoChanges() { - runDetectChanges(true); - } - - void dehydrateDirectives(destroyPipes) { - this.myNum0 = this.interpolate1 = _gen.ChangeDetectionUtil.uninitialized; - } - - static var gen_propertyBindingTargets = [ - _gen.ChangeDetectionUtil.bindingTarget("textNode", 0, null, null, - "Salad: {{myNum}} is awesome in MyComponent: