From d69bd021eeb59faa31a58da9fa680412fc50a36b Mon Sep 17 00:00:00 2001 From: Tim Blasi Date: Sun, 18 Oct 2015 18:36:58 -0700 Subject: [PATCH] refactor(dart/transform): Fix potential import collision Previously, importing a library twice using different prefixes could cause the template compiler step to incorrect omit `Directive` dependencies provided by that library. --- .../compile_data_creator.dart | 81 +++++++++---------- .../template_compiler/generator.dart | 5 +- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart b/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart index 8e07cda1c2..acaaa20b71 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart @@ -7,7 +7,6 @@ import 'package:angular2/src/core/compiler/directive_metadata.dart'; import 'package:angular2/src/core/compiler/template_compiler.dart'; import 'package:angular2/src/transform/common/asset_reader.dart'; import 'package:angular2/src/transform/common/logging.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/common/names.dart'; @@ -32,10 +31,8 @@ class CompileDataResults { final NgMeta ngMeta; final Map viewDefinitions; - final List directiveMetadatas; - CompileDataResults._( - this.ngMeta, this.viewDefinitions, this.directiveMetadatas); + CompileDataResults._(this.ngMeta, this.viewDefinitions); } /// Creates [ViewDefinition] objects for all `View` `Directive`s defined in @@ -44,7 +41,6 @@ class _CompileDataCreator { final AssetReader reader; final AssetId entryPoint; final NgMeta ngMeta; - final directiveMetadatas = []; _CompileDataCreator(this.reader, this.entryPoint, this.ngMeta); @@ -62,7 +58,7 @@ class _CompileDataCreator { Future createCompileData() async { if (ngDeps == null || ngDeps.reflectables == null) { - return new CompileDataResults._(ngMeta, const {}, directiveMetadatas); + return new CompileDataResults._(ngMeta, const {}); } final compileData = @@ -100,30 +96,30 @@ class _CompileDataCreator { } } } - return new CompileDataResults._(ngMeta, compileData, directiveMetadatas); + return new CompileDataResults._(ngMeta, compileData); } - /// Creates a map from [AssetId] to import prefix for `.dart` libraries - /// imported by `entryPoint`, excluding any `.ng_deps.dart` files it imports. - /// Unprefixed imports have `null` as their value. `entryPoint` is included - /// in the map with no prefix. - Future> _createImportAssetToPrefixMap() async { - final importAssetToPrefix = {entryPoint: null}; - if (ngDeps == null || ngDeps.imports == null || ngDeps.imports.isEmpty) { - return importAssetToPrefix; - } + /// Creates a map from import prefix to the asset: uris of all `.dart` + /// libraries visible from `entryPoint`, excluding `dart:` and `.ng_deps.dart` + /// files it imports. Unprefixed imports have the empty string as their key. + /// `entryPoint` is included in the map with no prefix. + Map> _createPrefixToImportsMap() { final baseUri = toAssetUri(entryPoint); + final map = >{'': new Set()..add(baseUri)}; + if (ngDeps == null || ngDeps.imports == null || ngDeps.imports.isEmpty) { + return map; + } final resolver = const TransformerUrlResolver(); - for (ImportModel model in ngMeta.ngDeps.imports) { - if (model.uri.endsWith('.dart') && !model.isNgDeps) { - var prefix = - model.prefix != null && model.prefix.isEmpty ? null : model.prefix; - importAssetToPrefix[fromUri(resolver.resolve(baseUri, model.uri))] = - prefix; - } - } - return importAssetToPrefix; + ngMeta.ngDeps.imports + .where((model) => !model.isNgDeps && !isDartCoreUri(model.uri)) + .forEach((model) { + var prefix = model.prefix == null ? '' : model.prefix; + map + .putIfAbsent(prefix, () => new Set()) + .add(resolver.resolve(baseUri, model.uri)); + }); + return map; } /// Reads the `.ng_meta.json` files associated with all of `entryPoint`'s @@ -155,29 +151,24 @@ class _CompileDataCreator { /// } /// ``` Future> _extractNgMeta() async { - var importAssetToPrefix = await _createImportAssetToPrefixMap(); + var prefixToImports = _createPrefixToImportsMap(); - var retVal = {}; - for (var importAssetId in importAssetToPrefix.keys) { - var prefix = importAssetToPrefix[importAssetId]; - if (prefix == null) prefix = ''; - var ngMeta = retVal.putIfAbsent(prefix, () => new NgMeta.empty()); - var metaAssetId = new AssetId( - importAssetId.package, toMetaExtension(importAssetId.path)); - if (await reader.hasInput(metaAssetId)) { - try { - var jsonString = await reader.readAsString(metaAssetId); - if (jsonString != null && jsonString.isNotEmpty) { - var json = JSON.decode(jsonString); - var newMetadata = new NgMeta.fromJson(json); - if (importAssetId == entryPoint) { - this.directiveMetadatas.addAll(newMetadata.types.values); + final retVal = {}; + for (var prefix in prefixToImports.keys) { + var ngMeta = retVal[prefix] = new NgMeta.empty(); + for (var importAssetUri in prefixToImports[prefix]) { + var metaAssetId = fromUri(toMetaExtension(importAssetUri)); + if (await reader.hasInput(metaAssetId)) { + try { + var jsonString = await reader.readAsString(metaAssetId); + if (jsonString != null && jsonString.isNotEmpty) { + var newMetadata = new NgMeta.fromJson(JSON.decode(jsonString)); + ngMeta.addAll(newMetadata); } - ngMeta.addAll(newMetadata); + } catch (ex, stackTrace) { + logger.warning('Failed to decode: $ex, $stackTrace', + asset: metaAssetId); } - } catch (ex, stackTrace) { - logger.warning('Failed to decode: $ex, $stackTrace', - asset: metaAssetId); } } } 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 34919e0fec..a39caacd0b 100644 --- a/modules_dart/transform/lib/src/transform/template_compiler/generator.dart +++ b/modules_dart/transform/lib/src/transform/template_compiler/generator.dart @@ -28,9 +28,10 @@ import 'compile_data_creator.dart'; Future processTemplates(AssetReader reader, AssetId assetId, {bool reflectPropertiesAsAttributes: false}) async { var viewDefResults = await createCompileData(reader, assetId); - if (viewDefResults.directiveMetadatas.isNotEmpty) { + final directiveMetadatas = viewDefResults.ngMeta.types.values; + if (directiveMetadatas.isNotEmpty) { var processor = new reg.Processor(); - viewDefResults.directiveMetadatas.forEach(processor.process); + directiveMetadatas.forEach(processor.process); viewDefResults.ngMeta.ngDeps.getters .addAll(processor.getterNames.map((e) => e.sanitizedName)); viewDefResults.ngMeta.ngDeps.setters