Skip to content

Commit 0b1bb17

Browse files
committed
feat(dart/analysis): Build DirectiveMetadata for LibrarySpecificUnit
initial commit for the dart analyzer task
1 parent 0856516 commit 0b1bb17

File tree

6 files changed

+647
-3
lines changed

6 files changed

+647
-3
lines changed

modules_dart/analysis_plugin/lib/plugin.dart renamed to modules_dart/analyzer_plugin/lib/plugin.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
library angular2.src.analysis.analyzer_plugin;
22

33
import 'package:analyzer/plugin/plugin.dart';
4+
import 'package:analyzer/plugin/task.dart';
5+
import 'src/tasks.dart';
46

57
/// Contribute a plugin to the dart analyzer for analysis of
68
/// Angular 2 dart code.
79
class AngularAnalyzerPlugin implements Plugin {
810

9-
/// the unique indetifier for this plugin
11+
/// The unique identifier for this plugin.
1012
static const String UNIQUE_IDENTIFIER = 'angular2.analysis';
1113

1214
@override
@@ -17,6 +19,7 @@ class AngularAnalyzerPlugin implements Plugin {
1719

1820
@override
1921
void registerExtensions(RegisterExtension registerExtension) {
20-
// TODO(keerti): register extension for analysis
22+
String taskId = TASK_EXTENSION_POINT_ID;
23+
registerExtension(taskId, BuildUnitDirectivesTask.DESCRIPTOR);
2124
}
2225
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
library angular2.src.analysis.analyzer_plugin.tasks;
2+
3+
import 'package:analyzer/src/generated/error.dart';
4+
import 'package:analyzer/task/model.dart';
5+
6+
/// The analysis errors associated with a target.
7+
/// The value combines errors represented by multiple other results.
8+
final CompositeResultDescriptor<List<AnalysisError>> HTML_ERRORS =
9+
new CompositeResultDescriptor<List<AnalysisError>>('ANGULAR_HTML_ERRORS');
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
name: angular2_analysis_plugin
1+
name: angular2_analyzer_plugin
22
version: 0.0.0
33
description: Dart analyzer plugin for Angular 2
44
environment:
55
sdk: '>=1.9.0-dev.8.0'
66
dependencies:
77
angular2: '0.0.0'
88
analyzer: '^0.24.4'
9+
dev_dependencies:
10+
unittest: any
11+
typed_mock: any
12+
test_reflective_loader: any
913
dependency_overrides:
1014
angular2:
1115
path: ../../dist/dart/angular2

0 commit comments

Comments
 (0)