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.
This commit is contained in:
Tim Blasi 2015-10-18 18:36:58 -07:00
parent 26044026c9
commit d69bd021ee
2 changed files with 39 additions and 47 deletions

View File

@ -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<ReflectionInfoModel,
NormalizedComponentWithViewDirectives> viewDefinitions;
final List<CompileDirectiveMetadata> 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 = <CompileDirectiveMetadata>[];
_CompileDataCreator(this.reader, this.entryPoint, this.ngMeta);
@ -62,7 +58,7 @@ class _CompileDataCreator {
Future<CompileDataResults> 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<Map<AssetId, String>> _createImportAssetToPrefixMap() async {
final importAssetToPrefix = <AssetId, String>{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<String, Iterable<String>> _createPrefixToImportsMap() {
final baseUri = toAssetUri(entryPoint);
final map = <String, Set<String>>{'': new Set<String>()..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<String>())
.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<Map<String, NgMeta>> _extractNgMeta() async {
var importAssetToPrefix = await _createImportAssetToPrefixMap();
var prefixToImports = _createPrefixToImportsMap();
var retVal = <String, NgMeta>{};
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 = <String, NgMeta>{};
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);
}
}
}

View File

@ -28,9 +28,10 @@ import 'compile_data_creator.dart';
Future<Outputs> 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