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 c9bfa08ad4..b99c393f58 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 @@ -140,7 +140,7 @@ abstract class NgDepsWriterMixin } // We do not support `partUris`, so skip outputting them. - model.imports.forEach((importModel) { + for (var importModel in model.imports) { // Ignore deferred imports here so as to not load the deferred libraries // code in the current library causing much of the code to not be // deferred. Instead `DeferredRewriter` will rewrite the code as to load @@ -148,7 +148,7 @@ abstract class NgDepsWriterMixin if (importModel.isDeferred) return; writeImportModel(importModel); - }); + } model.exports.forEach(writeExportModel); buffer @@ -162,6 +162,13 @@ abstract class NgDepsWriterMixin buffer.writeln(';'); } + // Call the setup method for our imports that are `.ng_deps` imports. + for (var importModel in model.imports) { + if (importModel.isNgDeps) { + buffer.writeln('${importModel.prefix}.${SETUP_METHOD_NAME}();'); + } + } + buffer.writeln('}'); } } diff --git a/modules_dart/transform/lib/src/transform/common/model/import_export_model.pb.dart b/modules_dart/transform/lib/src/transform/common/model/import_export_model.pb.dart index a74303793e..bd59a7bbc5 100644 --- a/modules_dart/transform/lib/src/transform/common/model/import_export_model.pb.dart +++ b/modules_dart/transform/lib/src/transform/common/model/import_export_model.pb.dart @@ -12,6 +12,7 @@ class ImportModel extends GeneratedMessage { ..p(3, 'hideCombinators', PbFieldType.PS) ..a(4, 'prefix', PbFieldType.OS) ..a(5, 'isDeferred', PbFieldType.OB) + ..a(6, 'isNgDeps', PbFieldType.OB) ; ImportModel() : super(); @@ -48,6 +49,11 @@ class ImportModel extends GeneratedMessage { void set isDeferred(bool v) { setField(5, v); } bool hasIsDeferred() => hasField(5); void clearIsDeferred() => clearField(5); + + bool get isNgDeps => getField(6); + void set isNgDeps(bool v) { setField(6, v); } + bool hasIsNgDeps() => hasField(6); + void clearIsNgDeps() => clearField(6); } class _ReadonlyImportModel extends ImportModel with ReadonlyMessageMixin {} @@ -95,6 +101,7 @@ const ImportModel$json = const { const {'1': 'hide_combinators', '3': 3, '4': 3, '5': 9}, const {'1': 'prefix', '3': 4, '4': 1, '5': 9}, const {'1': 'is_deferred', '3': 5, '4': 1, '5': 8}, + const {'1': 'is_ng_deps', '3': 6, '4': 1, '5': 8}, ], }; @@ -109,7 +116,7 @@ const ExportModel$json = const { /** * Generated with: - * import_export_model.proto (36a3a72d0884b84b451b7188ffa1fc93b44e7b62) + * import_export_model.proto (c018d2ad92db2d341631d813ace70925d1ccbb9b) * libprotoc 2.5.0 * dart-protoc-plugin (cc35f743de982a4916588b9c505dd21c7fe87d17) */ diff --git a/modules_dart/transform/lib/src/transform/common/model/import_export_model.proto b/modules_dart/transform/lib/src/transform/common/model/import_export_model.proto index eb23a3b712..0635276485 100644 --- a/modules_dart/transform/lib/src/transform/common/model/import_export_model.proto +++ b/modules_dart/transform/lib/src/transform/common/model/import_export_model.proto @@ -16,6 +16,8 @@ message ImportModel { optional string prefix = 4; optional bool is_deferred = 5; + + optional bool is_ng_deps = 6; } // See message above about wire-compatiblity with `ImportModel`. diff --git a/modules_dart/transform/lib/src/transform/common/names.dart b/modules_dart/transform/lib/src/transform/common/names.dart index 300ab9eaa0..0d410f4198 100644 --- a/modules_dart/transform/lib/src/transform/common/names.dart +++ b/modules_dart/transform/lib/src/transform/common/names.dart @@ -5,6 +5,7 @@ const SETUP_METHOD_NAME = 'initReflector'; const REFLECTOR_VAR_NAME = 'reflector'; const TRANSFORM_DYNAMIC_MODE = 'transform_dynamic'; 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). @@ -19,16 +20,19 @@ const REGISTER_METHODS_METHOD_NAME = 'registerMethods'; /// Returns `uri` with its extension updated to [META_EXTENSION]. String toMetaExtension(String uri) => - _toExtension(uri, const [DEPS_EXTENSION, '.dart'], META_EXTENSION); + _toExtension(uri, const [DEPS_EXTENSION, DEPS_JSON_EXTENSION, '.dart'], META_EXTENSION); /// Returns `uri` with its extension updated to [DEPS_EXTENSION]. String toDepsExtension(String uri) => - _toExtension(uri, const [META_EXTENSION, '.dart'], DEPS_EXTENSION); + _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); +String toJsonExtension(String uri) => + _toExtension(uri, const [DEPS_EXTENSION, '.dart'], DEPS_JSON_EXTENSION); + /// Returns `uri` with its extension updated to `toExtension` if its /// extension is currently in `fromExtension`. String _toExtension( diff --git a/modules_dart/transform/lib/src/transform/directive_linker/linker.dart b/modules_dart/transform/lib/src/transform/directive_linker/linker.dart index 4c2c8d093e..e537c1edd0 100644 --- a/modules_dart/transform/lib/src/transform/directive_linker/linker.dart +++ b/modules_dart/transform/lib/src/transform/directive_linker/linker.dart @@ -2,118 +2,115 @@ library angular2.transform.directive_linker.linker; import 'dart:async'; -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/model/import_export_model.pb.dart'; +import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart'; import 'package:barback/barback.dart'; import 'package:code_transformers/assets.dart'; -/// Checks the `.ng_deps.dart` file represented by `entryPoint` and +/// Checks the `.ng_deps.json` file represented by `entryPoint` and /// determines whether it is necessary to the functioning of the Angular 2 /// Dart app. /// -/// An `.ng_deps.dart` file is not necessary if: +/// An `.ng_deps.json` file is not necessary if: /// 1. It does not register any `@Injectable` types with the system. -/// 2. It does not import any libraries whose `.ng_deps.dart` files register +/// 2. It does not import any libraries whose `.ng_deps.json` files register /// any `@Injectable` types with the system. /// /// Since `@Directive` and `@Component` inherit from `@Injectable`, we know /// we will not miss processing any classes annotated with those tags. Future isNecessary(AssetReader reader, AssetId entryPoint) async { - NgDeps ngDeps = await NgDeps.parse(reader, entryPoint); + if (!(await reader.hasInput(entryPoint))) return false; + var jsonString = await reader.readAsString(entryPoint); + if (jsonString == null || jsonString.isEmpty) return false; + var ngDepsModel = new NgDepsModel.fromJson(jsonString); - if (ngDeps.registeredTypes.isNotEmpty) return true; + if (ngDepsModel.reflectables != null && + ngDepsModel.reflectables.isNotEmpty) return true; // We do not register any @Injectables, do we call any dependencies? - var linkedDepsMap = - await _processNgImports(reader, entryPoint, _getSortedDeps(ngDeps)); + var linkedDepsMap = await _processNgImports(reader, entryPoint, ngDepsModel); return linkedDepsMap.isNotEmpty; } -/// Modifies the `.ng_deps.dart` file represented by `entryPoint` to call its -/// dependencies associated `initReflector` methods. +/// Modifies the [NgDepsModel] represented by `entryPoint` to import its +/// dependencies' associated `.ng_deps.dart` files. /// /// For example, if entry_point.ng_deps.dart imports dependency.dart, this -/// will check if dependency.ng_deps.dart exists. If it does, we add: -/// -/// ``` -/// import 'dependency.ng_deps.dart' as i0; -/// ... -/// void setupReflection(reflector) { -/// ... -/// i0.initReflector(reflector); -/// } -/// ``` -Future linkNgDeps(AssetReader reader, AssetId entryPoint) async { - NgDeps ngDeps = await NgDeps.parse(reader, entryPoint); +/// will check if dependency.ng_deps.json exists. If it does, we add an import +/// to dependency.ng_deps.dart to the entry_point [NgDepsModel] and set +/// `isNgDeps` to `true` to signify that it is a dependency on which we need to +/// call `initReflector`. +Future linkNgDeps(AssetReader reader, AssetId entryPoint) async { + if (!(await reader.hasInput(entryPoint))) return null; + var jsonString = await reader.readAsString(entryPoint); + if (jsonString.isEmpty) return null; + var ngDepsModel = new NgDepsModel.fromJson(jsonString); - if (ngDeps == null) return null; - - var allDeps = _getSortedDeps(ngDeps); - var linkedDepsMap = await _processNgImports(reader, entryPoint, allDeps); + var linkedDepsMap = await _processNgImports(reader, entryPoint, ngDepsModel); if (linkedDepsMap.isEmpty) { - // We are not calling `initReflector` on any other libraries. - return ngDeps.code; + // We are not calling `initReflector` on any other libraries, but we still + // return the model to ensure it is written to code. + // TODO(kegluneq): Continue using the protobuf format after this phase. + return ngDepsModel; } - var importBuf = new StringBuffer(); - var declarationBuf = new StringBuffer(); - var code = ngDeps.code; - var codeIdx = 0; - // Generate import statements for linked deps where necessary. - for (var i = 0, it = allDeps.iterator; it.moveNext();) { - if (linkedDepsMap.containsKey(it.current)) { - importBuf.write(code.substring(codeIdx, it.current.end)); - codeIdx = it.current.end; - importBuf.write(''' - import '${linkedDepsMap[it.current]}' as i${i}; - '''); - declarationBuf.write('i${i}.${SETUP_METHOD_NAME}();'); - ++i; + for (var i = ngDepsModel.imports.length - 1; i >= 0; --i) { + var import = ngDepsModel.imports[i]; + if (linkedDepsMap.containsKey(import.uri)) { + var linkedModel = new ImportModel() + ..isNgDeps = true + ..uri = toDepsExtension(linkedDepsMap[import.uri]) + ..prefix = 'i$i'; + // TODO(kegluneq): Preserve combinators? + ngDepsModel.imports.insert(i + 1, linkedModel); + } + } + for (var i = 0, iLen = ngDepsModel.exports.length; i < iLen; ++i) { + var export = ngDepsModel.exports[i]; + if (linkedDepsMap.containsKey(export.uri)) { + var linkedModel = new ImportModel() + ..isNgDeps = true + ..uri = toDepsExtension(linkedDepsMap[export.uri]) + ..prefix = 'i${ngDepsModel.imports.length}'; + // TODO(kegluneq): Preserve combinators? + ngDepsModel.imports.add(linkedModel); } } - var declarationSeamIdx = ngDeps.setupMethod.end - 1; - return '$importBuf' - '${code.substring(codeIdx, declarationSeamIdx)}' - '$declarationBuf' - '${code.substring(declarationSeamIdx)}'; + return ngDepsModel; } -/// All `import`s and `export`s in `ngDeps` sorted by order of appearance in -/// the file. -List _getSortedDeps(NgDeps ngDeps) { - return [] - ..addAll(ngDeps.imports) - ..addAll(ngDeps.exports) - ..sort((a, b) => a.end.compareTo(b.end)); +bool _isNotDartDirective(dynamic model) { + return !model.uri.startsWith('dart:'); } -bool _isNotDartDirective(UriBasedDirective directive) { - return !stringLiteralToString(directive.uri).startsWith('dart:'); -} - -/// Maps each input {@link UriBasedDirective} to its associated `.ng_deps.dart` -/// file, if it exists. -Future> _processNgImports(AssetReader reader, - AssetId entryPoint, Iterable directives) { +/// Maps the `uri` of each input [ImportModel] or [ExportModel] to its +/// associated `.ng_deps.json` file, if one exists. +Future> _processNgImports( + AssetReader reader, AssetId ngJsonAsset, NgDepsModel model) { final nullFuture = new Future.value(null); - final retVal = {}; + final importsAndExports = new List.from(model.imports)..addAll(model.exports); + final retVal = {}; + final entryPoint = + new AssetId(ngJsonAsset.package, toDepsExtension(ngJsonAsset.path)); return Future - .wait(directives - .where(_isNotDartDirective) - .map((UriBasedDirective directive) { - var ngDepsUri = toDepsExtension(stringLiteralToString(directive.uri)); + .wait( + importsAndExports.where(_isNotDartDirective).map((dynamic directive) { + // The uri of the import or export with .dart replaced with .ng_deps.json. + // This is the json file containing Angular 2 codegen info, if one exists. + var linkedJsonUri = toJsonExtension(directive.uri); var spanArg = null; - var ngDepsAsset = uriToAssetId(entryPoint, ngDepsUri, logger, spanArg, + var linkedNgJsonAsset = uriToAssetId( + entryPoint, linkedJsonUri, logger, spanArg, errorOnAbsolute: false); - if (ngDepsAsset == entryPoint) return nullFuture; - return reader.hasInput(ngDepsAsset).then((hasInput) { + if (linkedNgJsonAsset == ngJsonAsset) return nullFuture; + return reader.hasInput(linkedNgJsonAsset).then((hasInput) { if (hasInput) { - retVal[directive] = ngDepsUri; + retVal[directive.uri] = linkedJsonUri; } }, onError: (_) => null); })) 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 1346140964..37a53ee366 100644 --- a/modules_dart/transform/lib/src/transform/directive_linker/transformer.dart +++ b/modules_dart/transform/lib/src/transform/directive_linker/transformer.dart @@ -3,6 +3,7 @@ library angular2.transform.directive_linker.transformer; import 'dart:async'; import 'package:angular2/src/transform/common/asset_reader.dart'; +import 'package:angular2/src/transform/common/code/ng_deps_code.dart'; import 'package:angular2/src/transform/common/formatter.dart'; import 'package:angular2/src/transform/common/logging.dart' as log; import 'package:angular2/src/transform/common/names.dart'; @@ -10,15 +11,14 @@ import 'package:barback/barback.dart'; import 'linker.dart'; -/// Transformer responsible for processing .ng_deps.dart files created by -/// {@link DirectiveProcessor} and ensuring that the generated calls to -/// `setupReflection` call the necessary `setupReflection` method in all -/// dependencies. +/// Transformer responsible for processing `.ng_deps.json` files created by +/// {@link DirectiveProcessor} and ensuring that each imports its dependencies' +/// .ng_deps.dart files. class DirectiveLinker extends Transformer implements DeclaringTransformer { DirectiveLinker(); @override - bool isPrimary(AssetId id) => id.path.endsWith(DEPS_EXTENSION); + bool isPrimary(AssetId id) => id.path.endsWith(DEPS_JSON_EXTENSION); @override declareOutputs(DeclaringTransform transform) { @@ -31,22 +31,27 @@ class DirectiveLinker extends Transformer implements DeclaringTransformer { var reader = new AssetReader.fromTransform(transform); var assetId = transform.primaryInput.id; var assetPath = assetId.path; - var transformedCode = await linkNgDeps(reader, assetId); - if (transformedCode != null) { - var formattedCode = formatter.format(transformedCode, uri: assetPath); - transform.addOutput(new Asset.fromString(assetId, formattedCode)); + var ngDepsModel = await linkNgDeps(reader, assetId); + if (ngDepsModel != null) { + var buf = new StringBuffer(); + var writer = new NgDepsWriter(buf); + writer.writeNgDepsModel(ngDepsModel); + var formattedCode = formatter.format('$buf', uri: assetPath); + var ngDepsAssetId = + new AssetId(assetId.package, toDepsExtension(assetPath)); + transform.addOutput(new Asset.fromString(ngDepsAssetId, formattedCode)); } }); } } -/// Transformer responsible for removing unnecessary `.ng_deps.dart` files +/// Transformer responsible for removing unnecessary `.ng_deps.json` files /// created by {@link DirectiveProcessor}. class EmptyNgDepsRemover extends Transformer implements DeclaringTransformer { EmptyNgDepsRemover(); @override - bool isPrimary(AssetId id) => id.path.endsWith(DEPS_EXTENSION); + bool isPrimary(AssetId id) => id.path.endsWith(DEPS_JSON_EXTENSION); /// We occasionally consume the primary input, but that depends on the /// contents of the file, so we conservatively do not declare any outputs nor 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 9d77a88d0a..b98641e6b1 100644 --- a/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart +++ b/modules_dart/transform/lib/src/transform/directive_processor/rewriter.dart @@ -51,6 +51,9 @@ Future createNgDeps(AssetReader reader, AssetId assetId, parsedCode.accept(ngDepsVisitor); var ngDepsModel = ngDepsVisitor.model; + var ngMetaVisitor = new _NgMetaVisitor(ngMeta); + parsedCode.accept(ngMetaVisitor); + // 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 && @@ -58,9 +61,6 @@ Future createNgDeps(AssetReader reader, AssetId assetId, return null; } - var ngMetaVisitor = new _NgMetaVisitor(ngMeta); - parsedCode.accept(ngMetaVisitor); - if (inlineViews) { await inlineViewProps(new XhrImpl(reader, assetId), ngDepsModel); } 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 17ba15a4c5..6ec3e953cd 100644 --- a/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart +++ b/modules_dart/transform/lib/src/transform/directive_processor/transformer.dart @@ -4,7 +4,6 @@ import 'dart:async'; import 'dart:convert'; import 'package:angular2/src/transform/common/asset_reader.dart'; -import 'package:angular2/src/transform/common/code/ng_deps_code.dart'; import 'package:angular2/src/transform/common/logging.dart' as log; import 'package:angular2/src/transform/common/names.dart'; import 'package:angular2/src/transform/common/options.dart'; @@ -52,15 +51,12 @@ class DirectiveProcessor extends Transformer implements DeclaringTransformer { inlineViews: options.inlineViews); if (ngDepsModel != null) { var ngDepsAssetId = - transform.primaryInput.id.changeExtension(DEPS_EXTENSION); + transform.primaryInput.id.changeExtension(DEPS_JSON_EXTENSION); if (await transform.hasInput(ngDepsAssetId)) { log.logger.error('Clobbering ${ngDepsAssetId}. ' 'This probably will not end well'); } - var buf = new StringBuffer(); - var writer = new NgDepsWriter(buf); - writer.writeNgDepsModel(ngDepsModel); - transform.addOutput(new Asset.fromString(ngDepsAssetId, '$buf')); + transform.addOutput(new Asset.fromString(ngDepsAssetId, ngDepsModel.writeToJson())); } if (!ngMeta.isEmpty) { var ngAliasesId = diff --git a/modules_dart/transform/lib/src/transform/transformer.dart b/modules_dart/transform/lib/src/transform/transformer.dart index 4808905b8d..bcb55c478d 100644 --- a/modules_dart/transform/lib/src/transform/transformer.dart +++ b/modules_dart/transform/lib/src/transform/transformer.dart @@ -32,11 +32,8 @@ class AngularTransformerGroup extends TransformerGroup { phases.addAll(new List.generate( options.optimizationPhases, (_) => [new EmptyNgDepsRemover()])); phases.addAll([ - [ - new DirectiveLinker(), - new DirectiveMetadataExtractor(), - new DeferredRewriter(options) - ], + [new DirectiveLinker(), new DeferredRewriter(options)], + [new DirectiveMetadataExtractor()], [new BindGenerator(options)], [new TemplateCompiler(options)] ]); diff --git a/modules_dart/transform/test/transform/directive_linker/all_tests.dart b/modules_dart/transform/test/transform/directive_linker/all_tests.dart index 14d6252356..b295098ed7 100644 --- a/modules_dart/transform/test/transform/directive_linker/all_tests.dart +++ b/modules_dart/transform/test/transform/directive_linker/all_tests.dart @@ -4,6 +4,7 @@ import 'package:barback/barback.dart'; import 'package:angular2/src/transform/common/model/annotation_model.pb.dart'; import 'package:angular2/src/transform/common/model/import_export_model.pb.dart'; import 'package:angular2/src/transform/common/model/ng_deps_model.pb.dart'; +import 'package:angular2/src/transform/common/model/reflection_info_model.pb.dart'; import 'package:angular2/src/transform/directive_linker/linker.dart'; import 'package:dart_style/dart_style.dart'; import 'package:guinness/guinness.dart'; @@ -15,36 +16,122 @@ var formatter = new DartFormatter(); main() => allTests(); void allTests() { - var reader = new TestAssetReader(); + var reader; - it('should ensure that dependencies are property chained.', () async { - for (var inputPath in [ - 'bar.ng_deps.dart', - 'foo.ng_deps.dart', - 'index.ng_deps.dart' - ]) { - var expected = - readFile('directive_linker/simple_files/expected/$inputPath'); - inputPath = 'directive_linker/simple_files/$inputPath'; - var actual = formatter - .format(await linkNgDeps(reader, new AssetId('a', inputPath))); - expect(actual).toEqual(formatter.format(expected)); - } + beforeEach(() { + reader = new TestAssetReader(); }); - it('should ensure that exported dependencies are property chained.', - () async { - for (var inputPath in [ - 'bar.ng_deps.dart', - 'foo.ng_deps.dart', - 'index.ng_deps.dart' - ]) { - var expected = - readFile('directive_linker/simple_export_files/expected/$inputPath'); - inputPath = 'directive_linker/simple_export_files/$inputPath'; - var actual = formatter - .format(await linkNgDeps(reader, new AssetId('a', inputPath))); - expect(actual).toEqual(formatter.format(expected)); - } + it('should chain imported dependencies.', () async { + var fooModel = new NgDepsModel() + ..libraryUri = 'test.foo' + ..imports.add(new ImportModel() + ..uri = 'bar.dart' + ..prefix = 'dep'); + var barModel = new NgDepsModel()..libraryUri = 'test.bar'; + + var fooAssetId = new AssetId('a', 'lib/foo.ng_deps.json'); + reader + ..addAsset(fooAssetId, fooModel.writeToJson()) + ..addAsset( + new AssetId('a', 'lib/bar.ng_deps.json'), barModel.writeToJson()); + + var linked = await linkNgDeps(reader, fooAssetId); + expect(linked).toBeNotNull(); + var linkedImport = + linked.imports.firstWhere((i) => i.uri.endsWith('bar.ng_deps.dart')); + expect(linkedImport).toBeNotNull(); + expect(linkedImport.isNgDeps).toBeTrue(); + expect(linkedImport.prefix.startsWith('i')).toBeTrue(); + }); + + it('should chain exported dependencies.', () async { + var fooModel = new NgDepsModel() + ..libraryUri = 'test.foo' + ..exports.add(new ExportModel()..uri = 'bar.dart'); + var barModel = new NgDepsModel()..libraryUri = 'test.bar'; + + var fooAssetId = new AssetId('a', 'lib/foo.ng_deps.json'); + reader + ..addAsset(fooAssetId, fooModel.writeToJson()) + ..addAsset( + new AssetId('a', 'lib/bar.ng_deps.json'), barModel.writeToJson()); + + var linked = await linkNgDeps(reader, fooAssetId); + expect(linked).toBeNotNull(); + var linkedImport = + linked.imports.firstWhere((i) => i.uri.endsWith('bar.ng_deps.dart')); + expect(linkedImport).toBeNotNull(); + expect(linkedImport.isNgDeps).toBeTrue(); + expect(linkedImport.prefix.startsWith('i')).toBeTrue(); + }); + + describe('isNecessary', () { + it('should drop deps that do no registration and do not import.', () async { + var fooModel = new NgDepsModel()..libraryUri = 'test.foo'; + + var fooAssetId = new AssetId('a', 'lib/foo.ng_deps.json'); + reader.addAsset(fooAssetId, fooModel.writeToJson()); + expect(await isNecessary(reader, fooAssetId)).toBeFalse(); + }); + + it('should retain deps that import other deps.', () async { + var fooModel = new NgDepsModel() + ..libraryUri = 'test.foo' + ..imports.add(new ImportModel()..uri = 'bar.dart'); + var barModel = new NgDepsModel()..libraryUri = 'test.bar'; + + var fooAssetId = new AssetId('a', 'lib/foo.ng_deps.json'); + reader + ..addAsset(fooAssetId, fooModel.writeToJson()) + ..addAsset( + new AssetId('a', 'lib/bar.ng_deps.json'), barModel.writeToJson()); + + expect(await isNecessary(reader, fooAssetId)).toBeTrue(); + }); + + it('should retain deps that export other deps.', () async { + var fooModel = new NgDepsModel() + ..libraryUri = 'test.foo' + ..exports.add(new ExportModel()..uri = 'bar.dart'); + var barModel = new NgDepsModel()..libraryUri = 'test.bar'; + + var fooAssetId = new AssetId('a', 'lib/foo.ng_deps.json'); + reader + ..addAsset(fooAssetId, fooModel.writeToJson()) + ..addAsset( + new AssetId('a', 'lib/bar.ng_deps.json'), barModel.writeToJson()); + + expect(await isNecessary(reader, fooAssetId)).toBeTrue(); + }); + + it('should retain deps that register injectable types.', () async { + var fooModel = new NgDepsModel() + ..libraryUri = 'test.foo' + ..reflectables.add(new ReflectionInfoModel() + ..name = 'MyInjectable' + ..annotations.add(new AnnotationModel() + ..name = 'Injectable' + ..isInjectable = true)); + + var fooAssetId = new AssetId('a', 'lib/foo.ng_deps.json'); + reader.addAsset(fooAssetId, fooModel.writeToJson()); + expect(await isNecessary(reader, fooAssetId)).toBeTrue(); + }); + + it('should retain deps that register injectable functions.', () async { + var fooModel = new NgDepsModel() + ..libraryUri = 'test.foo' + ..reflectables.add(new ReflectionInfoModel() + ..name = 'injectableFunction' + ..isFunction = true + ..annotations.add(new AnnotationModel() + ..name = 'Injectable' + ..isInjectable = true)); + + var fooAssetId = new AssetId('a', 'lib/foo.ng_deps.json'); + reader.addAsset(fooAssetId, fooModel.writeToJson()); + expect(await isNecessary(reader, fooAssetId)).toBeTrue(); + }); }); } diff --git a/modules_dart/transform/test/transform/directive_linker/simple_export_files/bar.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_export_files/bar.ng_deps.dart deleted file mode 100644 index 2012465d9a..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_export_files/bar.ng_deps.dart +++ /dev/null @@ -1,18 +0,0 @@ -library bar.ng_deps.dart; - -import 'bar.dart'; -export 'bar.dart'; -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/src/core/metadata.dart'; -export 'foo.dart'; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - _ngRef.reflector - ..registerType( - MyComponent, - new _ngRef.ReflectionInfo(const [const Component(selector: '[soup]')], - const [], () => new MyComponent())); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_export_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_export_files/expected/bar.ng_deps.dart deleted file mode 100644 index 2ef4869c97..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_export_files/expected/bar.ng_deps.dart +++ /dev/null @@ -1,20 +0,0 @@ -library bar.ng_deps.dart; - -import 'bar.dart'; -export 'bar.dart'; -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/src/core/metadata.dart'; -export 'foo.dart'; -import 'foo.ng_deps.dart' as i0; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - _ngRef.reflector - ..registerType( - MyComponent, - new _ngRef.ReflectionInfo(const [const Component(selector: '[soup]')], - const [], () => new MyComponent())); - i0.initReflector(); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_export_files/expected/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_export_files/expected/foo.ng_deps.dart deleted file mode 100644 index b7831829a3..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_export_files/expected/foo.ng_deps.dart +++ /dev/null @@ -1,17 +0,0 @@ -library foo.ng_deps.dart; - -import 'foo.dart'; -export 'foo.dart'; -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/src/core/metadata.dart'; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - _ngRef.reflector - ..registerType( - DependencyComponent, - new _ngRef.ReflectionInfo(const [const Component(selector: '[salad]')], - const [], () => new DependencyComponent())); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_export_files/expected/index.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_export_files/expected/index.ng_deps.dart deleted file mode 100644 index 39d81e09b9..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_export_files/expected/index.ng_deps.dart +++ /dev/null @@ -1,14 +0,0 @@ -library web_foo.ng_deps.dart; - -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/bootstrap_static.dart'; -import 'package:angular2/src/core/reflection/reflection_capabilities.dart'; -import 'bar.dart'; -import 'bar.ng_deps.dart' as i0; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - i0.initReflector(); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_export_files/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_export_files/foo.ng_deps.dart deleted file mode 100644 index b7831829a3..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_export_files/foo.ng_deps.dart +++ /dev/null @@ -1,17 +0,0 @@ -library foo.ng_deps.dart; - -import 'foo.dart'; -export 'foo.dart'; -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/src/core/metadata.dart'; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - _ngRef.reflector - ..registerType( - DependencyComponent, - new _ngRef.ReflectionInfo(const [const Component(selector: '[salad]')], - const [], () => new DependencyComponent())); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_export_files/index.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_export_files/index.ng_deps.dart deleted file mode 100644 index 5bdb4ad284..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_export_files/index.ng_deps.dart +++ /dev/null @@ -1,12 +0,0 @@ -library web_foo.ng_deps.dart; - -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/bootstrap_static.dart'; -import 'package:angular2/src/core/reflection/reflection_capabilities.dart'; -import 'bar.dart'; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_files/bar.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_files/bar.ng_deps.dart deleted file mode 100644 index 96cd3be310..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_files/bar.ng_deps.dart +++ /dev/null @@ -1,20 +0,0 @@ -library bar.ng_deps.dart; - -import 'bar.dart'; -export 'bar.dart'; -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/src/core/metadata.dart'; -import 'foo.dart' as dep; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - _ngRef.reflector - ..registerType( - MyComponent, - new ReflectionInfo(const [ - const Component( - selector: '[soup]', viewBindings: const [dep.DependencyComponent]) - ], const [], () => new MyComponent())); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_files/expected/bar.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_files/expected/bar.ng_deps.dart deleted file mode 100644 index c9ef1973bf..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_files/expected/bar.ng_deps.dart +++ /dev/null @@ -1,22 +0,0 @@ -library bar.ng_deps.dart; - -import 'bar.dart'; -export 'bar.dart'; -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/src/core/metadata.dart'; -import 'foo.dart' as dep; -import 'foo.ng_deps.dart' as i0; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - _ngRef.reflector - ..registerType( - MyComponent, - new ReflectionInfo(const [ - const Component( - selector: '[soup]', viewBindings: const [dep.DependencyComponent]) - ], const [], () => new MyComponent())); - i0.initReflector(); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_files/expected/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_files/expected/foo.ng_deps.dart deleted file mode 100644 index b7831829a3..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_files/expected/foo.ng_deps.dart +++ /dev/null @@ -1,17 +0,0 @@ -library foo.ng_deps.dart; - -import 'foo.dart'; -export 'foo.dart'; -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/src/core/metadata.dart'; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - _ngRef.reflector - ..registerType( - DependencyComponent, - new _ngRef.ReflectionInfo(const [const Component(selector: '[salad]')], - const [], () => new DependencyComponent())); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_files/expected/index.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_files/expected/index.ng_deps.dart deleted file mode 100644 index 39d81e09b9..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_files/expected/index.ng_deps.dart +++ /dev/null @@ -1,14 +0,0 @@ -library web_foo.ng_deps.dart; - -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/bootstrap_static.dart'; -import 'package:angular2/src/core/reflection/reflection_capabilities.dart'; -import 'bar.dart'; -import 'bar.ng_deps.dart' as i0; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - i0.initReflector(); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_files/foo.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_files/foo.ng_deps.dart deleted file mode 100644 index b7831829a3..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_files/foo.ng_deps.dart +++ /dev/null @@ -1,17 +0,0 @@ -library foo.ng_deps.dart; - -import 'foo.dart'; -export 'foo.dart'; -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/src/core/metadata.dart'; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; - _ngRef.reflector - ..registerType( - DependencyComponent, - new _ngRef.ReflectionInfo(const [const Component(selector: '[salad]')], - const [], () => new DependencyComponent())); -} diff --git a/modules_dart/transform/test/transform/directive_linker/simple_files/index.ng_deps.dart b/modules_dart/transform/test/transform/directive_linker/simple_files/index.ng_deps.dart deleted file mode 100644 index 5bdb4ad284..0000000000 --- a/modules_dart/transform/test/transform/directive_linker/simple_files/index.ng_deps.dart +++ /dev/null @@ -1,12 +0,0 @@ -library web_foo.ng_deps.dart; - -import 'package:angular2/src/core/reflection/reflection.dart' as _ngRef; -import 'package:angular2/bootstrap_static.dart'; -import 'package:angular2/src/core/reflection/reflection_capabilities.dart'; -import 'bar.dart'; - -var _visited = false; -void initReflector() { - if (_visited) return; - _visited = true; -} 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 1ba4fe342a..8571b732f1 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 i0; +import 'bar.ng_deps.dart' as i5; export 'index.dart'; var _visited = false; void initReflector() { if (_visited) return; _visited = true; - i0.initReflector(); + i5.initReflector(); }