| Index: third_party/pkg/angular/lib/tools/source_metadata_extractor.dart
|
| diff --git a/third_party/pkg/angular/lib/tools/source_metadata_extractor.dart b/third_party/pkg/angular/lib/tools/source_metadata_extractor.dart
|
| index ebe36844f4310f0c4befee126d5bfe851757a3b5..9752358c3d2ea95e4d26f72d2b00f1512f7e66fe 100644
|
| --- a/third_party/pkg/angular/lib/tools/source_metadata_extractor.dart
|
| +++ b/third_party/pkg/angular/lib/tools/source_metadata_extractor.dart
|
| @@ -1,6 +1,7 @@
|
| library angular.source_metadata_extractor ;
|
|
|
| import 'package:analyzer/src/generated/ast.dart';
|
| +import 'package:analyzer/src/generated/element.dart';
|
|
|
| import 'package:angular/tools/source_crawler.dart';
|
| import 'package:angular/tools/common.dart';
|
| @@ -98,7 +99,7 @@ class SourceMetadataExtractor {
|
| dirInfo.expressionAttrs.forEach((String attr) {
|
| if (attr == '.') {
|
| var matches = _ATTR_SELECTOR_REGEXP.allMatches(dirInfo.selector);
|
| - if (matches.length > 0) {
|
| + if (matches.isNotEmpty) {
|
| reprocessedAttrs.add(matches.last.group(1));
|
| }
|
| } else {
|
| @@ -107,87 +108,120 @@ class SourceMetadataExtractor {
|
| });
|
| dirInfo.expressionAttrs = reprocessedAttrs;
|
| directives.add(dirInfo);
|
| -
|
| });
|
|
|
| + directives.addAll(metadataVisitor.templates.map(
|
| + (tmpl) => new DirectiveInfo()..template = tmpl));
|
| +
|
| return directives;
|
| }
|
| }
|
|
|
| -class DirectiveMetadataCollectingVisitor {
|
| - List<DirectiveMetadata> metadata = <DirectiveMetadata>[];
|
| +class DirectiveMetadataCollectingAstVisitor extends RecursiveAstVisitor {
|
| + final List<DirectiveMetadata> metadata;
|
| + final List<String> templates;
|
| +
|
| + DirectiveMetadataCollectingAstVisitor(this.metadata, this.templates);
|
| +
|
| + visitMethodInvocation(MethodInvocation node) {
|
| + if (node.methodName.name == 'ngRoute') {
|
| + NamedExpression viewHtmlExpression =
|
| + node.argumentList.arguments
|
| + .firstWhere((e) => e is NamedExpression &&
|
| + e.name.label.name == 'viewHtml', orElse: () => null);
|
| + if (viewHtmlExpression != null) {
|
| + if (viewHtmlExpression.expression is! StringLiteral) {
|
| + throw 'viewHtml must be a string literal';
|
| + }
|
| + templates.add(
|
| + (viewHtmlExpression.expression as StringLiteral).stringValue);
|
| + }
|
| + }
|
| + super.visitMethodInvocation(node);
|
| + }
|
|
|
| - call(CompilationUnit cu) {
|
| - cu.declarations.forEach((CompilationUnitMember declaration) {
|
| - // We only care about classes.
|
| - if (declaration is! ClassDeclaration) return;
|
| - ClassDeclaration clazz = declaration;
|
| - // Check class annotations for presense of NgComponent/NgDirective.
|
| - DirectiveMetadata meta;
|
| - clazz.metadata.forEach((Annotation ann) {
|
| - if (ann.arguments == null) return; // Ignore non-class annotations.
|
| - // TODO(pavelj): this is not a safe check for the type of the
|
| - // annotations, but good enough for now.
|
| - if (ann.name.name != 'NgComponent'
|
| - && ann.name.name != 'NgDirective') return;
|
| -
|
| - bool isComponent = ann.name.name == 'NgComponent';
|
| -
|
| - meta = new DirectiveMetadata()
|
| - ..className = clazz.name.name
|
| - ..type = isComponent ? COMPONENT : DIRECTIVE;
|
| - metadata.add(meta);
|
| -
|
| - ann.arguments.arguments.forEach((Expression arg) {
|
| - if (arg is NamedExpression) {
|
| - NamedExpression namedArg = arg;
|
| - var paramName = namedArg.name.label.name;
|
| - if (paramName == 'selector') {
|
| - meta.selector = assertString(namedArg.expression).stringValue;
|
| - }
|
| - if (paramName == 'template') {
|
| - meta.template = assertString(namedArg.expression).stringValue;
|
| - }
|
| - if (paramName == 'map') {
|
| - MapLiteral map = namedArg.expression;
|
| - map.entries.forEach((MapLiteralEntry entry) {
|
| - meta.attributeMappings[assertString(entry.key).stringValue] =
|
| - assertString(entry.value).stringValue;
|
| - });
|
| - }
|
| - if (paramName == 'exportExpressions') {
|
| - meta.exportExpressions = getStringValues(namedArg.expression);
|
| - }
|
| - if (paramName == 'exportExpressionAttrs') {
|
| - meta.exportExpressionAttrs = getStringValues(namedArg.expression);
|
| - }
|
| + visitClassDeclaration(ClassDeclaration clazz) {
|
| + // Check class annotations for presense of Component/Decorator.
|
| + clazz.metadata.forEach((Annotation ann) {
|
| + if (ann.arguments == null) return; // Ignore non-class annotations.
|
| + // TODO(pavelj): this is not a safe check for the type of the
|
| + // annotations, but good enough for now.
|
| + if (ann.name.name != 'Component'
|
| + && ann.name.name != 'Decorator') return;
|
| +
|
| + bool isComponent = ann.name.name == 'Component';
|
| +
|
| + var meta = new DirectiveMetadata()
|
| + ..className = clazz.name.name
|
| + ..type = isComponent ? COMPONENT : DIRECTIVE;
|
| + metadata.add(meta);
|
| +
|
| + ann.arguments.arguments.forEach((Expression arg) {
|
| + if (arg is NamedExpression) {
|
| + NamedExpression namedArg = arg;
|
| + var paramName = namedArg.name.label.name;
|
| + if (paramName == 'selector') {
|
| + meta.selector = assertString(namedArg.expression).stringValue;
|
| }
|
| - });
|
| + if (paramName == 'template') {
|
| + meta.template = assertString(namedArg.expression).stringValue;
|
| + }
|
| + if (paramName == 'map') {
|
| + MapLiteral map = namedArg.expression;
|
| + map.entries.forEach((MapLiteralEntry entry) {
|
| + meta.attributeMappings[assertString(entry.key).stringValue] =
|
| + assertString(entry.value).stringValue;
|
| + });
|
| + }
|
| + if (paramName == 'exportExpressions') {
|
| + meta.exportExpressions = getStringValues(namedArg.expression);
|
| + }
|
| + if (paramName == 'exportExpressionAttrs') {
|
| + meta.exportExpressionAttrs = getStringValues(namedArg.expression);
|
| + }
|
| + }
|
| });
|
|
|
| - // Check fields/getters/setter for presense of attr mapping annotations.
|
| - if (meta != null) {
|
| - clazz.members.forEach((ClassMember member) {
|
| - if (member is FieldDeclaration ||
|
| - (member is MethodDeclaration &&
|
| - (member.isSetter || member.isGetter))) {
|
| - member.metadata.forEach((Annotation ann) {
|
| - if (_attrAnnotationsToSpec.containsKey(ann.name.name)) {
|
| - String fieldName;
|
| - if (member is FieldDeclaration) {
|
| - fieldName = member.fields.variables.first.name.name;
|
| - } else { // MethodDeclaration
|
| - fieldName = (member as MethodDeclaration).name.name;
|
| - }
|
| - StringLiteral attNameLiteral = ann.arguments.arguments.first;
|
| - if (meta.attributeMappings
|
| - .containsKey(attNameLiteral.stringValue)) {
|
| - throw 'Attribute mapping already defined for $fieldName';
|
| - }
|
| - meta.attributeMappings[attNameLiteral.stringValue] =
|
| - _attrAnnotationsToSpec[ann.name.name] + fieldName;
|
| - }
|
| - });
|
| + if (meta != null) _walkSuperclassChain(clazz, meta, _extractMappingsFromClass);
|
| + });
|
| +
|
| + return super.visitClassDeclaration(clazz);
|
| + }
|
| +
|
| + _walkSuperclassChain(ClassDeclaration clazz, DirectiveMetadata meta,
|
| + metadataExtractor(ClassDeclaration clazz, DirectiveMetadata meta)) {
|
| + while (clazz != null) {
|
| + metadataExtractor(clazz, meta);
|
| + if (clazz.element != null && clazz.element.supertype != null) {
|
| + clazz = clazz.element.supertype.element.node;
|
| + } else {
|
| + clazz = null;
|
| + }
|
| + }
|
| + }
|
| +
|
| + _extractMappingsFromClass(ClassDeclaration clazz, DirectiveMetadata meta) {
|
| + // Check fields/getters/setter for presence of attr mapping annotations.
|
| + clazz.members.forEach((ClassMember member) {
|
| + if (member is FieldDeclaration ||
|
| + (member is MethodDeclaration &&
|
| + (member.isSetter || member.isGetter))) {
|
| + member.metadata.forEach((Annotation ann) {
|
| + if (_attrAnnotationsToSpec.containsKey(ann.name.name)) {
|
| + String fieldName;
|
| + if (member is FieldDeclaration) {
|
| + fieldName = member.fields.variables.first.name.name;
|
| + } else { // MethodDeclaration
|
| + fieldName = (member as MethodDeclaration).name.name;
|
| + }
|
| + StringLiteral attNameLiteral = ann.arguments.arguments.first;
|
| + if (meta.attributeMappings
|
| + .containsKey(attNameLiteral.stringValue)) {
|
| + throw 'Attribute mapping already defined for '
|
| + '${clazz.name}.$fieldName';
|
| + }
|
| + meta.attributeMappings[attNameLiteral.stringValue] =
|
| + _attrAnnotationsToSpec[ann.name.name] + fieldName;
|
| }
|
| });
|
| }
|
| @@ -195,6 +229,15 @@ class DirectiveMetadataCollectingVisitor {
|
| }
|
| }
|
|
|
| +class DirectiveMetadataCollectingVisitor {
|
| + List<DirectiveMetadata> metadata = <DirectiveMetadata>[];
|
| + List<String> templates = <String>[];
|
| +
|
| + call(CompilationUnit cu) {
|
| + cu.accept(new DirectiveMetadataCollectingAstVisitor(metadata, templates));
|
| + }
|
| +}
|
| +
|
| List<String> getStringValues(ListLiteral listLiteral) {
|
| List<String> res = <String>[];
|
| for (Expression element in listLiteral.elements) {
|
|
|