Skip to content

Commit 20dc210

Browse files
alorenzenferhatb
authored andcommitted
SourceGen: Find InjectorModules.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=138543270
1 parent 9749fe8 commit 20dc210

19 files changed

+1222
-41
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import 'package:analyzer/dart/constant/value.dart';
2+
import 'package:analyzer/dart/element/element.dart';
3+
import 'package:analyzer/dart/element/visitor.dart';
4+
import 'package:angular2/src/compiler/compile_metadata.dart';
5+
import 'package:angular2/src/core/di/decorators.dart';
6+
import 'package:angular2/src/core/metadata.dart';
7+
import 'package:angular2/src/source_gen/common/annotation_matcher.dart'
8+
as annotation_matcher;
9+
import 'package:angular2/src/source_gen/common/url_resolver.dart';
10+
import 'package:angular2/src/source_gen/template_compiler/dart_object_utils.dart';
11+
import 'package:build/build.dart';
12+
13+
List<CompileInjectorModuleMetadata> findInjectableModules(
14+
BuildStep buildStep, Element element) {
15+
var visitor = new CompileInjectorModuleMetadataVisitor(buildStep);
16+
element.accept(visitor);
17+
return visitor.modules;
18+
}
19+
20+
class CompileInjectorModuleMetadataVisitor
21+
extends RecursiveElementVisitor<Null> {
22+
final List<CompileInjectorModuleMetadata> _modules = [];
23+
final BuildStep _buildStep;
24+
25+
CompileInjectorModuleMetadataVisitor(this._buildStep);
26+
27+
List<CompileInjectorModuleMetadata> get modules =>
28+
_modules.where((module) => module != null).toList();
29+
30+
@override
31+
Null visitClassElement(ClassElement element) {
32+
if (element.metadata.any((annotation) =>
33+
annotation_matcher.matchAnnotation(InjectorModule, annotation))) {
34+
var typeVisitor = new CompileTypeMetadataVisitor(_buildStep);
35+
CompileTypeMetadata type = element.accept(typeVisitor);
36+
_modules.add(new CompileInjectorModuleMetadata(
37+
name: type.name,
38+
moduleUrl: type.moduleUrl,
39+
diDeps: type.diDeps,
40+
injectable: element.metadata.any(_isInjectable),
41+
// TODO(alorenzen): Find providers.
42+
providers: []));
43+
}
44+
return null;
45+
}
46+
}
47+
48+
class CompileTypeMetadataVisitor
49+
extends SimpleElementVisitor<CompileTypeMetadata> {
50+
final BuildStep _buildStep;
51+
52+
CompileTypeMetadataVisitor(this._buildStep);
53+
54+
@override
55+
CompileTypeMetadata visitClassElement(ClassElement element) =>
56+
element.metadata.any(_isInjectable)
57+
? new CompileTypeMetadata(
58+
moduleUrl: toAssetUri(_buildStep.input.id),
59+
name: element.name,
60+
diDeps: _getCompileDiDependencyMetadata(
61+
element.unnamedConstructor?.parameters ?? []),
62+
runtime: null // Intentionally `null`, cannot be provided here.
63+
)
64+
: null;
65+
66+
List<CompileDiDependencyMetadata> _getCompileDiDependencyMetadata(
67+
List<ParameterElement> parameters) =>
68+
parameters.map(_createCompileDiDependencyMetadata).toList();
69+
70+
CompileDiDependencyMetadata _createCompileDiDependencyMetadata(
71+
ParameterElement p) =>
72+
new CompileDiDependencyMetadata(
73+
token: _getToken(p),
74+
isAttribute: _hasAnnotation(p, Attribute),
75+
isSelf: _hasAnnotation(p, Self),
76+
isHost: _hasAnnotation(p, Host),
77+
isSkipSelf: _hasAnnotation(p, SkipSelf),
78+
isOptional: _hasAnnotation(p, Optional),
79+
query: _getQuery(p),
80+
viewQuery: _getViewQuery(p));
81+
82+
CompileTokenMetadata _getToken(ParameterElement p) =>
83+
_hasAnnotation(p, Attribute)
84+
? _tokenForAttribute(p)
85+
: _hasAnnotation(p, Inject) ? _tokenForInject(p) : _tokenForType(p);
86+
87+
CompileTokenMetadata _tokenForAttribute(ParameterElement p) =>
88+
new CompileTokenMetadata(
89+
value: coerceString(
90+
_getAnnotation(p, Attribute).constantValue, 'attributeName'));
91+
92+
CompileTokenMetadata _tokenForInject(ParameterElement p) {
93+
throw new ArgumentError("@Inject is not yet supported.");
94+
}
95+
96+
CompileTokenMetadata _tokenForType(ParameterElement p) =>
97+
new CompileTokenMetadata(
98+
identifier: new CompileIdentifierMetadata(name: p.type.name));
99+
100+
CompileQueryMetadata _getQuery(ParameterElement p) => _hasAnnotation(p, Query)
101+
? _createQueryMetadata(_getAnnotation(p, Query))
102+
: _hasAnnotation(p, ContentChildren)
103+
? _createQueryMetadata(_getAnnotation(p, ContentChildren))
104+
: null;
105+
106+
CompileQueryMetadata _getViewQuery(ParameterElement p) =>
107+
_hasAnnotation(p, ViewQuery)
108+
? _createQueryMetadata(_getAnnotation(p, ViewQuery))
109+
: _hasAnnotation(p, ViewChildren)
110+
? _createQueryMetadata(_getAnnotation(p, ViewChildren))
111+
: null;
112+
113+
CompileQueryMetadata _createQueryMetadata(ElementAnnotation annotation) {
114+
return new CompileQueryMetadata(
115+
selectors: _getSelector(getField(annotation.constantValue, 'selector')),
116+
descendants: coerceBool(annotation.constantValue, 'descendants'),
117+
first: false,
118+
read: null,
119+
propertyName: null);
120+
}
121+
122+
List<CompileTokenMetadata> _getSelector(DartObject obj) {
123+
if (obj.toStringValue() != null) {
124+
return obj
125+
.toStringValue()
126+
.split(',')
127+
.map((value) => new CompileTokenMetadata(value: value))
128+
.toList();
129+
}
130+
throw new ArgumentError("Types not yet supported.");
131+
}
132+
133+
ElementAnnotation _getAnnotation(Element element, Type type) =>
134+
element.metadata.firstWhere(
135+
(annotation) => annotation_matcher.matchAnnotation(type, annotation));
136+
137+
bool _hasAnnotation(Element element, Type type) => element.metadata.any(
138+
(annotation) => annotation_matcher.matchAnnotation(type, annotation));
139+
}
140+
141+
bool _isInjectable(ElementAnnotation element) => const [
142+
Component,
143+
Directive,
144+
Pipe,
145+
Injectable,
146+
InjectorModule
147+
].any((type) => annotation_matcher.matchAnnotation(type, element));

lib/src/source_gen/template_compiler/generator.dart

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:build/build.dart';
1111
import 'package:source_gen/source_gen.dart';
1212

1313
import 'find_components.dart';
14+
import 'find_injectable_modules.dart';
1415

1516
/// Generates `.template.dart` files to initialize the Angular2 system.
1617
///
@@ -41,20 +42,24 @@ Future<Outputs> processTemplates(Element element, BuildStep buildStep,
4142
reflectPropertiesAsAttributes, false),
4243
);
4344

44-
final compileComponentsData = findComponents(buildStep, element);
45+
final compileComponentsData = logElapsedSync(
46+
() => findComponents(buildStep, element),
47+
operationName: 'findComponents',
48+
assetId: buildStep.input.id,
49+
log: buildStep.logger);
4550
if (compileComponentsData.isEmpty) return new Outputs._(null);
4651
await Future.forEach(compileComponentsData, (component) async {
4752
component.component =
4853
await templateCompiler.normalizeDirectiveMetadata(component.component);
4954
});
50-
51-
final injectorDefinitions = <CompileInjectorModuleMetadata>[];
52-
final compiledTemplates = logElapsedSync(
53-
() =>
54-
templateCompiler.compile(compileComponentsData, injectorDefinitions),
55-
operationName: 'compile',
55+
List<CompileInjectorModuleMetadata> injectorDefinitions = logElapsedSync(
56+
() => findInjectableModules(buildStep, element),
57+
operationName: 'findInjectableModules',
5658
assetId: buildStep.input.id,
5759
log: buildStep.logger);
60+
final compiledTemplates = logElapsedSync(() {
61+
return templateCompiler.compile(compileComponentsData, injectorDefinitions);
62+
}, operationName: 'compile', assetId: buildStep.input.id);
5863
return new Outputs._(compiledTemplates);
5964
}
6065

lib/src/source_gen/template_compiler/testing/component_extractor_generator.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class TestComponentExtractor extends Generator {
1414
if (element is! LibraryElement) return null;
1515
var components = findComponents(buildStep, element);
1616
if (components.isEmpty) return null;
17-
var output = _encoder.convert(components.map((c) => c.toJson()).toList());
17+
var output = _encoder.convert(components);
1818
return 'final String output = """$output""";';
1919
}
2020
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import 'dart:async';
2+
import 'dart:convert';
3+
4+
import 'package:analyzer/dart/element/element.dart';
5+
import 'package:angular2/src/source_gen/template_compiler/find_injectable_modules.dart';
6+
import 'package:build/build.dart';
7+
import 'package:source_gen/source_gen.dart';
8+
9+
class TestInjectableExtractor extends Generator {
10+
final JsonEncoder _encoder = const JsonEncoder.withIndent(' ');
11+
12+
@override
13+
Future<String> generate(Element element, BuildStep buildStep) async {
14+
if (element is! LibraryElement) return null;
15+
var modules = findInjectableModules(buildStep, element);
16+
if (modules.isEmpty) return null;
17+
var output = _encoder.convert(modules);
18+
return 'final String output = """$output""";';
19+
}
20+
}

lib/src/transform/common/type_metadata_reader.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,7 @@ dynamic _readValue(dynamic el) {
14981498
}
14991499
}
15001500

1501-
dynamic _readToken(dynamic el) {
1501+
CompileTokenMetadata _readToken(dynamic el) {
15021502
if (el is DoubleLiteral ||
15031503
el is IntegerLiteral ||
15041504
el is SimpleStringLiteral ||
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
library compare_to_golden;
2+
3+
import 'dart:async';
4+
import 'dart:io';
5+
import 'dart:mirrors';
6+
import 'package:path/path.dart' as p;
7+
import 'package:test/test.dart';
8+
9+
Future compareSummaryFileToGolden(String dartFileName,
10+
{String summaryExtension, String goldenExtension}) async {
11+
var input = getFile(dartFileName, summaryExtension);
12+
var golden = getFile(dartFileName, goldenExtension);
13+
14+
expect(await input.readAsString(), await golden.readAsString());
15+
}
16+
17+
File getFile(String dartFileName, String extension) =>
18+
_getFile('${p.withoutExtension(dartFileName)}${extension}');
19+
20+
File _getFile(String filename) {
21+
Uri fileUri = new Uri.file(p.join(_testFilesDir, filename));
22+
return new File.fromUri(fileUri);
23+
}
24+
25+
final String _testFilesDir = p.join(_scriptDir(), 'test_files');
26+
27+
String _scriptDir() =>
28+
p.dirname(currentMirrorSystem().findLibrary(#compare_to_golden).uri.path);
Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
@TestOn('vm')
2-
library template_compiler_test;
3-
42
import 'dart:async';
5-
import 'dart:io';
6-
import 'dart:mirrors';
7-
8-
import 'package:path/path.dart' as p;
93
import 'package:test/test.dart';
4+
import 'compare_to_golden.dart' as golden;
105

11-
const String summaryExtension = '.ng_summary';
12-
const String goldenExtension = '.golden';
6+
const String summaryExtension = '.ng_component';
7+
const String goldenExtension = '.ng_component.golden';
138

149
main() {
1510
group('Test Components', () {
@@ -43,22 +38,6 @@ main() {
4338
});
4439
}
4540

46-
Future compareSummaryFileToGolden(String dartFileName) async {
47-
var input = getFile(dartFileName, summaryExtension);
48-
var golden = getFile(dartFileName, goldenExtension);
49-
50-
expect(await input.readAsString(), await golden.readAsString());
51-
}
52-
53-
File getFile(String dartFileName, String extension) =>
54-
_getFile('${p.withoutExtension(dartFileName)}${extension}');
55-
56-
File _getFile(String filename) {
57-
Uri fileUri = new Uri.file(p.join(_testFilesDir, filename));
58-
return new File.fromUri(fileUri);
59-
}
60-
61-
final String _testFilesDir = p.join(_scriptDir(), 'test_files');
62-
63-
String _scriptDir() => p.dirname(
64-
currentMirrorSystem().findLibrary(#template_compiler_test).uri.path);
41+
Future compareSummaryFileToGolden(String dartFile) =>
42+
golden.compareSummaryFileToGolden(dartFile,
43+
summaryExtension: summaryExtension, goldenExtension: goldenExtension);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
@TestOn('vm')
2+
import 'dart:async';
3+
import 'package:test/test.dart';
4+
import 'compare_to_golden.dart' as golden;
5+
6+
const String summaryExtension = '.ng_injectable';
7+
const String goldenExtension = '.ng_injectable.golden';
8+
9+
main() {
10+
group('Test Injectable Modules', () {
11+
test('test_foo', () async {
12+
await compareSummaryFileToGolden(
13+
'injectable_module/injectable_module.dart');
14+
});
15+
});
16+
}
17+
18+
Future compareSummaryFileToGolden(String dartFile) =>
19+
golden.compareSummaryFileToGolden(dartFile,
20+
summaryExtension: summaryExtension, goldenExtension: goldenExtension);
Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1+
import 'package:angular2/src/source_gen/template_compiler/testing/component_extractor_generator.dart';
2+
import 'package:angular2/src/source_gen/template_compiler/testing/injectable_module_extractor_generator.dart';
13
import 'package:build/build.dart';
4+
import 'package:source_gen/source_gen.dart';
25

3-
import 'component_extractor_generator.dart';
6+
const testFiles = 'test/source_gen/template_compiler/test_files';
47

58
main() async {
6-
var phase = new PhaseGroup.singleAction(
7-
testComponentExtractor(extension: '.golden'),
8-
new InputSet('angular2', ['$testFiles/*.dart', '$testFiles/**/*.dart']));
9+
var inputs =
10+
new InputSet('angular2', ['$testFiles/*.dart', '$testFiles/**/*.dart']);
11+
var phaseGroup = new PhaseGroup()
12+
..addPhase(new Phase()
13+
..addAction(
14+
new GeneratorBuilder([new TestComponentExtractor()],
15+
generatedExtension: '.ng_component.golden', isStandalone: true),
16+
inputs)
17+
..addAction(
18+
new GeneratorBuilder([new TestInjectableExtractor()],
19+
generatedExtension: '.ng_injectable.golden', isStandalone: true),
20+
inputs));
921

10-
await build(phase);
22+
await build(phaseGroup);
1123
}

0 commit comments

Comments
 (0)