|  | 
|  | 1 | +library angular2.src.analysis.analyzer_plugin.src.tasks; | 
|  | 2 | + | 
|  | 3 | +import 'package:analyzer/src/generated/ast.dart' hide Directive; | 
|  | 4 | +import 'package:analyzer/src/generated/element.dart'; | 
|  | 5 | +import 'package:analyzer/src/generated/engine.dart'; | 
|  | 6 | +import 'package:analyzer/src/task/general.dart'; | 
|  | 7 | +import 'package:analyzer/task/dart.dart'; | 
|  | 8 | +import 'package:analyzer/task/model.dart'; | 
|  | 9 | +import 'package:angular2/src/core/annotations/annotations.dart'; | 
|  | 10 | +import 'package:angular2/src/render/api.dart'; | 
|  | 11 | + | 
|  | 12 | +/// The [DirectiveMetadata]s of a [LibrarySpecificUnit]. | 
|  | 13 | +final ListResultDescriptor<DirectiveMetadata> DIRECTIVES = | 
|  | 14 | + new ListResultDescriptor<DirectiveMetadata>('ANGULAR2_DIRECTIVES', null); | 
|  | 15 | + | 
|  | 16 | +/// A task that builds [DirectiveMetadata]s for directive classes. | 
|  | 17 | +class BuildUnitDirectivesTask extends SourceBasedAnalysisTask { | 
|  | 18 | + static const String UNIT_INPUT = 'UNIT_INPUT'; | 
|  | 19 | + | 
|  | 20 | + static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( | 
|  | 21 | + 'BuildUnitDirectivesTask', createTask, buildInputs, | 
|  | 22 | + <ResultDescriptor>[DIRECTIVES]); | 
|  | 23 | + | 
|  | 24 | + BuildUnitDirectivesTask(AnalysisContext context, AnalysisTarget target) | 
|  | 25 | + : super(context, target); | 
|  | 26 | + | 
|  | 27 | + @override | 
|  | 28 | + TaskDescriptor get descriptor => DESCRIPTOR; | 
|  | 29 | + | 
|  | 30 | + @override | 
|  | 31 | + void internalPerform() { | 
|  | 32 | + CompilationUnit unit = getRequiredInput(UNIT_INPUT); | 
|  | 33 | + List<DirectiveMetadata> metaList = <DirectiveMetadata>[]; | 
|  | 34 | + for (CompilationUnitMember unitMember in unit.declarations) { | 
|  | 35 | + if (unitMember is ClassDeclaration) { | 
|  | 36 | + for (Annotation annotationNode in unitMember.metadata) { | 
|  | 37 | + Directive directive = _createDirective(annotationNode); | 
|  | 38 | + if (directive != null) { | 
|  | 39 | + DirectiveMetadata meta = new DirectiveMetadata( | 
|  | 40 | + type: _getDirectiveType(directive), | 
|  | 41 | + selector: directive.selector); | 
|  | 42 | + metaList.add(meta); | 
|  | 43 | + } | 
|  | 44 | + } | 
|  | 45 | + } | 
|  | 46 | + } | 
|  | 47 | + outputs[DIRECTIVES] = metaList; | 
|  | 48 | + } | 
|  | 49 | + | 
|  | 50 | + /// Returns an Angular [Directive] that corresponds to the given [node]. | 
|  | 51 | + /// Returns `null` if not an Angular annotation. | 
|  | 52 | + Directive _createDirective(Annotation node) { | 
|  | 53 | + // TODO(scheglov) add support for all arguments | 
|  | 54 | + if (_isAngularAnnotation(node, 'Component')) { | 
|  | 55 | + String selector = _getNamedArgument(node, 'selector'); | 
|  | 56 | + return new Component(selector: selector); | 
|  | 57 | + } | 
|  | 58 | + if (_isAngularAnnotation(node, 'Directive')) { | 
|  | 59 | + String selector = _getNamedArgument(node, 'selector'); | 
|  | 60 | + return new Directive(selector: selector); | 
|  | 61 | + } | 
|  | 62 | + return null; | 
|  | 63 | + } | 
|  | 64 | + | 
|  | 65 | + int _getDirectiveType(Directive directive) { | 
|  | 66 | + if (directive is Component) { | 
|  | 67 | + return DirectiveMetadata.COMPONENT_TYPE; | 
|  | 68 | + } | 
|  | 69 | + return DirectiveMetadata.DIRECTIVE_TYPE; | 
|  | 70 | + } | 
|  | 71 | + | 
|  | 72 | + /// Returns the value of an argument with the given [name]. | 
|  | 73 | + /// Returns `null` if not found or cannot be evaluated statically. | 
|  | 74 | + Object _getNamedArgument(Annotation node, String name) { | 
|  | 75 | + if (node.arguments != null) { | 
|  | 76 | + List<Expression> arguments = node.arguments.arguments; | 
|  | 77 | + for (Expression argument in arguments) { | 
|  | 78 | + if (argument is NamedExpression && | 
|  | 79 | + argument.name != null && | 
|  | 80 | + argument.name.label != null && | 
|  | 81 | + argument.name.label.name == name) { | 
|  | 82 | + Expression expression = argument.expression; | 
|  | 83 | + if (expression is SimpleStringLiteral) { | 
|  | 84 | + return expression.value; | 
|  | 85 | + } | 
|  | 86 | + } | 
|  | 87 | + } | 
|  | 88 | + } | 
|  | 89 | + return null; | 
|  | 90 | + } | 
|  | 91 | + | 
|  | 92 | + /// Returns `true` is the given [node] is resolved to a creation of an Angular | 
|  | 93 | + /// annotation class with the given [name]. | 
|  | 94 | + bool _isAngularAnnotation(Annotation node, String name) { | 
|  | 95 | + if (node.element is ConstructorElement) { | 
|  | 96 | + ClassElement clazz = node.element.enclosingElement; | 
|  | 97 | + return clazz.library.name == | 
|  | 98 | + 'angular2.src.core.annotations.annotations' && | 
|  | 99 | + clazz.name == name; | 
|  | 100 | + } | 
|  | 101 | + return null; | 
|  | 102 | + } | 
|  | 103 | + | 
|  | 104 | + static Map<String, TaskInput> buildInputs(LibrarySpecificUnit target) { | 
|  | 105 | + return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT.of(target)}; | 
|  | 106 | + } | 
|  | 107 | + | 
|  | 108 | + static BuildUnitDirectivesTask createTask( | 
|  | 109 | + AnalysisContext context, LibrarySpecificUnit target) { | 
|  | 110 | + return new BuildUnitDirectivesTask(context, target); | 
|  | 111 | + } | 
|  | 112 | +} | 
0 commit comments