X Tutup
Skip to content

Commit 87449ab

Browse files
Tim Blasivsavkin
authored andcommitted
feature(dart/transform): Inject initReflector at @AngularEntrypoint
Detect the `@AngularEntrypoint` annotations on methods and/or functions and add a call to `initReflector` there. See angular#4865
1 parent 6b2ef25 commit 87449ab

File tree

14 files changed

+316
-33
lines changed

14 files changed

+316
-33
lines changed

modules_dart/payload/hello_world/web/index.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
library hello_world.index;
22

3-
import "package:angular2/bootstrap.dart" show bootstrap;
3+
import "package:angular2/bootstrap.dart" show AngularEntrypoint, bootstrap;
44
import "package:angular2/angular2.dart"
55
show Component, Directive, ElementRef, Injectable, Renderer;
66

7+
@AngularEntrypoint("Hello World Entrypoint")
78
main() {
89
bootstrap(HelloCmp);
910
}

modules_dart/transform/lib/src/transform/common/annotation_matcher.dart

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const _INJECTABLES = const [
2222

2323
const _DIRECTIVES = const [
2424
const ClassDescriptor(
25-
'Directive', 'package:angular2/src/core/metadatada/directive.dart',
25+
'Directive', 'package:angular2/src/core/metadata/directive.dart',
2626
superClass: 'Injectable'),
2727
const ClassDescriptor('Directive', 'package:angular2/src/core/metadata.dart',
2828
superClass: 'Injectable'),
@@ -57,6 +57,19 @@ const _VIEWS = const [
5757
const ClassDescriptor('View', 'package:angular2/src/core/metadata.dart'),
5858
];
5959

60+
const _ENTRYPOINTS = const [
61+
const ClassDescriptor('AngularEntrypoint', 'package:angular2/angular2.dart'),
62+
const ClassDescriptor('AngularEntrypoint', 'package:angular2/bootstrap.dart'),
63+
const ClassDescriptor(
64+
'AngularEntrypoint', 'package:angular2/bootstrap_static.dart'),
65+
const ClassDescriptor(
66+
'AngularEntrypoint', 'package:angular2/platform/browser.dart'),
67+
const ClassDescriptor(
68+
'AngularEntrypoint', 'package:angular2/platform/browser_static.dart'),
69+
const ClassDescriptor(
70+
'AngularEntrypoint', 'package:angular2/src/core/angular_entrypoint.dart'),
71+
];
72+
6073
/// Checks if a given [Annotation] matches any of the given
6174
/// [ClassDescriptors].
6275
class AnnotationMatcher extends ClassMatcherBase {
@@ -67,7 +80,8 @@ class AnnotationMatcher extends ClassMatcherBase {
6780
..addAll(_COMPONENTS)
6881
..addAll(_DIRECTIVES)
6982
..addAll(_INJECTABLES)
70-
..addAll(_VIEWS));
83+
..addAll(_VIEWS)
84+
..addAll(_ENTRYPOINTS));
7185
}
7286

7387
bool _implementsWithWarning(Annotation annotation, AssetId assetId,
@@ -94,4 +108,8 @@ class AnnotationMatcher extends ClassMatcherBase {
94108
/// Checks if an [Annotation] node implements [View].
95109
bool isView(Annotation annotation, AssetId assetId) =>
96110
_implementsWithWarning(annotation, assetId, _VIEWS);
111+
112+
/// Checks if an [Annotation] node implements [AngularEntrypoint]
113+
bool isEntrypoint(Annotation annotation, AssetId assetId) =>
114+
_implementsWithWarning(annotation, assetId, _ENTRYPOINTS);
97115
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
library angular2.transform.reflection_remover.entrypoint_matcher;
2+
3+
import 'package:analyzer/analyzer.dart';
4+
import 'package:barback/barback.dart';
5+
6+
import 'package:angular2/src/transform/common/annotation_matcher.dart';
7+
import 'package:angular2/src/transform/common/naive_eval.dart';
8+
9+
/// Determines if a [FunctionDeclaration] or [MethodDeclaration] is an
10+
/// `AngularEntrypoint`.
11+
class EntrypointMatcher {
12+
final AssetId _assetId;
13+
final AnnotationMatcher _annotationMatcher;
14+
15+
EntrypointMatcher(this._assetId, this._annotationMatcher) {
16+
if (_assetId == null) {
17+
throw new ArgumentError.notNull('AssetId');
18+
}
19+
if (_annotationMatcher == null) {
20+
throw new ArgumentError.notNull('AnnotationMatcher');
21+
}
22+
}
23+
24+
bool isEntrypoint(AnnotatedNode node) {
25+
if (node == null ||
26+
(node is! FunctionDeclaration && node is! MethodDeclaration)) {
27+
return false;
28+
}
29+
return node.metadata
30+
.any((a) => _annotationMatcher.isEntrypoint(a, _assetId));
31+
}
32+
33+
/// Gets the name assigned to the `AngularEntrypoint`.
34+
///
35+
/// This method assumes the name is the first argument to `AngularEntrypoint`;
36+
String getName(AnnotatedNode node) {
37+
final annotation = node.metadata.firstWhere(
38+
(a) => _annotationMatcher.isEntrypoint(a, _assetId),
39+
orElse: () => null);
40+
if (annotation == null) return null;
41+
if (annotation.arguments == null ||
42+
annotation.arguments.arguments == null ||
43+
annotation.arguments.arguments.isEmpty) {
44+
return _defaultEntrypointName;
45+
}
46+
final entryPointName = naiveEval(annotation.arguments.arguments.first);
47+
if (entryPointName == NOT_A_CONSTANT) {
48+
throw new ArgumentError(
49+
'Could not evaluate "${node}" as parameter to @AngularEntrypoint');
50+
}
51+
if (entryPointName is! String) {
52+
throw new ArgumentError('Unexpected type "${entryPointName.runtimeType}" '
53+
'as first parameter to @AngularEntrypoint');
54+
}
55+
return entryPointName;
56+
}
57+
}
58+
59+
const _defaultEntrypointName = "(no name provided)";

modules_dart/transform/lib/src/transform/reflection_remover/remove_reflection_capabilities.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ library angular2.transform.reflection_remover.remove_reflection_capabilities;
22

33
import 'dart:async';
44
import 'package:analyzer/analyzer.dart';
5+
import 'package:barback/barback.dart';
6+
7+
import 'package:angular2/src/transform/common/annotation_matcher.dart';
58
import 'package:angular2/src/transform/common/asset_reader.dart';
69
import 'package:angular2/src/transform/common/mirror_mode.dart';
7-
import 'package:barback/barback.dart';
810

911
import 'codegen.dart';
12+
import 'entrypoint_matcher.dart';
1013
import 'rewriter.dart';
1114

1215
/// Finds the call to the Angular2 `ReflectionCapabilities` constructor
@@ -15,14 +18,15 @@ import 'rewriter.dart';
1518
///
1619
/// This only searches the code in `reflectionEntryPoint`, not `part`s,
1720
/// `import`s, `export`s, etc.
18-
Future<String> removeReflectionCapabilities(
19-
AssetReader reader, AssetId reflectionEntryPoint,
21+
Future<String> removeReflectionCapabilities(AssetReader reader,
22+
AssetId reflectionEntryPoint, AnnotationMatcher annotationMatcher,
2023
{MirrorMode mirrorMode: MirrorMode.none,
2124
bool writeStaticInit: true}) async {
2225
var code = await reader.readAsString(reflectionEntryPoint);
2326

2427
var codegen = new Codegen(reflectionEntryPoint);
2528
return new Rewriter(code, codegen,
29+
new EntrypointMatcher(reflectionEntryPoint, annotationMatcher),
2630
mirrorMode: mirrorMode, writeStaticInit: writeStaticInit)
2731
.rewrite(parseCompilationUnit(code, name: reflectionEntryPoint.path));
2832
}

modules_dart/transform/lib/src/transform/reflection_remover/rewriter.dart

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,43 @@
11
library angular2.transform.reflection_remover.rewriter;
22

33
import 'package:analyzer/src/generated/ast.dart';
4+
import 'package:path/path.dart' as path;
5+
46
import 'package:angular2/src/transform/common/logging.dart';
57
import 'package:angular2/src/transform/common/mirror_matcher.dart';
68
import 'package:angular2/src/transform/common/mirror_mode.dart';
79
import 'package:angular2/src/transform/common/names.dart';
8-
import 'package:path/path.dart' as path;
910

1011
import 'codegen.dart';
12+
import 'entrypoint_matcher.dart';
1113

1214
class Rewriter {
1315
final String _code;
1416
final Codegen _codegen;
17+
final EntrypointMatcher _entrypointMatcher;
1518
final MirrorMatcher _mirrorMatcher;
1619
final MirrorMode _mirrorMode;
1720
final bool _writeStaticInit;
1821

19-
Rewriter(this._code, this._codegen,
22+
Rewriter(this._code, this._codegen, this._entrypointMatcher,
2023
{MirrorMatcher mirrorMatcher,
2124
MirrorMode mirrorMode: MirrorMode.none,
2225
bool writeStaticInit: true})
2326
: _mirrorMode = mirrorMode,
2427
_writeStaticInit = writeStaticInit,
2528
_mirrorMatcher =
26-
mirrorMatcher == null ? const MirrorMatcher() : mirrorMatcher;
29+
mirrorMatcher == null ? const MirrorMatcher() : mirrorMatcher {
30+
if (_codegen == null) {
31+
throw new ArgumentError.notNull('Codegen');
32+
}
33+
if (_entrypointMatcher == null) {
34+
throw new ArgumentError.notNull('EntrypointMatcher');
35+
}
36+
}
2737

28-
/// Rewrites the provided code removing imports of the
38+
/// Rewrites the provided code to remove dart:mirrors.
39+
///
40+
/// Specifically, removes imports of the
2941
/// {@link ReflectionCapabilities} library and instantiations of
3042
/// {@link ReflectionCapabilities}, as detected by the (potentially) provided
3143
/// {@link MirrorMatcher}.
@@ -51,7 +63,7 @@ class Rewriter {
5163
class _RewriterVisitor extends Object with RecursiveAstVisitor<Object> {
5264
final Rewriter _rewriter;
5365
final buf = new StringBuffer();
54-
final reflectionCapabilityAssignments = [];
66+
final reflectionCapabilityAssignments = <AssignmentExpression>[];
5567

5668
int _currentIndex = 0;
5769
bool _setupAdded = false;
@@ -105,6 +117,45 @@ class _RewriterVisitor extends Object with RecursiveAstVisitor<Object> {
105117
return super.visitMethodInvocation(node);
106118
}
107119

120+
@override
121+
Object visitMethodDeclaration(MethodDeclaration node) {
122+
if (_rewriter._entrypointMatcher.isEntrypoint(node)) {
123+
if (_rewriter._writeStaticInit) {
124+
_rewriteEntrypointFunctionBody(node.body);
125+
}
126+
}
127+
return super.visitMethodDeclaration(node);
128+
}
129+
130+
@override
131+
Object visitFunctionDeclaration(FunctionDeclaration node) {
132+
if (_rewriter._entrypointMatcher.isEntrypoint(node)) {
133+
if (_rewriter._writeStaticInit) {
134+
_rewriteEntrypointFunctionBody(node.functionExpression.body);
135+
}
136+
}
137+
return super.visitFunctionDeclaration(node);
138+
}
139+
140+
void _rewriteEntrypointFunctionBody(FunctionBody node) {
141+
if (node is BlockFunctionBody) {
142+
final insertOffset = node.block.leftBracket.end;
143+
buf.write(_rewriter._code.substring(_currentIndex, insertOffset));
144+
buf.write(_getStaticReflectorInitBlock());
145+
_currentIndex = insertOffset;
146+
} else if (node is ExpressionFunctionBody) {
147+
// TODO(kegluneq): Add support, see issue #5474.
148+
throw new ArgumentError(
149+
'Arrow syntax is not currently supported as `@AngularEntrypoint`s');
150+
} else if (node is NativeFunctionBody) {
151+
throw new ArgumentError('Native functions and methods are not supported '
152+
'as `@AngularEntrypoint`s');
153+
} else if (node is EmptyFunctionBody) {
154+
throw new ArgumentError('Empty functions and methods are not supported '
155+
'as `@AngularEntrypoint`s');
156+
}
157+
}
158+
108159
String outputRewrittenCode() {
109160
if (_currentIndex < _rewriter._code.length) {
110161
buf.write(_rewriter._code.substring(_currentIndex));

modules_dart/transform/lib/src/transform/reflection_remover/transformer.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ class ReflectionRemover extends Transformer implements LazyTransformer {
5252
}
5353

5454
var transformedCode = await removeReflectionCapabilities(
55-
new AssetReader.fromTransform(transform), primaryId,
56-
mirrorMode: mirrorMode, writeStaticInit: writeStaticInit);
55+
new AssetReader.fromTransform(transform),
56+
primaryId,
57+
options.annotationMatcher,
58+
mirrorMode: mirrorMode,
59+
writeStaticInit: writeStaticInit);
5760
transform.addOutput(new Asset.fromString(primaryId, transformedCode));
5861
}, log: transform.logger);
5962
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
library web_foo;
2+
3+
import 'package:angular2/bootstrap.dart';
4+
5+
abstract class TestBootstrapper {
6+
@AngularEntrypoint()
7+
void testBootstrap();
8+
}

0 commit comments

Comments
 (0)
X Tutup