feat(transformers): changes transformers to collect information about providers and resolve identifiers during linking
Closes #7380
This commit is contained in:
@ -166,11 +166,11 @@ abstract class NgDepsWriterMixin
|
||||
..writeln('void ${SETUP_METHOD_NAME}() {')
|
||||
..writeln('if (_visited) return; _visited = true;');
|
||||
|
||||
final needsReceiver = (model.reflectables != null &&
|
||||
model.reflectables.isNotEmpty) ||
|
||||
(model.getters != null && model.getters.isNotEmpty) ||
|
||||
(model.setters != null && model.setters.isNotEmpty) ||
|
||||
(model.methods != null && model.methods.isNotEmpty);
|
||||
final needsReceiver =
|
||||
(model.reflectables != null && model.reflectables.isNotEmpty) ||
|
||||
(model.getters != null && model.getters.isNotEmpty) ||
|
||||
(model.setters != null && model.setters.isNotEmpty) ||
|
||||
(model.methods != null && model.methods.isNotEmpty);
|
||||
|
||||
if (needsReceiver) {
|
||||
buffer.writeln('$REFLECTOR_PREFIX.$REFLECTOR_VAR_NAME');
|
||||
|
@ -74,6 +74,50 @@ class PrintLogger implements TransformLogger {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps the logger and prints the messages
|
||||
/// only if they have not been printed before
|
||||
class DeduppingLogger implements TransformLogger {
|
||||
Set<String> _printedMessages;
|
||||
|
||||
final TransformLogger _logger;
|
||||
|
||||
DeduppingLogger(this._logger, this._printedMessages);
|
||||
|
||||
String _key(msg, AssetId asset) => "$msg $asset";
|
||||
|
||||
@override
|
||||
void info(msg, {AssetId asset, SourceSpan span}) {
|
||||
if (!_printedMessages.contains(_key(msg, asset))) {
|
||||
_printedMessages.add(_key(msg, asset));
|
||||
_logger.info(msg, asset: asset, span: span);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void fine(msg, {AssetId asset, SourceSpan span}) {
|
||||
if (!_printedMessages.contains(_key(msg, asset))) {
|
||||
_printedMessages.add(_key(msg, asset));
|
||||
_logger.fine(msg, asset: asset, span: span);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void warning(msg, {AssetId asset, SourceSpan span}) {
|
||||
if (!_printedMessages.contains(_key(msg, asset))) {
|
||||
_printedMessages.add(_key(msg, asset));
|
||||
_logger.warning(msg, asset: asset, span: span);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void error(msg, {AssetId asset, SourceSpan span}) {
|
||||
if (!_printedMessages.contains(_key(msg, asset))) {
|
||||
_printedMessages.add(_key(msg, asset));
|
||||
_logger.error(msg, asset: asset, span: span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PrintLoggerError extends Error {
|
||||
final String message;
|
||||
final AssetId asset;
|
||||
|
@ -23,8 +23,8 @@ class NamedParameter extends GeneratedMessage {
|
||||
static PbList<NamedParameter> createRepeated() =>
|
||||
new PbList<NamedParameter>();
|
||||
static NamedParameter getDefault() {
|
||||
if (_defaultInstance == null) _defaultInstance =
|
||||
new _ReadonlyNamedParameter();
|
||||
if (_defaultInstance == null)
|
||||
_defaultInstance = new _ReadonlyNamedParameter();
|
||||
return _defaultInstance;
|
||||
}
|
||||
|
||||
@ -78,8 +78,8 @@ class AnnotationModel extends GeneratedMessage {
|
||||
static PbList<AnnotationModel> createRepeated() =>
|
||||
new PbList<AnnotationModel>();
|
||||
static AnnotationModel getDefault() {
|
||||
if (_defaultInstance == null) _defaultInstance =
|
||||
new _ReadonlyAnnotationModel();
|
||||
if (_defaultInstance == null)
|
||||
_defaultInstance = new _ReadonlyAnnotationModel();
|
||||
return _defaultInstance;
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,8 @@ class ParameterModel extends GeneratedMessage {
|
||||
static PbList<ParameterModel> createRepeated() =>
|
||||
new PbList<ParameterModel>();
|
||||
static ParameterModel getDefault() {
|
||||
if (_defaultInstance == null) _defaultInstance =
|
||||
new _ReadonlyParameterModel();
|
||||
if (_defaultInstance == null)
|
||||
_defaultInstance = new _ReadonlyParameterModel();
|
||||
return _defaultInstance;
|
||||
}
|
||||
|
||||
|
@ -27,15 +27,15 @@ class PropertyMetadataModel extends GeneratedMessage {
|
||||
static PbList<PropertyMetadataModel> createRepeated() =>
|
||||
new PbList<PropertyMetadataModel>();
|
||||
static PropertyMetadataModel getDefault() {
|
||||
if (_defaultInstance == null) _defaultInstance =
|
||||
new _ReadonlyPropertyMetadataModel();
|
||||
if (_defaultInstance == null)
|
||||
_defaultInstance = new _ReadonlyPropertyMetadataModel();
|
||||
return _defaultInstance;
|
||||
}
|
||||
|
||||
static PropertyMetadataModel _defaultInstance;
|
||||
static void $checkItem(PropertyMetadataModel v) {
|
||||
if (v
|
||||
is! PropertyMetadataModel) checkItemFailed(v, 'PropertyMetadataModel');
|
||||
if (v is! PropertyMetadataModel)
|
||||
checkItemFailed(v, 'PropertyMetadataModel');
|
||||
}
|
||||
|
||||
String get name => $_get(0, 1, '');
|
||||
@ -70,8 +70,8 @@ class PrefixedType extends GeneratedMessage {
|
||||
static PrefixedType create() => new PrefixedType();
|
||||
static PbList<PrefixedType> createRepeated() => new PbList<PrefixedType>();
|
||||
static PrefixedType getDefault() {
|
||||
if (_defaultInstance == null) _defaultInstance =
|
||||
new _ReadonlyPrefixedType();
|
||||
if (_defaultInstance == null)
|
||||
_defaultInstance = new _ReadonlyPrefixedType();
|
||||
return _defaultInstance;
|
||||
}
|
||||
|
||||
@ -130,8 +130,8 @@ class ReflectionInfoModel extends GeneratedMessage {
|
||||
static PbList<ReflectionInfoModel> createRepeated() =>
|
||||
new PbList<ReflectionInfoModel>();
|
||||
static ReflectionInfoModel getDefault() {
|
||||
if (_defaultInstance == null) _defaultInstance =
|
||||
new _ReadonlyReflectionInfoModel();
|
||||
if (_defaultInstance == null)
|
||||
_defaultInstance = new _ReadonlyReflectionInfoModel();
|
||||
return _defaultInstance;
|
||||
}
|
||||
|
||||
|
@ -28,10 +28,8 @@ import 'url_resolver.dart' show isDartCoreUri;
|
||||
/// `.ng_meta.json` files as intermediate assets during the compilation process.
|
||||
class NgMeta {
|
||||
static const _ALIAS_VALUE = 'alias';
|
||||
static const _KIND_KEY = 'kind';
|
||||
static const _NG_DEPS_KEY = 'ngDeps';
|
||||
static const _TYPE_VALUE = 'type';
|
||||
static const _VALUE_KEY = 'value';
|
||||
|
||||
/// Metadata for each identifier
|
||||
/// Type: [CompileDirectiveMetadata]|[CompilePipeMetadata]|[CompileTypeMetadata]|[CompileIdentifierMetadata]
|
||||
@ -43,11 +41,9 @@ class NgMeta {
|
||||
// The NgDeps generated from
|
||||
final NgDepsModel ngDeps;
|
||||
|
||||
bool definesAlias;
|
||||
|
||||
NgMeta({Map<String, List<String>> aliases,
|
||||
Map<String, dynamic> identifiers,
|
||||
this.ngDeps: null, this.definesAlias: false})
|
||||
Map<String, dynamic> identifiers,
|
||||
this.ngDeps: null})
|
||||
:this.aliases = aliases != null ? aliases : {},
|
||||
this.identifiers = identifiers != null ? identifiers : {};
|
||||
|
||||
@ -72,48 +68,43 @@ class NgMeta {
|
||||
|
||||
bool get isEmpty => identifiers.isEmpty && aliases.isEmpty && isNgDepsEmpty;
|
||||
|
||||
List<String> get linkingUris {
|
||||
final r = ngDeps.exports.map((r) => r.uri).toList();
|
||||
if (definesAlias) {
|
||||
r.addAll(ngDeps.imports.map((r) => r.uri));
|
||||
}
|
||||
return r;
|
||||
bool get needsResolution {
|
||||
return identifiers.values.any((id) =>
|
||||
id is CompileDirectiveMetadata || id is CompilePipeMetadata || id is CompileTypeMetadata
|
||||
|| (id is CompileIdentifierMetadata && id.value != null));
|
||||
}
|
||||
|
||||
/// Parse from the serialized form produced by [toJson].
|
||||
factory NgMeta.fromJson(Map json) {
|
||||
var ngDeps = null;
|
||||
final aliases = {};
|
||||
final identifiers = {};
|
||||
var definesAlias = false;
|
||||
for (var key in json.keys) {
|
||||
if (key == _NG_DEPS_KEY) {
|
||||
var ngDepsJsonMap = json[key];
|
||||
if (ngDepsJsonMap == null) continue;
|
||||
|
||||
if (json.containsKey(_NG_DEPS_KEY)) {
|
||||
var ngDepsJsonMap = json[_NG_DEPS_KEY];
|
||||
if (ngDepsJsonMap != null) {
|
||||
if (ngDepsJsonMap is! Map) {
|
||||
log.warning(
|
||||
'Unexpected value $ngDepsJsonMap for key "$key" in NgMeta.');
|
||||
continue;
|
||||
'Unexpected value $ngDepsJsonMap for key "$_NG_DEPS_KEY" in NgMeta.');
|
||||
} else {
|
||||
ngDeps = new NgDepsModel()..mergeFromJsonMap(ngDepsJsonMap);
|
||||
}
|
||||
ngDeps = new NgDepsModel()
|
||||
..mergeFromJsonMap(ngDepsJsonMap);
|
||||
} else if (key == 'definesAlias') {
|
||||
definesAlias = json[key];
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
var entry = json[key];
|
||||
final aliases = json[_ALIAS_VALUE] != null ? json[_ALIAS_VALUE] : {};
|
||||
|
||||
final identifiers = {};
|
||||
if (json.containsKey(_TYPE_VALUE)) {
|
||||
for (var key in json[_TYPE_VALUE].keys) {
|
||||
var entry = json[_TYPE_VALUE][key];
|
||||
if (entry is! Map) {
|
||||
log.warning('Unexpected value $entry for key "$key" in NgMeta.');
|
||||
continue;
|
||||
}
|
||||
if (entry[_KIND_KEY] == _TYPE_VALUE) {
|
||||
identifiers[key] = CompileMetadataWithIdentifier.fromJson(entry[_VALUE_KEY]);
|
||||
} else if (entry[_KIND_KEY] == _ALIAS_VALUE) {
|
||||
aliases[key] = entry[_VALUE_KEY];
|
||||
}
|
||||
identifiers[key] = metadataFromJson(entry);
|
||||
}
|
||||
}
|
||||
return new NgMeta(identifiers: identifiers, aliases: aliases, ngDeps: ngDeps, definesAlias: definesAlias);
|
||||
|
||||
return new NgMeta(identifiers: identifiers, aliases: aliases, ngDeps: ngDeps);
|
||||
}
|
||||
|
||||
/// Serialized representation of this instance.
|
||||
@ -121,16 +112,11 @@ class NgMeta {
|
||||
var result = {};
|
||||
result[_NG_DEPS_KEY] = isNgDepsEmpty ? null : ngDeps.writeToJsonMap();
|
||||
|
||||
result[_TYPE_VALUE] = {};
|
||||
identifiers.forEach((k, v) {
|
||||
result[k] = {_KIND_KEY: _TYPE_VALUE, _VALUE_KEY: v.toJson()};
|
||||
result[_TYPE_VALUE][k] = v.toJson();
|
||||
});
|
||||
|
||||
aliases.forEach((k, v) {
|
||||
result[k] = {_KIND_KEY: _ALIAS_VALUE, _VALUE_KEY: v};
|
||||
});
|
||||
|
||||
result['definesAlias'] = definesAlias;
|
||||
|
||||
result[_ALIAS_VALUE] = aliases;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -150,10 +136,10 @@ class NgMeta {
|
||||
log.error('Circular alias dependency for "$name". Cycle: ${newPath.join(' -> ')}.');
|
||||
return;
|
||||
}
|
||||
if (identifiers.containsKey(name)) {
|
||||
result.add(identifiers[name]);
|
||||
} else if (aliases.containsKey(name)) {
|
||||
if (aliases.containsKey(name)) {
|
||||
aliases[name].forEach((n) => helper(n, newPath));
|
||||
} else if (identifiers.containsKey(name)) {
|
||||
result.add(identifiers[name]);
|
||||
} else {
|
||||
log.error('Unknown alias: ${newPath.join(' -> ')}. Make sure you export ${name} from the file where ${path.last} is defined.');
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import 'mirror_mode.dart';
|
||||
import 'options.dart';
|
||||
import './url_resolver.dart';
|
||||
|
||||
TransformerOptions parseBarbackSettings(BarbackSettings settings) {
|
||||
TransformerOptions parseBarbackSettings(BarbackSettings settings) {
|
||||
var config = settings.configuration;
|
||||
var entryPoints = _readStringList(config, ENTRY_POINT_PARAM);
|
||||
var initReflector =
|
||||
|
@ -22,10 +22,11 @@ class TypeMetadataReader {
|
||||
final _DirectiveMetadataVisitor _directiveVisitor;
|
||||
final _PipeMetadataVisitor _pipeVisitor;
|
||||
final _CompileTypeMetadataVisitor _typeVisitor;
|
||||
final _CompileFactoryMetadataVisitor _factoryVisitor;
|
||||
final TemplateCompiler _templateCompiler;
|
||||
|
||||
TypeMetadataReader._(
|
||||
this._directiveVisitor, this._pipeVisitor, this._templateCompiler, this._typeVisitor);
|
||||
TypeMetadataReader._(this._directiveVisitor, this._pipeVisitor,
|
||||
this._templateCompiler, this._typeVisitor, this._factoryVisitor);
|
||||
|
||||
/// Accepts an [AnnotationMatcher] which tests that an [Annotation]
|
||||
/// is a [Directive], [Component], or [View].
|
||||
@ -33,12 +34,13 @@ class TypeMetadataReader {
|
||||
InterfaceMatcher interfaceMatcher, TemplateCompiler templateCompiler) {
|
||||
var lifecycleVisitor = new _LifecycleHookVisitor(interfaceMatcher);
|
||||
var typeVisitor = new _CompileTypeMetadataVisitor(annotationMatcher);
|
||||
var directiveVisitor =
|
||||
new _DirectiveMetadataVisitor(annotationMatcher, lifecycleVisitor, typeVisitor);
|
||||
var directiveVisitor = new _DirectiveMetadataVisitor(
|
||||
annotationMatcher, lifecycleVisitor, typeVisitor);
|
||||
var pipeVisitor = new _PipeMetadataVisitor(annotationMatcher);
|
||||
var factoryVisitor = new _CompileFactoryMetadataVisitor(annotationMatcher);
|
||||
|
||||
return new TypeMetadataReader._(
|
||||
directiveVisitor, pipeVisitor, templateCompiler, typeVisitor);
|
||||
directiveVisitor, pipeVisitor, templateCompiler, typeVisitor, factoryVisitor);
|
||||
}
|
||||
|
||||
/// Reads *un-normalized* [CompileDirectiveMetadata]/[CompilePipeMetadata] from the
|
||||
@ -71,6 +73,47 @@ class TypeMetadataReader {
|
||||
return new Future.value(null);
|
||||
}
|
||||
}
|
||||
|
||||
Future<dynamic> readFactoryMetadata(FunctionDeclaration node, AssetId assetId) {
|
||||
_factoryVisitor.reset(assetId);
|
||||
|
||||
node.accept(_factoryVisitor);
|
||||
|
||||
if (_factoryVisitor.isInjectable) {
|
||||
return new Future.value(_factoryVisitor.factory);
|
||||
} else {
|
||||
return new Future.value(null);
|
||||
}
|
||||
}
|
||||
|
||||
CompileIdentifierMetadata readIdentifierMetadata(
|
||||
VariableDeclaration decl, AssetId assetId) {
|
||||
final name = decl.name.name;
|
||||
return new CompileIdentifierMetadata(
|
||||
name: name, moduleUrl: toAssetUri(assetId), value: _readValue(decl.initializer));
|
||||
}
|
||||
|
||||
dynamic _readValue(dynamic initializer) {
|
||||
try {
|
||||
if (initializer is InstanceCreationExpression &&
|
||||
((initializer as InstanceCreationExpression)
|
||||
.constructorName
|
||||
.toString() ==
|
||||
"Provider" ||
|
||||
(initializer as InstanceCreationExpression)
|
||||
.constructorName
|
||||
.toString() ==
|
||||
"Binding")) {
|
||||
return _readProvider(initializer);
|
||||
} else if (initializer is ListLiteral) {
|
||||
return _readProviders(initializer);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluates the [Map] represented by `expression` and adds all `key`,
|
||||
@ -134,7 +177,6 @@ bool _expressionToBool(Expression node, String nodeDescription) {
|
||||
|
||||
class _CompileTypeMetadataVisitor extends Object
|
||||
with RecursiveAstVisitor<CompileTypeMetadata> {
|
||||
|
||||
bool _isInjectable = false;
|
||||
CompileTypeMetadata _type;
|
||||
AssetId _assetId;
|
||||
@ -166,58 +208,79 @@ class _CompileTypeMetadataVisitor extends Object
|
||||
@override
|
||||
Object visitClassDeclaration(ClassDeclaration node) {
|
||||
node.metadata.accept(this);
|
||||
final fieldTypes = _readFields(node);
|
||||
if (this._isInjectable) {
|
||||
final constructor = node.getConstructor(null);
|
||||
final diDeps = constructor == null ? [] :
|
||||
_getCompileDiDependencyMetadata(constructor.parameters, fieldTypes);
|
||||
|
||||
_type = new CompileTypeMetadata(
|
||||
moduleUrl: toAssetUri(_assetId),
|
||||
name: node.name.toString(),
|
||||
diDeps: _getCompileDiDependencyMetadata(node),
|
||||
diDeps: diDeps,
|
||||
runtime: null // Intentionally `null`, cannot be provided here.
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, TypeName> _readFields(ClassDeclaration clazz) {
|
||||
final res = {};
|
||||
clazz.members
|
||||
.where((member) => member is FieldDeclaration)
|
||||
.forEach((FieldDeclaration field) {
|
||||
var type = field.fields.type;
|
||||
if (type != null) {
|
||||
field.fields.variables.forEach((VariableDeclaration decl) {
|
||||
var key = '${decl.name}';
|
||||
res[key] = type;
|
||||
});
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
class _CompileFactoryMetadataVisitor extends Object
|
||||
with RecursiveAstVisitor<CompileFactoryMetadata> {
|
||||
bool _isInjectable = false;
|
||||
CompileFactoryMetadata _factory;
|
||||
AssetId _assetId;
|
||||
final AnnotationMatcher _annotationMatcher;
|
||||
|
||||
_CompileFactoryMetadataVisitor(this._annotationMatcher);
|
||||
|
||||
bool get isInjectable => _isInjectable;
|
||||
|
||||
CompileFactoryMetadata get factory => _factory;
|
||||
|
||||
void reset(AssetId assetId) {
|
||||
this._assetId = assetId;
|
||||
this._isInjectable = false;
|
||||
this._factory = null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitAnnotation(Annotation node) {
|
||||
_isInjectable = _annotationMatcher.isInjectable(node, _assetId);
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
node.metadata.accept(this);
|
||||
if (this._isInjectable) {
|
||||
_factory = new CompileFactoryMetadata(
|
||||
moduleUrl: toAssetUri(_assetId),
|
||||
name: node.name.toString(),
|
||||
diDeps: _getCompileDiDependencyMetadata(node.functionExpression.parameters, {}),
|
||||
runtime: null // Intentionally `null`, cannot be provided here.
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<CompileDiDependencyMetadata> _getCompileDiDependencyMetadata(ClassDeclaration node) {
|
||||
final constructor = node.getConstructor(null);
|
||||
if (constructor == null) return [];
|
||||
|
||||
return constructor.parameters.parameters.map((p) {
|
||||
final typeToken = p is SimpleFormalParameter && p.type != null ? _readIdentifier(p.type.name) : null;
|
||||
final injectTokens = p.metadata.where((m) => m.name.toString() == "Inject").map((m) => _readIdentifier(m.arguments.arguments[0]));
|
||||
final token = injectTokens.isNotEmpty ? injectTokens.first : typeToken;
|
||||
final query = _hasAnnotation(p, "Query") ? _createQueryMetadata(_getAnnotation(p, "Query")) : null;
|
||||
final viewQuery = _hasAnnotation(p, "ViewQuery") ? _createQueryMetadata(_getAnnotation(p, "ViewQuery")) : null;
|
||||
|
||||
return new CompileDiDependencyMetadata(
|
||||
token: token,
|
||||
isAttribute: _hasAnnotation(p, "Attribute"),
|
||||
isSelf: _hasAnnotation(p, "Self"),
|
||||
isHost: _hasAnnotation(p, "Host"),
|
||||
isSkipSelf: _hasAnnotation(p, "SkipSelf"),
|
||||
isOptional: _hasAnnotation(p, "Optional"),
|
||||
query: query,
|
||||
viewQuery: viewQuery);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
_getAnnotation(p, String attrName) => p.metadata.where((m) => m.name.toString() == attrName).first;
|
||||
_hasAnnotation(p, String attrName) => p.metadata.where((m) => m.name.toString() == attrName).isNotEmpty;
|
||||
_createQueryMetadata(Annotation a) {
|
||||
final selector = _readIdentifier(a.arguments.arguments.first);
|
||||
var descendants = false;
|
||||
a.arguments.arguments.skip(0).forEach((arg) {
|
||||
if (arg is NamedExpression && arg.name.toString() == "descendants:")
|
||||
descendants = naiveEval(arg.expression);
|
||||
});
|
||||
|
||||
final selectors = selector is String ? selector.split(",") : [selector];
|
||||
return new CompileQueryMetadata(selectors: selectors, descendants: descendants);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Visitor responsible for processing a [Directive] annotated
|
||||
/// [ClassDeclaration] and creating a [CompileDirectiveMetadata] object.
|
||||
class _DirectiveMetadataVisitor extends Object
|
||||
@ -233,7 +296,8 @@ class _DirectiveMetadataVisitor extends Object
|
||||
/// The [AssetId] we are currently processing.
|
||||
AssetId _assetId;
|
||||
|
||||
_DirectiveMetadataVisitor(this._annotationMatcher, this._lifecycleVisitor, this._typeVisitor) {
|
||||
_DirectiveMetadataVisitor(
|
||||
this._annotationMatcher, this._lifecycleVisitor, this._typeVisitor) {
|
||||
reset(null);
|
||||
}
|
||||
|
||||
@ -250,7 +314,10 @@ class _DirectiveMetadataVisitor extends Object
|
||||
List<String> _inputs;
|
||||
List<String> _outputs;
|
||||
Map<String, String> _host;
|
||||
List<CompileProviderMetadata> _providers;
|
||||
List _providers;
|
||||
List _viewProviders;
|
||||
List _queries;
|
||||
List _viewQueries;
|
||||
List<LifecycleHooks> _lifecycleHooks;
|
||||
CompileTemplateMetadata _cmpTemplate;
|
||||
CompileTemplateMetadata _viewTemplate;
|
||||
@ -269,7 +336,10 @@ class _DirectiveMetadataVisitor extends Object
|
||||
_inputs = <String>[];
|
||||
_outputs = <String>[];
|
||||
_host = <String, String>{};
|
||||
_providers = <CompileProviderMetadata>[];
|
||||
_providers = [];
|
||||
_viewProviders = [];
|
||||
_queries = [];
|
||||
_viewQueries = [];
|
||||
_lifecycleHooks = null;
|
||||
_cmpTemplate = null;
|
||||
_viewTemplate = null;
|
||||
@ -292,6 +362,9 @@ class _DirectiveMetadataVisitor extends Object
|
||||
outputs: _outputs,
|
||||
host: _host,
|
||||
providers: _providers,
|
||||
viewProviders: _viewProviders,
|
||||
queries: _queries,
|
||||
viewQueries: _viewQueries,
|
||||
lifecycleHooks: _lifecycleHooks,
|
||||
template: _template);
|
||||
}
|
||||
@ -367,6 +440,19 @@ class _DirectiveMetadataVisitor extends Object
|
||||
_host['[${variable.name}]'] = '${variable.name}';
|
||||
}
|
||||
}
|
||||
|
||||
if (_isAnnotation(meta, 'ContentChild')) {
|
||||
this._queries.add(_createQueryMetadata(meta, false, true, variable.name.toString()));
|
||||
}
|
||||
if (_isAnnotation(meta, 'ContentChildren')) {
|
||||
this._queries.add(_createQueryMetadata(meta, false, false, variable.name.toString()));
|
||||
}
|
||||
if (_isAnnotation(meta, 'ViewChild')) {
|
||||
this._viewQueries.add(_createQueryMetadata(meta, true, true, variable.name.toString()));
|
||||
}
|
||||
if (_isAnnotation(meta, 'ViewChildren')) {
|
||||
this._viewQueries.add(_createQueryMetadata(meta, false, false, variable.name.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -383,6 +469,19 @@ class _DirectiveMetadataVisitor extends Object
|
||||
_addPropertyToType(_inputs, node.name.toString(), meta);
|
||||
}
|
||||
|
||||
if (_isAnnotation(meta, 'ContentChild') && node.isSetter) {
|
||||
this._queries.add(_createQueryMetadata(meta, false, true, node.name.toString()));
|
||||
}
|
||||
if (_isAnnotation(meta, 'ContentChildren') && node.isSetter) {
|
||||
this._queries.add(_createQueryMetadata(meta, false, false, node.name.toString()));
|
||||
}
|
||||
if (_isAnnotation(meta, 'ViewChild') && node.isSetter) {
|
||||
this._viewQueries.add(_createQueryMetadata(meta, true, true, node.name.toString()));
|
||||
}
|
||||
if (_isAnnotation(meta, 'ViewChildren') && node.isSetter) {
|
||||
this._viewQueries.add(_createQueryMetadata(meta, false, false, node.name.toString()));
|
||||
}
|
||||
|
||||
if (_isAnnotation(meta, 'HostListener')) {
|
||||
if (meta.arguments.arguments.length == 0 ||
|
||||
meta.arguments.arguments.length > 2) {
|
||||
@ -416,38 +515,13 @@ class _DirectiveMetadataVisitor extends Object
|
||||
}
|
||||
}
|
||||
|
||||
void _populateProviders(Expression providerValues) {
|
||||
void _populateProviders(Expression providerValues, List providers) {
|
||||
_checkMeta();
|
||||
|
||||
if (providerValues is ListLiteral) {
|
||||
final providers = providerValues.elements.map((el) {
|
||||
if (el is PrefixedIdentifier || el is SimpleIdentifier) {
|
||||
return new CompileProviderMetadata(token: _readIdentifier(el));
|
||||
|
||||
} else if (el is InstanceCreationExpression &&
|
||||
(el.constructorName.toString() == "Provider" ||
|
||||
el.constructorName.toString() == "Binding")
|
||||
|
||||
) {
|
||||
final token = el.argumentList.arguments.first;
|
||||
|
||||
var useClass;
|
||||
el.argumentList.arguments.skip(1).forEach((arg) {
|
||||
if (arg.name.toString() == "useClass:") {
|
||||
final id = _readIdentifier(arg.expression);
|
||||
useClass = new CompileTypeMetadata(prefix: id.prefix, name: id.name);
|
||||
}
|
||||
});
|
||||
return new CompileProviderMetadata(token: _readIdentifier(token), useClass: useClass);
|
||||
|
||||
} else {
|
||||
throw new ArgumentError(
|
||||
'Incorrect value. Expected a Provider or a String, but got "${el}".');
|
||||
}
|
||||
});
|
||||
_providers.addAll(providers);
|
||||
providers.addAll(_readProviders(providerValues));
|
||||
} else {
|
||||
_providers.add(new CompileProviderMetadata(token: _readIdentifier(providerValues)));
|
||||
providers.add(_readIdentifier(providerValues));
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,7 +613,16 @@ class _DirectiveMetadataVisitor extends Object
|
||||
_populateEvents(node.expression);
|
||||
break;
|
||||
case 'providers':
|
||||
_populateProviders(node.expression);
|
||||
_populateProviders(node.expression, _providers);
|
||||
break;
|
||||
case 'bindings':
|
||||
_populateProviders(node.expression, _providers);
|
||||
break;
|
||||
case 'viewProviders':
|
||||
_populateProviders(node.expression, _viewProviders);
|
||||
break;
|
||||
case 'viewBindings':
|
||||
_populateProviders(node.expression, _viewProviders);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
@ -607,27 +690,30 @@ class _LifecycleHookVisitor extends SimpleAstVisitor<List<LifecycleHooks>> {
|
||||
List<LifecycleHooks> 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -824,21 +910,199 @@ class _PipeMetadataVisitor extends Object with RecursiveAstVisitor<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
List _readProviders(ListLiteral providerValues) {
|
||||
return providerValues.elements.map((el) {
|
||||
if (el is PrefixedIdentifier || el is SimpleIdentifier) {
|
||||
return _readIdentifier(el);
|
||||
} else if (el is InstanceCreationExpression &&
|
||||
(el.constructorName.toString() == "Provider" ||
|
||||
el.constructorName.toString() == "Binding")) {
|
||||
return _readProvider(el);
|
||||
} else {
|
||||
throw new ArgumentError(
|
||||
'Incorrect value. Expected a Provider or a String, but got "${el}".');
|
||||
}
|
||||
}).toList();
|
||||
}
|
||||
|
||||
|
||||
CompileProviderMetadata _readProvider(InstanceCreationExpression el) {
|
||||
final token = el.argumentList.arguments.first;
|
||||
|
||||
var useClass, useExisting, useValue, useFactory, deps;
|
||||
el.argumentList.arguments.skip(1).forEach((arg) {
|
||||
switch (arg.name.toString()) {
|
||||
case "useClass:":
|
||||
final id = _readIdentifier(arg.expression);
|
||||
useClass = new CompileTypeMetadata(prefix: id.prefix, name: id.name);
|
||||
break;
|
||||
case "toClass:":
|
||||
final id = _readIdentifier(arg.expression);
|
||||
useClass = new CompileTypeMetadata(prefix: id.prefix, name: id.name);
|
||||
break;
|
||||
case "useExisting:":
|
||||
useExisting = _readIdentifier(arg.expression);
|
||||
break;
|
||||
case "toAlias:":
|
||||
useExisting = _readIdentifier(arg.expression);
|
||||
break;
|
||||
case "useValue:":
|
||||
useValue = _readIdentifier(arg.expression);
|
||||
break;
|
||||
case "toValue:":
|
||||
useValue = _readIdentifier(arg.expression);
|
||||
break;
|
||||
case "useFactory:":
|
||||
final id = _readIdentifier(arg.expression);
|
||||
useFactory = new CompileFactoryMetadata(
|
||||
name: id.name, prefix: id.prefix);
|
||||
break;
|
||||
case "toFactory:":
|
||||
final id = _readIdentifier(arg.expression);
|
||||
useFactory = new CompileFactoryMetadata(
|
||||
name: id.name, prefix: id.prefix);
|
||||
break;
|
||||
case "deps:":
|
||||
deps = _readDeps(arg.expression);
|
||||
break;
|
||||
}
|
||||
});
|
||||
return new CompileProviderMetadata(
|
||||
token: _readIdentifier(token),
|
||||
useClass: useClass,
|
||||
useExisting: useExisting,
|
||||
useValue: useValue,
|
||||
useFactory: useFactory,
|
||||
deps: deps);
|
||||
}
|
||||
|
||||
List<CompileDiDependencyMetadata> _readDeps(ListLiteral deps) {
|
||||
if (deps is! ListLiteral) {
|
||||
throw new ArgumentError('Incorrect value is set as deps. '
|
||||
'Expected type is ListLiteral');
|
||||
}
|
||||
|
||||
return deps.elements.map((p) {
|
||||
final list = p is ListLiteral ? p.elements : [p];
|
||||
final first = list.first;
|
||||
|
||||
var token;
|
||||
if (first is InstanceCreationExpression &&
|
||||
(first as InstanceCreationExpression).constructorName.toString() ==
|
||||
"Inject") {
|
||||
token = _readIdentifier(first.argumentList.arguments[0]);
|
||||
} else {
|
||||
token = _readIdentifier(first);
|
||||
}
|
||||
|
||||
return new CompileDiDependencyMetadata(
|
||||
token: token,
|
||||
isSelf: _hasConst(list, "Self"),
|
||||
isHost: _hasConst(list, "Host"),
|
||||
isSkipSelf: _hasConst(list, "SkipSelf"),
|
||||
isOptional: _hasConst(list, "Optional"));
|
||||
}).toList();
|
||||
}
|
||||
|
||||
_createQueryMetadata(Annotation a, bool defaultDescendantsValue, bool first, String propertyName) {
|
||||
final selector = _readIdentifier(a.arguments.arguments.first);
|
||||
var descendants = defaultDescendantsValue;
|
||||
a.arguments.arguments.skip(0).forEach((arg) {
|
||||
if (arg is NamedExpression && arg.name.toString() == "descendants:")
|
||||
descendants = naiveEval(arg.expression);
|
||||
});
|
||||
|
||||
final selectors = selector is String ? selector.split(",") : [selector];
|
||||
return new CompileQueryMetadata(
|
||||
selectors: selectors, descendants: descendants, first: first, propertyName: propertyName);
|
||||
}
|
||||
|
||||
List<CompileDiDependencyMetadata> _getCompileDiDependencyMetadata(
|
||||
FormalParameterList params, Map<String, TypeName> fieldTypes) {
|
||||
return params.parameters.map((p) {
|
||||
if (p is DefaultFormalParameter) {
|
||||
p = p.parameter;
|
||||
}
|
||||
|
||||
var token;
|
||||
final isAttribute = _hasAnnotation(p, "Attribute");
|
||||
if (isAttribute) {
|
||||
token = _readIdentifier(_getAnnotation(p, "Attribute").arguments.arguments.first);
|
||||
} else {
|
||||
var type = null;
|
||||
if (p is SimpleFormalParameter) {
|
||||
type = p.type;
|
||||
} else if (p is FieldFormalParameter) {
|
||||
type = fieldTypes[p.identifier.toString()];
|
||||
}
|
||||
final typeToken = type != null ? _readIdentifier(type.name) : null;
|
||||
final injectTokens = p.metadata
|
||||
.where((m) => m.name.toString() == "Inject")
|
||||
.map((m) => _readIdentifier(m.arguments.arguments[0]));
|
||||
token = injectTokens.isNotEmpty ? injectTokens.first : typeToken;
|
||||
}
|
||||
|
||||
var query;
|
||||
if(_hasAnnotation(p, "Query")) {
|
||||
query = _createQueryMetadata(_getAnnotation(p, "Query"), false, false, null);
|
||||
}
|
||||
if(_hasAnnotation(p, "ContentChildren")) {
|
||||
query = _createQueryMetadata(_getAnnotation(p, "ContentChildren"), true, false, null);
|
||||
}
|
||||
|
||||
var viewQuery;
|
||||
if(_hasAnnotation(p, "ViewQuery")) {
|
||||
viewQuery = _createQueryMetadata(_getAnnotation(p, "ViewQuery"), false, false, null);
|
||||
}
|
||||
if(_hasAnnotation(p, "ViewChildren")) {
|
||||
viewQuery = _createQueryMetadata(_getAnnotation(p, "ViewChildren"), true, false, null);
|
||||
}
|
||||
|
||||
return new CompileDiDependencyMetadata(
|
||||
token: token,
|
||||
isAttribute: _hasAnnotation(p, "Attribute"),
|
||||
isSelf: _hasAnnotation(p, "Self"),
|
||||
isHost: _hasAnnotation(p, "Host"),
|
||||
isSkipSelf: _hasAnnotation(p, "SkipSelf"),
|
||||
isOptional: _hasAnnotation(p, "Optional"),
|
||||
query: query,
|
||||
viewQuery: viewQuery);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
_getAnnotation(p, String attrName) =>
|
||||
p.metadata.where((m) => m.name.toString() == attrName).first;
|
||||
|
||||
_hasAnnotation(p, String attrName) =>
|
||||
p.metadata.where((m) => m.name.toString() == attrName).isNotEmpty;
|
||||
|
||||
bool _hasConst(List list, String name) => list
|
||||
.where((m) =>
|
||||
m is InstanceCreationExpression && m.constructorName.toString() == name)
|
||||
.isNotEmpty;
|
||||
|
||||
dynamic _readIdentifier(dynamic el) {
|
||||
if (el is PrefixedIdentifier) {
|
||||
return new CompileIdentifierMetadata(name: '${el.identifier}', prefix: '${el.prefix}');
|
||||
|
||||
final prefix = '${el.prefix}';
|
||||
if (prefix.length > 0 && prefix.toUpperCase()[0] == prefix[0]) {
|
||||
throw new ArgumentError('Incorrect identifier "${el}".');
|
||||
} else {
|
||||
return new CompileIdentifierMetadata(
|
||||
name: '${el.identifier}', prefix: prefix);
|
||||
}
|
||||
} else if (el is SimpleIdentifier) {
|
||||
return new CompileIdentifierMetadata(name: '$el');
|
||||
|
||||
} else if (el is SimpleStringLiteral){
|
||||
} else if (el is DoubleLiteral ||
|
||||
el is IntegerLiteral ||
|
||||
el is SimpleStringLiteral ||
|
||||
el is BooleanLiteral) {
|
||||
return el.value;
|
||||
|
||||
} else if (el is InstanceCreationExpression){
|
||||
return new CompileIdentifierMetadata(name: '${el.constructorName}', constConstructor: true);
|
||||
|
||||
} else if (el is NullLiteral) {
|
||||
return null;
|
||||
} else if (el is InstanceCreationExpression) {
|
||||
return new CompileIdentifierMetadata(
|
||||
name: '${el.constructorName}', constConstructor: true);
|
||||
} else {
|
||||
throw new ArgumentError('Incorrect identifier "${el}".');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ class TransformerUrlResolver implements UrlResolver {
|
||||
|
||||
if (!uri.isAbsolute) {
|
||||
if (baseUrl == null) throw new ArgumentError.notNull('baseUrl');
|
||||
if (baseUrl.isEmpty) throw new ArgumentError.value(
|
||||
'(empty string)', 'baseUrl');
|
||||
if (baseUrl.isEmpty)
|
||||
throw new ArgumentError.value('(empty string)', 'baseUrl');
|
||||
uri = Uri.parse(baseUrl).resolveUri(uri);
|
||||
}
|
||||
|
||||
@ -29,8 +29,8 @@ String toAssetUri(AssetId assetId) {
|
||||
|
||||
AssetId fromUri(String assetUri) {
|
||||
if (assetUri == null) throw new ArgumentError.notNull('assetUri');
|
||||
if (assetUri.isEmpty) throw new ArgumentError.value(
|
||||
'(empty string)', 'assetUri');
|
||||
if (assetUri.isEmpty)
|
||||
throw new ArgumentError.value('(empty string)', 'assetUri');
|
||||
var uri = toAssetScheme(Uri.parse(assetUri));
|
||||
return new AssetId(
|
||||
uri.pathSegments.first, uri.pathSegments.skip(1).join('/'));
|
||||
|
@ -64,20 +64,20 @@ Future<Map<String, String>> _processNgImports(NgDepsModel model,
|
||||
return Future
|
||||
.wait(
|
||||
importsAndExports.where(_isNotDartDirective).map((dynamic directive) {
|
||||
// Check whether the import or export generated summary NgMeta information.
|
||||
final summaryJsonUri =
|
||||
resolver.resolve(assetUri, toSummaryExtension(directive.uri));
|
||||
return reader.hasInput(fromUri(summaryJsonUri)).then((hasInput) {
|
||||
if (hasInput) {
|
||||
retVal[directive.uri] = summaryJsonUri;
|
||||
}
|
||||
}, onError: (err, stack) {
|
||||
log.warning(
|
||||
'Error while looking for $summaryJsonUri. '
|
||||
'Message: $err\n'
|
||||
'Stack: $stack',
|
||||
asset: assetId);
|
||||
});
|
||||
}))
|
||||
// Check whether the import or export generated summary NgMeta information.
|
||||
final summaryJsonUri =
|
||||
resolver.resolve(assetUri, toSummaryExtension(directive.uri));
|
||||
return reader.hasInput(fromUri(summaryJsonUri)).then((hasInput) {
|
||||
if (hasInput) {
|
||||
retVal[directive.uri] = summaryJsonUri;
|
||||
}
|
||||
}, onError: (err, stack) {
|
||||
log.warning(
|
||||
'Error while looking for $summaryJsonUri. '
|
||||
'Message: $err\n'
|
||||
'Stack: $stack',
|
||||
asset: assetId);
|
||||
});
|
||||
}))
|
||||
.then((_) => retVal);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ library angular2.transform.directive_metadata_linker.linker;
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:angular2/src/compiler/directive_metadata.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';
|
||||
@ -12,36 +13,40 @@ import 'package:barback/barback.dart';
|
||||
|
||||
import 'ng_deps_linker.dart';
|
||||
|
||||
/// Returns [NgMeta] associated with [entryPoint] combined with the [NgMeta] of
|
||||
/// Returns [NgMeta] associated with the provided asset 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.
|
||||
/// The returned NgMeta has all the identifiers resolved.
|
||||
///
|
||||
/// 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<NgMeta> linkDirectiveMetadata(
|
||||
AssetReader reader, AssetId assetId) async {
|
||||
var ngMeta = await _readNgMeta(reader, assetId);
|
||||
/// `summaryAssetId` - the unlinked asset id (source)
|
||||
/// `summaryAssetId` - the linked asset id (dest)
|
||||
/// `resolvedIdentifiers` - preresolved identifiers (e.g., Window)
|
||||
/// `ngMetas` - in memory cache of linked ngMeta files
|
||||
Future<NgMeta> linkDirectiveMetadata(AssetReader reader, AssetId summaryAssetId,
|
||||
AssetId metaAssetId, Map<String, String> resolvedIdentifiers,
|
||||
[Map<AssetId, NgMeta> ngMetas]) async {
|
||||
if (ngMetas == null) ngMetas = {};
|
||||
|
||||
var ngMeta = await _readNgMeta(reader, summaryAssetId, ngMetas);
|
||||
if (ngMeta == null || ngMeta.isEmpty) return null;
|
||||
|
||||
await Future.wait([
|
||||
linkNgDeps(ngMeta.ngDeps, reader, assetId, _urlResolver),
|
||||
linkNgDeps(ngMeta.ngDeps, reader, summaryAssetId, _urlResolver),
|
||||
logElapsedAsync(() async {
|
||||
await _linkRecursive(ngMeta, reader, assetId, new Set<String>());
|
||||
final linker = new _Linker(reader, ngMetas, resolvedIdentifiers);
|
||||
await linker.linkRecursive(ngMeta, metaAssetId, new Set<AssetId>());
|
||||
return ngMeta;
|
||||
}, operationName: 'linkDirectiveMetadata', assetId: assetId)
|
||||
}, operationName: 'linkDirectiveMetadata', assetId: summaryAssetId)
|
||||
]);
|
||||
|
||||
return ngMeta;
|
||||
}
|
||||
|
||||
Future<NgMeta> _readNgMeta(AssetReader reader, AssetId ngMetaAssetId) async {
|
||||
final _urlResolver = const TransformerUrlResolver();
|
||||
|
||||
Future<NgMeta> _readNgMeta(AssetReader reader, AssetId ngMetaAssetId,
|
||||
Map<AssetId, NgMeta> ngMetas) async {
|
||||
if (ngMetas.containsKey(ngMetaAssetId)) return ngMetas[ngMetaAssetId];
|
||||
if (!(await reader.hasInput(ngMetaAssetId))) return null;
|
||||
|
||||
var ngMetaJson = await reader.readAsString(ngMetaAssetId);
|
||||
@ -50,34 +55,381 @@ Future<NgMeta> _readNgMeta(AssetReader reader, AssetId ngMetaAssetId) async {
|
||||
return new NgMeta.fromJson(JSON.decode(ngMetaJson));
|
||||
}
|
||||
|
||||
final _urlResolver = const TransformerUrlResolver();
|
||||
class _Linker {
|
||||
final AssetReader reader;
|
||||
final Map<AssetId, NgMeta> ngMetas;
|
||||
final Map<String, String> resolvedIdentifiers;
|
||||
|
||||
_Linker(this.reader, this.ngMetas, this.resolvedIdentifiers);
|
||||
|
||||
Future<NgMeta> linkRecursive(NgMeta ngMeta, AssetId assetId, Set<AssetId> seen) async {
|
||||
if (seen.contains(assetId)) return ngMeta;
|
||||
|
||||
final newSeen = new Set.from(seen)
|
||||
..add(assetId);
|
||||
|
||||
await _resolveDeps(ngMeta, assetId, newSeen);
|
||||
await _resolveIdentifiers(ngMeta, assetId);
|
||||
await _mergeExports(ngMeta, assetId);
|
||||
|
||||
ngMetas[assetId] = ngMeta;
|
||||
|
||||
Future _linkRecursive(NgMeta ngMeta, AssetReader reader, AssetId assetId,
|
||||
Set<String> seen) async {
|
||||
if (ngMeta == null ||
|
||||
ngMeta.ngDeps == null ||
|
||||
ngMeta.ngDeps.exports == null) {
|
||||
return ngMeta;
|
||||
}
|
||||
var assetUri = toAssetUri(assetId);
|
||||
|
||||
return Future.wait(ngMeta.linkingUris
|
||||
.where((uri) => !isDartCoreUri(uri))
|
||||
.map((uri) =>
|
||||
_urlResolver.resolve(assetUri, toSummaryExtension(uri)))
|
||||
.where((uri) => !seen.contains(uri))
|
||||
.map((uri) async {
|
||||
seen.add(uri);
|
||||
try {
|
||||
final exportAssetId = fromUri(uri);
|
||||
final exportNgMeta = await _readNgMeta(reader, exportAssetId);
|
||||
if (exportNgMeta != null) {
|
||||
await _linkRecursive(exportNgMeta, reader, exportAssetId, seen);
|
||||
ngMeta.addAll(exportNgMeta);
|
||||
Future _resolveDeps(NgMeta ngMeta, AssetId assetId, Set<AssetId> seen) async {
|
||||
final importsAndExports = [];
|
||||
if (ngMeta != null &&
|
||||
ngMeta.ngDeps != null &&
|
||||
ngMeta.ngDeps.exports != null)
|
||||
importsAndExports.addAll(ngMeta.ngDeps.exports);
|
||||
|
||||
if (ngMeta != null &&
|
||||
ngMeta.needsResolution &&
|
||||
ngMeta.ngDeps != null &&
|
||||
ngMeta.ngDeps.imports != null)
|
||||
importsAndExports
|
||||
.addAll(ngMeta.ngDeps.imports.where((i) => !i.isDeferred));
|
||||
|
||||
final assetUri = toAssetUri(assetId);
|
||||
for (var withUri in importsAndExports) {
|
||||
if (isDartCoreUri(withUri.uri)) continue;
|
||||
final metaAsset =
|
||||
fromUri(_urlResolver.resolve(assetUri, toMetaExtension(withUri.uri)));
|
||||
final summaryAsset = fromUri(
|
||||
_urlResolver.resolve(assetUri, toSummaryExtension(withUri.uri)));
|
||||
|
||||
if (!await _hasMeta(metaAsset)) {
|
||||
final ngMeta = await _readSummary(summaryAsset);
|
||||
if (ngMeta != null) {
|
||||
await linkRecursive(ngMeta, metaAsset, seen);
|
||||
}
|
||||
}
|
||||
} catch (err, st) {
|
||||
// Log and continue.
|
||||
log.warning('Failed to fetch $uri. Message: $err.\n$st', asset: assetId);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
Future _resolveIdentifiers(NgMeta ngMeta, AssetId assetId) async {
|
||||
if (ngMeta.needsResolution) {
|
||||
final resolver = new _NgMetaIdentifierResolver(
|
||||
assetId, reader, ngMetas, resolvedIdentifiers);
|
||||
return resolver.resolveNgMeta(ngMeta);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future _mergeExports(NgMeta ngMeta, AssetId assetId) async {
|
||||
if (ngMeta == null ||
|
||||
ngMeta.ngDeps == null ||
|
||||
ngMeta.ngDeps.exports == null) {
|
||||
return ngMeta;
|
||||
}
|
||||
var assetUri = toAssetUri(assetId);
|
||||
|
||||
return Future.wait(ngMeta.ngDeps.exports.map((r) => r.uri)
|
||||
.where((export) => !isDartCoreUri(export))
|
||||
.map((export) =>
|
||||
_urlResolver.resolve(assetUri, toMetaExtension(export)))
|
||||
.map((uri) async {
|
||||
try {
|
||||
final exportAssetId = fromUri(uri);
|
||||
final exportNgMeta = await _readMeta(exportAssetId);
|
||||
if (exportNgMeta != null) {
|
||||
ngMeta.addAll(exportNgMeta);
|
||||
}
|
||||
} catch (err, st) {
|
||||
// Log and continue.
|
||||
log.warning('Failed to fetch $uri. Message: $err.\n$st',
|
||||
asset: assetId);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
Future<NgMeta> _readSummary(AssetId summaryAssetId) async {
|
||||
if (!(await reader.hasInput(summaryAssetId))) return null;
|
||||
|
||||
var ngMetaJson = await reader.readAsString(summaryAssetId);
|
||||
if (ngMetaJson == null || ngMetaJson.isEmpty) return null;
|
||||
return new NgMeta.fromJson(JSON.decode(ngMetaJson));
|
||||
}
|
||||
|
||||
Future<NgMeta> _readMeta(AssetId metaAssetId) async {
|
||||
final content = await _readNgMeta(reader, metaAssetId, ngMetas);
|
||||
if (content != null) {
|
||||
ngMetas[metaAssetId] = content;
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
Future<bool> _hasMeta(AssetId ngMetaAssetId) async {
|
||||
return ngMetas.containsKey(ngMetaAssetId) ||
|
||||
await reader.hasInput(ngMetaAssetId);
|
||||
}
|
||||
}
|
||||
|
||||
class _NgMetaIdentifierResolver {
|
||||
final Map<String, String> resolvedIdentifiers;
|
||||
final Map<AssetId, NgMeta> ngMetas;
|
||||
final AssetReader reader;
|
||||
final AssetId entryPoint;
|
||||
|
||||
_NgMetaIdentifierResolver(this.entryPoint, this.reader, this.ngMetas, this.resolvedIdentifiers);
|
||||
|
||||
Future resolveNgMeta(NgMeta ngMeta) async {
|
||||
final ngMetaMap = await _extractNgMetaMap(ngMeta);
|
||||
ngMeta.identifiers.forEach((_, meta) {
|
||||
if (meta is CompileIdentifierMetadata && meta.value != null) {
|
||||
meta.value = _resolveProviders(ngMetaMap, meta.value, "root");
|
||||
}
|
||||
});
|
||||
|
||||
ngMeta.identifiers.forEach((_, meta) {
|
||||
if (meta is CompileDirectiveMetadata) {
|
||||
_resolveProviderMetadata(ngMetaMap, meta);
|
||||
_resolveQueryMetadata(ngMetaMap, meta);
|
||||
_resolveDiDependencyMetadata(ngMetaMap, meta.type.name, meta.type.diDeps);
|
||||
} else if (meta is CompileTypeMetadata) {
|
||||
_resolveDiDependencyMetadata(ngMetaMap, meta.name, meta.diDeps);
|
||||
} else if (meta is CompileFactoryMetadata) {
|
||||
_resolveDiDependencyMetadata(ngMetaMap, meta.name, meta.diDeps);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
List<CompileProviderMetadata> _resolveProviders(Map<String, NgMeta> ngMetaMap, Object value, String neededBy) {
|
||||
|
||||
if (value is List) {
|
||||
final res = [];
|
||||
for (var v in value) {
|
||||
res.addAll(_resolveProviders(ngMetaMap, v, neededBy));
|
||||
}
|
||||
return res;
|
||||
|
||||
} else if (value is CompileProviderMetadata) {
|
||||
_resolveProvider(ngMetaMap, neededBy, value);
|
||||
|
||||
return [value];
|
||||
|
||||
} else if (value is CompileIdentifierMetadata) {
|
||||
final resolved = _resolveIdentifier(ngMetaMap, neededBy, value);
|
||||
if (resolved == null) return [];
|
||||
|
||||
if (resolved is CompileTypeMetadata) {
|
||||
return [new CompileProviderMetadata(token: resolved, useClass: resolved)];
|
||||
|
||||
} else if (resolved is CompileIdentifierMetadata && resolved.value is List) {
|
||||
return _resolveProviders(ngMetaMap, resolved.value, neededBy);
|
||||
|
||||
} else if (resolved is CompileIdentifierMetadata && resolved.value is CompileProviderMetadata) {
|
||||
return [_resolveProviders(ngMetaMap, resolved.value, neededBy)];
|
||||
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
void _resolveProviderMetadata(Map<String, NgMeta> ngMetaMap, CompileDirectiveMetadata dirMeta) {
|
||||
final neededBy = dirMeta.type.name;
|
||||
if (dirMeta.providers != null) {
|
||||
dirMeta.providers =
|
||||
_resolveProviders(ngMetaMap, dirMeta.providers, neededBy);
|
||||
}
|
||||
|
||||
if (dirMeta.viewProviders != null) {
|
||||
dirMeta.viewProviders =
|
||||
_resolveProviders(ngMetaMap, dirMeta.viewProviders, neededBy);
|
||||
}
|
||||
}
|
||||
|
||||
void _resolveQueryMetadata(Map<String, NgMeta> ngMetaMap, CompileDirectiveMetadata dirMeta) {
|
||||
final neededBy = dirMeta.type.name;
|
||||
if (dirMeta.queries != null) {
|
||||
_resolveQueries(ngMetaMap, dirMeta.queries, neededBy);
|
||||
}
|
||||
if (dirMeta.viewQueries != null) {
|
||||
_resolveQueries(ngMetaMap, dirMeta.viewQueries, neededBy);
|
||||
}
|
||||
}
|
||||
|
||||
void _resolveQueries(Map<String, NgMeta> ngMetaMap, List queries, String neededBy) {
|
||||
queries.forEach((q) {
|
||||
q.selectors = q.selectors.map((s) => _resolveIdentifier(ngMetaMap, neededBy, s)).toList();
|
||||
});
|
||||
}
|
||||
|
||||
void _resolveProvider(Map<String, NgMeta> ngMetaMap,
|
||||
String neededBy, CompileProviderMetadata provider) {
|
||||
provider.token = _resolveIdentifier(ngMetaMap, neededBy, provider.token);
|
||||
if (provider.useClass != null) {
|
||||
provider.useClass =
|
||||
_resolveIdentifier(ngMetaMap, neededBy, provider.useClass);
|
||||
}
|
||||
if (provider.useExisting != null) {
|
||||
provider.useExisting =
|
||||
_resolveIdentifier(ngMetaMap, neededBy, provider.useExisting);
|
||||
}
|
||||
if (provider.useValue != null) {
|
||||
provider.useValue =
|
||||
_resolveIdentifier(ngMetaMap, neededBy, provider.useValue);
|
||||
}
|
||||
if (provider.useFactory != null) {
|
||||
provider.useFactory = _resolveIdentifier(ngMetaMap, neededBy, provider.useFactory);
|
||||
}
|
||||
if (provider.deps != null) {
|
||||
_resolveDiDependencyMetadata(ngMetaMap, neededBy, provider.deps);
|
||||
};;
|
||||
}
|
||||
|
||||
void _resolveDiDependencyMetadata(Map<String, NgMeta> ngMetaMap,
|
||||
String neededBy, List<CompileDiDependencyMetadata> deps) {
|
||||
if (deps == null) return;
|
||||
for (var dep in deps) {
|
||||
_setModuleUrl(ngMetaMap, neededBy, dep.token);
|
||||
if (dep.query != null) {
|
||||
dep.query.selectors
|
||||
.forEach((s) => _setModuleUrl(ngMetaMap, neededBy, s));
|
||||
}
|
||||
if (dep.viewQuery != null) {
|
||||
dep.viewQuery.selectors
|
||||
.forEach((s) => _setModuleUrl(ngMetaMap, neededBy, s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _setModuleUrl(Map<String, NgMeta> ngMetaMap, String neededBy, dynamic id) {
|
||||
final resolved = _resolveIdentifier(ngMetaMap, neededBy, id);
|
||||
if (resolved != null && id is CompileIdentifierMetadata) {
|
||||
id.moduleUrl = resolved.moduleUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves an identifier using the provided ngMetaMap.
|
||||
///
|
||||
/// ngMetaMap - a map of prefixes to the symbols available via those prefixes
|
||||
/// neededBy - a type using the unresolved symbol. It's used to generate
|
||||
/// good error message.
|
||||
/// id - an unresolved id.
|
||||
dynamic _resolveIdentifier(Map<String, NgMeta> ngMetaMap, String neededBy, dynamic id) {
|
||||
if (id is String || id is bool || id is num || id == null) return id;
|
||||
if (id is CompileMetadataWithIdentifier) {
|
||||
id = id.identifier;
|
||||
}
|
||||
|
||||
if (id.moduleUrl != null) return id;
|
||||
|
||||
final prefix = id.prefix == null ? "" : id.prefix;
|
||||
|
||||
if (!ngMetaMap.containsKey(prefix)) {
|
||||
final resolved = _resolveSpecialCases(id);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
} else {
|
||||
log.error(
|
||||
'Missing prefix "${prefix}" '
|
||||
'needed by "${neededBy}" from metadata map',
|
||||
asset: entryPoint);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final depNgMeta = ngMetaMap[prefix];
|
||||
if (depNgMeta.identifiers.containsKey(id.name)) {
|
||||
final res = depNgMeta.identifiers[id.name];
|
||||
if (res is CompileMetadataWithIdentifier) {
|
||||
return res.identifier;
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
} else if (_isPrimitive(id.name)) {
|
||||
return id;
|
||||
} else {
|
||||
final resolved = _resolveSpecialCases(id);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
} else {
|
||||
log.error(
|
||||
'Missing identifier "${id.name}" '
|
||||
'needed by "${neededBy}" from metadata map',
|
||||
asset: entryPoint);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic _resolveSpecialCases(CompileIdentifierMetadata id) {
|
||||
if (resolvedIdentifiers != null &&
|
||||
resolvedIdentifiers.containsKey(id.name)) {
|
||||
return new CompileIdentifierMetadata(
|
||||
name: id.name, moduleUrl: resolvedIdentifiers[id.name]);
|
||||
|
||||
// these are so common that we special case them in the transformer
|
||||
} else if (id.name == "Window" || id.name == "Document") {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'dart:html');
|
||||
} else if (id.name == "Logger") {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:logging/lib/logging.dart');
|
||||
} else if (id.name == "Clock") {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:quiver/lib/src/time/clock.dart');
|
||||
} else if (id.name == "Log") {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:angular2/lib/src/testing/utils.dart');
|
||||
} else if (id.name == "TestComponentBuilder") {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:angular2/lib/src/testing/test_component_builder.dart');
|
||||
} else if (id.name == "FakeAsync") {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:angular2/lib/src/testing/fake_async.dart');
|
||||
} else if (id.name == "StreamTracer") {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:streamy/lib/src/core/tracing.dart');
|
||||
} else if (id.name == "Tracer") {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:streamy/lib/src/core/tracing.dart');
|
||||
} else if (id.name == "RequestHandler") {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: 'asset:streamy/lib/src/core/request_handler.dart');
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
bool _isPrimitive(String typeName) =>
|
||||
typeName == "String" ||
|
||||
typeName == "Object" ||
|
||||
typeName == "num" ||
|
||||
typeName == "int" ||
|
||||
typeName == "double" ||
|
||||
typeName == "bool" ||
|
||||
typeName == "dynamic";
|
||||
|
||||
/// Walks all the imports and creates a map from prefixes to
|
||||
/// all the symbols available through those prefixes
|
||||
Future<Map<String, NgMeta>> _extractNgMetaMap(NgMeta ngMeta) async {
|
||||
final res = {"": new NgMeta.empty()};
|
||||
res[""].addAll(ngMeta);
|
||||
|
||||
if (ngMeta.ngDeps == null || ngMeta.ngDeps.imports == null) return res;
|
||||
|
||||
for (var import in ngMeta.ngDeps.imports) {
|
||||
if (isDartCoreUri(import.uri)) continue;
|
||||
|
||||
final assetUri = toAssetUri(entryPoint);
|
||||
final metaAsset =
|
||||
fromUri(_urlResolver.resolve(assetUri, toMetaExtension(import.uri)));
|
||||
final newMeta = await _readNgMeta(reader, metaAsset, ngMetas);
|
||||
|
||||
if (!res.containsKey(import.prefix)) {
|
||||
res[import.prefix] = new NgMeta.empty();
|
||||
}
|
||||
|
||||
if (newMeta != null) {
|
||||
res[import.prefix].addAll(newMeta);
|
||||
} else {
|
||||
final summaryAsset =
|
||||
fromUri(_urlResolver.resolve(assetUri, toSummaryExtension(import.uri)));
|
||||
final summary = await _readNgMeta(reader, summaryAsset, {});
|
||||
if (summary != null) {
|
||||
res[import.prefix].addAll(summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import 'package:barback/barback.dart';
|
||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||
import 'package:angular2/src/transform/common/names.dart';
|
||||
import 'package:angular2/src/transform/common/zone.dart' as zone;
|
||||
import 'package:angular2/src/transform/common/options.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart';
|
||||
|
||||
import 'ng_meta_linker.dart';
|
||||
|
||||
@ -33,6 +35,12 @@ import 'ng_meta_linker.dart';
|
||||
class DirectiveMetadataLinker extends Transformer implements LazyTransformer {
|
||||
final _encoder = const JsonEncoder.withIndent(' ');
|
||||
|
||||
final TransformerOptions options;
|
||||
final Map ngMetasCache = {};
|
||||
final Set<String> errorMessages = new Set<String>();
|
||||
|
||||
DirectiveMetadataLinker(this.options);
|
||||
|
||||
@override
|
||||
bool isPrimary(AssetId id) => id.path.endsWith(SUMMARY_META_EXTENSION);
|
||||
|
||||
@ -47,7 +55,11 @@ class DirectiveMetadataLinker extends Transformer implements LazyTransformer {
|
||||
var primaryId = transform.primaryInput.id;
|
||||
|
||||
return linkDirectiveMetadata(
|
||||
new AssetReader.fromTransform(transform), primaryId).then((ngMeta) {
|
||||
new AssetReader.fromTransform(transform),
|
||||
primaryId,
|
||||
_ngLinkedAssetId(primaryId),
|
||||
options.resolvedIdentifiers,
|
||||
ngMetasCache).then((ngMeta) {
|
||||
if (ngMeta != null) {
|
||||
final outputId = _ngLinkedAssetId(primaryId);
|
||||
// Not outputting an asset could confuse barback.
|
||||
@ -55,7 +67,7 @@ class DirectiveMetadataLinker extends Transformer implements LazyTransformer {
|
||||
transform.addOutput(new Asset.fromString(outputId, output));
|
||||
}
|
||||
});
|
||||
}, log: transform.logger);
|
||||
}, log: new DeduppingLogger(transform.logger, errorMessages));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,8 @@ import 'dart:async';
|
||||
import 'package:analyzer/analyzer.dart';
|
||||
import 'package:barback/barback.dart' show AssetId;
|
||||
|
||||
import 'package:angular2/src/compiler/directive_metadata.dart' show CompileIdentifierMetadata;
|
||||
import 'package:angular2/src/compiler/directive_metadata.dart'
|
||||
show CompileIdentifierMetadata, CompileProviderMetadata;
|
||||
import 'package:angular2/src/compiler/template_compiler.dart';
|
||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||
@ -90,13 +91,15 @@ class _NgMetaVisitor extends Object with SimpleAstVisitor<Object> {
|
||||
|
||||
@override
|
||||
Object visitClassDeclaration(ClassDeclaration node) {
|
||||
_normalizations.add(
|
||||
_reader.readTypeMetadata(node, assetId).then((compileMetadataWithIdentifier) {
|
||||
if (compileMetadataWithIdentifier!= null) {
|
||||
_normalizations.add(_reader
|
||||
.readTypeMetadata(node, assetId)
|
||||
.then((compileMetadataWithIdentifier) {
|
||||
if (compileMetadataWithIdentifier != null) {
|
||||
ngMeta.identifiers[compileMetadataWithIdentifier.identifier.name] =
|
||||
compileMetadataWithIdentifier;
|
||||
} else {
|
||||
ngMeta.identifiers[node.name.name] = new CompileIdentifierMetadata(name: node.name.name, moduleUrl: toAssetUri(assetId));
|
||||
ngMeta.identifiers[node.name.name] = new CompileIdentifierMetadata(
|
||||
name: node.name.name, moduleUrl: toAssetUri(assetId));
|
||||
}
|
||||
}).catchError((err) {
|
||||
log.error('ERROR: $err', asset: assetId);
|
||||
@ -114,8 +117,8 @@ class _NgMetaVisitor extends Object with SimpleAstVisitor<Object> {
|
||||
// angular/angular#1747 and angular/ts2dart#249 for context).
|
||||
outer: for (var variable in node.variables.variables) {
|
||||
if (variable.isConst) {
|
||||
ngMeta.identifiers[variable.name.name] =
|
||||
new CompileIdentifierMetadata(name: variable.name.name, moduleUrl: toAssetUri(assetId));
|
||||
final id = _reader.readIdentifierMetadata(variable, assetId);
|
||||
ngMeta.identifiers[variable.name.name] = id;
|
||||
}
|
||||
|
||||
var initializer = variable.initializer;
|
||||
@ -127,7 +130,6 @@ class _NgMetaVisitor extends Object with SimpleAstVisitor<Object> {
|
||||
if (exp is! SimpleIdentifier) continue outer;
|
||||
otherNames.add(exp.name);
|
||||
}
|
||||
ngMeta.definesAlias = true;
|
||||
ngMeta.aliases[variable.name.name] = otherNames;
|
||||
}
|
||||
}
|
||||
@ -136,15 +138,33 @@ class _NgMetaVisitor extends Object with SimpleAstVisitor<Object> {
|
||||
|
||||
@override
|
||||
Object visitFunctionTypeAlias(FunctionTypeAlias node) {
|
||||
ngMeta.identifiers[node.name.name] =
|
||||
new CompileIdentifierMetadata(name: node.name.name, moduleUrl: toAssetUri(assetId));
|
||||
ngMeta.identifiers[node.name.name] = new CompileIdentifierMetadata(
|
||||
name: node.name.name, moduleUrl: toAssetUri(assetId));
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
_normalizations.add(_reader
|
||||
.readFactoryMetadata(node, assetId)
|
||||
.then((compileMetadataWithIdentifier) {
|
||||
if (compileMetadataWithIdentifier != null) {
|
||||
ngMeta.identifiers[compileMetadataWithIdentifier.identifier.name] =
|
||||
compileMetadataWithIdentifier;
|
||||
} else {
|
||||
ngMeta.identifiers[node.name.name] = new CompileIdentifierMetadata(
|
||||
name: node.name.name, moduleUrl: toAssetUri(assetId));
|
||||
}
|
||||
}).catchError((err) {
|
||||
log.error('ERROR: $err', asset: assetId);
|
||||
}));
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitEnumDeclaration(EnumDeclaration node) {
|
||||
ngMeta.identifiers[node.name.name] =
|
||||
new CompileIdentifierMetadata(name: node.name.name, moduleUrl: toAssetUri(assetId));
|
||||
ngMeta.identifiers[node.name.name] = new CompileIdentifierMetadata(
|
||||
name: node.name.name, moduleUrl: toAssetUri(assetId));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -123,8 +123,8 @@ class _CodegenState {
|
||||
|
||||
var names = new CodegenNameUtil(
|
||||
protoRecords, eventBindings, def.directiveRecords, '$genPrefix$_UTIL');
|
||||
var logic = new CodegenLogicUtil(
|
||||
names, '$genPrefix$_UTIL', '$genPrefix$_STATE');
|
||||
var logic =
|
||||
new CodegenLogicUtil(names, '$genPrefix$_UTIL', '$genPrefix$_STATE');
|
||||
return new _CodegenState._(
|
||||
genPrefix,
|
||||
def.id,
|
||||
|
@ -29,20 +29,18 @@ Future<CompileDataResults> createCompileData(
|
||||
AssetReader reader,
|
||||
AssetId assetId,
|
||||
List<String> platformDirectives,
|
||||
List<String> platformPipes,
|
||||
Map<String, String> resolvedIdentifiers
|
||||
) async {
|
||||
List<String> platformPipes) async {
|
||||
return logElapsedAsync(() async {
|
||||
final creator = await _CompileDataCreator.create(
|
||||
reader, assetId, platformDirectives, platformPipes, resolvedIdentifiers);
|
||||
reader, assetId, platformDirectives, platformPipes);
|
||||
return creator != null ? creator.createCompileData() : null;
|
||||
}, operationName: 'createCompileData', assetId: assetId);
|
||||
}
|
||||
|
||||
class CompileDataResults {
|
||||
final NgMeta ngMeta;
|
||||
final Map<ReflectionInfoModel,
|
||||
NormalizedComponentWithViewDirectives> viewDefinitions;
|
||||
final Map<ReflectionInfoModel, NormalizedComponentWithViewDirectives>
|
||||
viewDefinitions;
|
||||
|
||||
CompileDataResults._(this.ngMeta, this.viewDefinitions);
|
||||
}
|
||||
@ -55,20 +53,19 @@ class _CompileDataCreator {
|
||||
final NgMeta ngMeta;
|
||||
final List<String> platformDirectives;
|
||||
final List<String> platformPipes;
|
||||
final Map<String, String> resolvedIdentifiers;
|
||||
|
||||
_CompileDataCreator(this.reader, this.entryPoint, this.ngMeta,
|
||||
this.platformDirectives, this.platformPipes, this.resolvedIdentifiers);
|
||||
this.platformDirectives, this.platformPipes);
|
||||
|
||||
static Future<_CompileDataCreator> create(AssetReader reader, AssetId assetId,
|
||||
List<String> platformDirectives, List<String> platformPipes, Map<String, String> resolvedIdentifiers) async {
|
||||
List<String> platformDirectives, List<String> platformPipes) async {
|
||||
if (!(await reader.hasInput(assetId))) return null;
|
||||
final json = await reader.readAsString(assetId);
|
||||
if (json == null || json.isEmpty) return null;
|
||||
|
||||
final ngMeta = new NgMeta.fromJson(JSON.decode(json));
|
||||
return new _CompileDataCreator(
|
||||
reader, assetId, ngMeta, platformDirectives, platformPipes, resolvedIdentifiers);
|
||||
reader, assetId, ngMeta, platformDirectives, platformPipes);
|
||||
}
|
||||
|
||||
NgDepsModel get ngDeps => ngMeta.ngDeps;
|
||||
@ -84,14 +81,15 @@ class _CompileDataCreator {
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!hasTemplate) return new CompileDataResults._(ngMeta, const {});
|
||||
|
||||
final compileData =
|
||||
<ReflectionInfoModel, NormalizedComponentWithViewDirectives>{};
|
||||
final ngMetaMap = await _extractNgMeta();
|
||||
final platformDirectives =
|
||||
await _readPlatformTypes(this.platformDirectives, 'directives');
|
||||
final platformPipes = await _readPlatformTypes(this.platformPipes, 'pipes');
|
||||
final ngMetaMap = await _extractNgMeta();
|
||||
|
||||
for (var reflectable in ngDeps.reflectables) {
|
||||
if (ngMeta.identifiers.containsKey(reflectable.name)) {
|
||||
@ -109,9 +107,6 @@ class _CompileDataCreator {
|
||||
compileDatum.pipes
|
||||
.addAll(_resolveTypeMetadata(ngMetaMap, reflectable.pipes));
|
||||
compileData[reflectable] = compileDatum;
|
||||
|
||||
_resolveDiDependencyMetadata(ngMetaMap, compileDirectiveMetadata.type, compileDirectiveMetadata.type.diDeps);
|
||||
_resolveProviderMetadata(ngMetaMap, compileDirectiveMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,11 +125,12 @@ class _CompileDataCreator {
|
||||
return null;
|
||||
}
|
||||
final depNgMeta = ngMetaMap[dep.prefix];
|
||||
|
||||
if (depNgMeta.identifiers.containsKey(dep.name)) {
|
||||
resolvedMetadata.add(depNgMeta.identifiers[dep.name]);
|
||||
} else if (depNgMeta.aliases.containsKey(dep.name)) {
|
||||
if (depNgMeta.aliases.containsKey(dep.name)) {
|
||||
resolvedMetadata.addAll(depNgMeta.flatten(dep.name));
|
||||
|
||||
} else if (depNgMeta.identifiers.containsKey(dep.name)) {
|
||||
resolvedMetadata.add(depNgMeta.identifiers[dep.name]);
|
||||
|
||||
} else {
|
||||
log.error(
|
||||
'Could not find Directive/Pipe entry for $dep. '
|
||||
@ -147,98 +143,6 @@ class _CompileDataCreator {
|
||||
return resolvedMetadata;
|
||||
}
|
||||
|
||||
void _resolveProviderMetadata(Map<String, NgMeta> ngMetaMap, CompileDirectiveMetadata dirMeta) {
|
||||
final neededBy = dirMeta.type;
|
||||
|
||||
if (dirMeta.providers == null) return;
|
||||
|
||||
final resolvedProviders = [];
|
||||
for (var provider in dirMeta.providers) {
|
||||
final alias = _resolveAlias(ngMetaMap, neededBy, provider.token);
|
||||
if (alias != null) {
|
||||
resolvedProviders.addAll(alias.map((a) => new CompileProviderMetadata(token:a)));
|
||||
} else {
|
||||
provider.token = _resolveIdentifier(ngMetaMap, neededBy, provider.token);
|
||||
if (provider.useClass != null) {
|
||||
provider.useClass = _resolveIdentifier(ngMetaMap, neededBy, provider.useClass);
|
||||
}
|
||||
resolvedProviders.add(provider);
|
||||
}
|
||||
}
|
||||
|
||||
dirMeta.providers = resolvedProviders;
|
||||
}
|
||||
|
||||
void _resolveDiDependencyMetadata(
|
||||
Map<String, NgMeta> ngMetaMap,CompileTypeMetadata neededBy, List<CompileDiDependencyMetadata> deps) {
|
||||
if (deps == null) return;
|
||||
for (var dep in deps) {
|
||||
dep.token = _resolveIdentifier(ngMetaMap, neededBy, dep.token);
|
||||
if (dep.query != null) {
|
||||
dep.query.selectors = dep.query.selectors.map((s) => _resolveIdentifier(ngMetaMap, neededBy, s)).toList();
|
||||
}
|
||||
if (dep.viewQuery != null) {
|
||||
dep.viewQuery.selectors = dep.viewQuery.selectors.map((s) => _resolveIdentifier(ngMetaMap, neededBy, s)).toList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic _resolveAlias(Map<String, NgMeta> ngMetaMap, CompileTypeMetadata neededBy, dynamic id) {
|
||||
if (id is String || id == null) return null;
|
||||
|
||||
final prefix = id.prefix == null ? "" : id.prefix;
|
||||
|
||||
if (!ngMetaMap.containsKey(prefix)) {
|
||||
log.error(
|
||||
'Missing prefix "${prefix}" '
|
||||
'needed by "${neededBy.name}" from metadata map',
|
||||
asset: entryPoint);
|
||||
return null;
|
||||
}
|
||||
|
||||
final depNgMeta = ngMetaMap[prefix];
|
||||
if (depNgMeta.aliases.containsKey(id.name)) {
|
||||
return depNgMeta.flatten(id.name);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
dynamic _resolveIdentifier(Map<String, NgMeta> ngMetaMap, CompileTypeMetadata neededBy, dynamic id) {
|
||||
if (id is String || id == null) return id;
|
||||
|
||||
final prefix = id.prefix == null ? "" : id.prefix;
|
||||
|
||||
if (!ngMetaMap.containsKey(prefix)) {
|
||||
log.error(
|
||||
'Missing prefix "${prefix}" '
|
||||
'needed by "${neededBy.name}" from metadata map',
|
||||
asset: entryPoint);
|
||||
return null;
|
||||
}
|
||||
|
||||
final depNgMeta = ngMetaMap[prefix];
|
||||
if (depNgMeta.identifiers.containsKey(id.name)) {
|
||||
return depNgMeta.identifiers[id.name];
|
||||
|
||||
} else if (_isPrimitive(id.name)) {
|
||||
return id;
|
||||
|
||||
} else if (resolvedIdentifiers != null && resolvedIdentifiers.containsKey(id.name)) {
|
||||
return new CompileIdentifierMetadata(name: id.name, moduleUrl: resolvedIdentifiers[id.name]);
|
||||
|
||||
} else {
|
||||
log.error(
|
||||
'Missing identifier "${id.name}" '
|
||||
'needed by "${neededBy.name}" from metadata map',
|
||||
asset: entryPoint);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
bool _isPrimitive(String typeName) =>
|
||||
typeName == "String" || typeName == "Object" || typeName == "num" || typeName == "int" || typeName == "double" || typeName == "bool";
|
||||
|
||||
Future<List<dynamic>> _readPlatformTypes(
|
||||
List<String> inputPlatformTypes, String configOption) async {
|
||||
if (inputPlatformTypes == null) return const [];
|
||||
@ -266,10 +170,12 @@ class _CompileDataCreator {
|
||||
if (jsonString != null && jsonString.isNotEmpty) {
|
||||
var newMetadata = new NgMeta.fromJson(JSON.decode(jsonString));
|
||||
|
||||
if (newMetadata.identifiers.containsKey(token)) {
|
||||
return [newMetadata.identifiers[token]];
|
||||
} else if (newMetadata.aliases.containsKey(token)) {
|
||||
if (newMetadata.aliases.containsKey(token)) {
|
||||
return newMetadata.flatten(token);
|
||||
|
||||
} else if (newMetadata.identifiers.containsKey(token)) {
|
||||
return [newMetadata.identifiers[token]];
|
||||
|
||||
} else {
|
||||
log.warning('Could not resolve platform type ${token} in ${uri}',
|
||||
asset: metaAssetId);
|
||||
|
@ -44,7 +44,7 @@ Future<Outputs> processTemplates(AssetReader reader, AssetId assetId,
|
||||
Map<String, String> resolvedIdentifiers
|
||||
}) async {
|
||||
var viewDefResults = await createCompileData(
|
||||
reader, assetId, platformDirectives, platformPipes, resolvedIdentifiers);
|
||||
reader, assetId, platformDirectives, platformPipes);
|
||||
if (viewDefResults == null) return null;
|
||||
final compileTypeMetadatas = viewDefResults.ngMeta.identifiers.values;
|
||||
if (compileTypeMetadatas.isNotEmpty) {
|
||||
@ -106,4 +106,4 @@ class Outputs {
|
||||
final SourceModule templatesSource;
|
||||
|
||||
Outputs._(this.ngDeps, this.templatesSource);
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class AngularTransformerGroup extends TransformerGroup {
|
||||
} else {
|
||||
phases = [
|
||||
[new DirectiveProcessor(options)],
|
||||
[new DirectiveMetadataLinker()],
|
||||
[new DirectiveMetadataLinker(options)],
|
||||
[new ReflectionRemover(options)],
|
||||
[
|
||||
new DeferredRewriter(),
|
||||
|
@ -39,7 +39,7 @@ class CodegenTransformer extends TransformerGroup {
|
||||
} else {
|
||||
phases = [
|
||||
[new DirectiveProcessor(options)],
|
||||
[new DirectiveMetadataLinker()],
|
||||
[new DirectiveMetadataLinker(options)],
|
||||
[new StylesheetCompiler(), new TemplateCompiler(options),],
|
||||
];
|
||||
}
|
||||
|
Reference in New Issue
Block a user