Skip to content

Commit e889ec8

Browse files
author
Tim Blasi
committed
refactor(dart/transform): Use a protobufs representation during transform
To simplify processing and testing in the future, use protobufs to represent of `.ng_deps.dart` files rather than always dealing directly in Dart code. This update does not actually use the protobuf representation, but this is a step towards moving all phases to parse and use protobufs rather than Dart code.
1 parent cb4ff74 commit e889ec8

File tree

41 files changed

+1152
-711
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1152
-711
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
library angular2.transform.common.code.annotation_code;
2+
3+
import 'package:analyzer/analyzer.dart';
4+
import 'package:analyzer/src/generated/ast.dart';
5+
import 'package:angular2/src/transform/common/annotation_matcher.dart';
6+
import 'package:angular2/src/transform/common/model/annotation_model.pb.dart';
7+
import 'package:barback/barback.dart' show AssetId;
8+
9+
import 'constify.dart' show constify;
10+
11+
/// Visitor responsible for parsing [Annotation]s into [AnnotationModel]s.
12+
class AnnotationVisitor extends SimpleAstVisitor<AnnotationModel> {
13+
/// The file we are processing.
14+
final AssetId assetId;
15+
16+
/// Responsible for testing whether [Annotation]s are those recognized by
17+
/// Angular 2, for example `@Component`.
18+
final AnnotationMatcher _annotationMatcher;
19+
20+
AnnotationVisitor(this.assetId, this._annotationMatcher);
21+
22+
@override
23+
AnnotationModel visitAnnotation(Annotation node) {
24+
var name = constify(node.name);
25+
if (node.constructorName != null) {
26+
name += '.${constify(node.constructorName)}';
27+
}
28+
var isComponent = _annotationMatcher.isComponent(node, assetId);
29+
var isDirective =
30+
isComponent || _annotationMatcher.isDirective(node, assetId);
31+
var isInjectable =
32+
isDirective || _annotationMatcher.isInjectable(node, assetId);
33+
var isView = _annotationMatcher.isView(node, assetId);
34+
var model = new AnnotationModel()
35+
..name = name
36+
..isComponent = isComponent
37+
..isDirective = isDirective
38+
..isInjectable = isInjectable
39+
..isView = isView;
40+
41+
if (node.arguments != null) {
42+
for (var arg in node.arguments.arguments) {
43+
if (arg is NamedExpression) {
44+
model.namedParameters.add(new NamedParameter()
45+
..name = constify(arg.name.label)
46+
..value = constify(arg.expression));
47+
} else {
48+
model.parameters.add(constify(arg));
49+
}
50+
}
51+
}
52+
53+
return model;
54+
}
55+
}
56+
57+
/// Defines the format in which an [AnnotationModel] is expressed as Dart code
58+
/// in a `.ng_deps.dart` file.
59+
abstract class AnnotationWriterMixin {
60+
StringBuffer get buffer;
61+
62+
void writeAnnotationModel(AnnotationModel model) {
63+
if (model.parameters != null || model.namedParameters != null) {
64+
buffer.write('const ${model.name}(');
65+
var first = true;
66+
for (var param in model.parameters) {
67+
if (!first) {
68+
buffer.write(', ');
69+
}
70+
first = false;
71+
buffer.write(param);
72+
}
73+
// TODO(kegluneq): We are currently outputting these sorted to ensure we
74+
// have repeatable output for testing purposes.
75+
// Remove this sorting once we are not testing output code directly.
76+
var namedParameters = model.namedParameters.toList();
77+
namedParameters.sort((a, b) => a.name.compareTo(b.name));
78+
for (var param in namedParameters) {
79+
if (!first) {
80+
buffer.write(', ');
81+
}
82+
first = false;
83+
buffer.write('${param.name}: ${param.value}');
84+
}
85+
buffer.write(')');
86+
} else {
87+
// This is a const instance, not a ctor invocation and does not need a
88+
// const instance creation expression.
89+
buffer.write(model.name);
90+
}
91+
}
92+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
library angular2.transform.common.code.constify;
2+
3+
import 'package:analyzer/analyzer.dart';
4+
import 'package:analyzer/src/generated/java_core.dart';
5+
6+
/// Serializes the provided [AstNode] to Dart source, replacing `new` in
7+
/// [InstanceCreationExpression]s and the `@` in [Annotation]s with `const`.
8+
String constify(AstNode node) {
9+
var writer = new PrintStringWriter();
10+
node.accept(new _ConstifyingVisitor(writer));
11+
return '$writer';
12+
}
13+
14+
class _ConstifyingVisitor extends ToSourceVisitor {
15+
final PrintWriter writer;
16+
17+
_ConstifyingVisitor(PrintWriter writer)
18+
: this.writer = writer,
19+
super(writer);
20+
21+
@override
22+
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
23+
if (node.keyword.lexeme == 'const') {
24+
return super.visitInstanceCreationExpression(node);
25+
} else if (node.keyword.lexeme == 'new') {
26+
writer.print('const ');
27+
if (node.constructorName != null) {
28+
node.constructorName.accept(this);
29+
}
30+
if (node.argumentList != null) {
31+
node.argumentList.accept(this);
32+
}
33+
}
34+
return null;
35+
}
36+
37+
@override
38+
Object visitAnnotation(Annotation node) {
39+
var hasArguments =
40+
node.arguments != null && node.arguments.arguments != null;
41+
if (hasArguments) {
42+
writer.print('const ');
43+
}
44+
if (node.name != null) {
45+
node.name.accept(this);
46+
}
47+
if (node.constructorName != null) {
48+
writer.print('.');
49+
node.constructorName.accept(this);
50+
}
51+
if (hasArguments) {
52+
var args = node.arguments.arguments;
53+
writer.print('(');
54+
for (var i = 0, iLen = args.length; i < iLen; ++i) {
55+
if (i != 0) {
56+
writer.print(', ');
57+
}
58+
args[i].accept(this);
59+
}
60+
writer.print(')');
61+
}
62+
return null;
63+
}
64+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
library angular2.transform.common.code.import_export_code;
2+
3+
import 'package:analyzer/analyzer.dart';
4+
import 'package:angular2/src/transform/common/model/import_export_model.pb.dart';
5+
6+
/// Visitor responsible for parsing [ImportDirective]s into [ImportModel]s.
7+
class ImportVisitor extends SimpleAstVisitor<ImportModel> {
8+
@override
9+
ImportModel visitImportDirective(ImportDirective node) {
10+
if (node.isSynthetic) return null;
11+
12+
var model = new ImportModel()
13+
..uri = stringLiteralToString(node.uri)
14+
..isDeferred = node.deferredKeyword != null;
15+
if (node.prefix != null) {
16+
model.prefix = node.prefix.name;
17+
}
18+
_populateCombinators(node, model);
19+
return model;
20+
}
21+
}
22+
23+
/// Visitor responsible for parsing [ExportDirective]s into [ExportModel]s.
24+
class ExportVisitor extends SimpleAstVisitor<ExportModel> {
25+
@override
26+
ExportModel visitExportDirective(ExportDirective node) {
27+
if (node.isSynthetic) return null;
28+
29+
var model = new ExportModel()..uri = stringLiteralToString(node.uri);
30+
_populateCombinators(node, model);
31+
return model;
32+
}
33+
}
34+
35+
/// Parses `combinators` in `node` and adds them to `model`, which should be
36+
/// either an [ImportModel] or an [ExportModel].
37+
void _populateCombinators(NamespaceDirective node, dynamic model) {
38+
if (node.combinators != null) {
39+
node.combinators.forEach((c) {
40+
if (c is ShowCombinator) {
41+
model.showCombinators.addAll(c.shownNames.map((id) => '$id'));
42+
} else if (c is HideCombinator) {
43+
model.hideCombinators.addAll(c.hiddenNames.map((id) => '$id'));
44+
}
45+
});
46+
}
47+
}
48+
49+
/// Defines the format in which an [ImportModel] is expressed as Dart code in a
50+
/// `.ng_deps.dart` file.
51+
abstract class ImportWriterMixin {
52+
StringBuffer get buffer;
53+
54+
void writeImportModel(ImportModel model) {
55+
buffer.write("import '${model.uri}'");
56+
if (model.isDeferred) {
57+
buffer.write(' deferred');
58+
}
59+
if (model.prefix != null && model.prefix.isNotEmpty) {
60+
buffer.write(' as ${model.prefix}');
61+
}
62+
_writeCombinators(buffer, model);
63+
buffer.writeln(';');
64+
}
65+
}
66+
67+
/// Defines the format in which an [ExportModel] is expressed as Dart code in a
68+
/// `.ng_deps.dart` file.
69+
abstract class ExportWriterMixin {
70+
StringBuffer get buffer;
71+
72+
void writeExportModel(ExportModel model) {
73+
buffer.write("export '${model.uri}'");
74+
_writeCombinators(buffer, model);
75+
buffer.writeln(';');
76+
}
77+
}
78+
79+
void _writeCombinators(StringBuffer buffer, dynamic model) {
80+
if (model.showCombinators != null && model.showCombinators.isNotEmpty) {
81+
buffer.write(' show ');
82+
for (var i = 0; i < model.showCombinators.length; ++i) {
83+
if (i != 0) {
84+
buffer.write(', ');
85+
}
86+
buffer.write(model.showCombinators[i]);
87+
}
88+
}
89+
if (model.hideCombinators != null && model.hideCombinators.isNotEmpty) {
90+
buffer.write(' hide ');
91+
for (var i = 0; i < model.hideCombinators.length; ++i) {
92+
if (i != 0) {
93+
buffer.write(', ');
94+
}
95+
buffer.write(model.hideCombinators[i]);
96+
}
97+
}
98+
}

0 commit comments

Comments
 (0)