Skip to content

Commit 2cab7c7

Browse files
author
Tim Blasi
committed
feat(dart/transform): Allow multiple transformer entry points
- Allow the user to specify multiple entry points to an app. - Allow the Angular 2 transformer to run without explicit entry points to generate necessary setters & getters on built-in directives like `For` and `If`. Closes angular#1246
1 parent bba8499 commit 2cab7c7

12 files changed

Lines changed: 121 additions & 75 deletions

File tree

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,29 @@
11
library angular2.transform.common.options;
22

3-
const ENTRY_POINT_PARAM = 'entry_point';
4-
const REFLECTION_ENTRY_POINT_PARAM = 'reflection_entry_point';
3+
const ENTRY_POINT_PARAM = 'entry_points';
4+
const REFLECTION_ENTRY_POINT_PARAM = 'reflection_entry_points';
55

66
/// Provides information necessary to transform an Angular2 app.
77
class TransformerOptions {
8-
/// The path to the file where the application's call to [bootstrap] is.
9-
// TODO(kegluneq): Allow multiple entry points.
10-
final String entryPoint;
8+
/// The path to the files where the application's calls to `bootstrap` are.
9+
final List<String> entryPoints;
1110

12-
/// The reflection entry point, that is, the path to the file where the
13-
/// application's [ReflectionCapabilities] are set.
14-
final String reflectionEntryPoint;
11+
/// The paths to the files where the application's [ReflectionCapabilities]
12+
/// are set.
13+
final List<String> reflectionEntryPoints;
1514

1615
/// The `BarbackMode#name` we are running in.
1716
final String modeName;
1817

1918
TransformerOptions._internal(
20-
this.entryPoint, this.reflectionEntryPoint, this.modeName);
19+
this.entryPoints, this.reflectionEntryPoints, this.modeName);
2120

22-
factory TransformerOptions(String entryPoint,
23-
{String reflectionEntryPoint, String modeName: 'release'}) {
24-
if (entryPoint == null) {
25-
throw new ArgumentError.notNull(ENTRY_POINT_PARAM);
26-
} else if (entryPoint.isEmpty) {
27-
throw new ArgumentError.value(entryPoint, 'entryPoint');
28-
}
29-
if (reflectionEntryPoint == null || entryPoint.isEmpty) {
30-
reflectionEntryPoint = entryPoint;
21+
factory TransformerOptions(List<String> entryPoints,
22+
{List<String> reflectionEntryPoints, String modeName: 'release'}) {
23+
if (reflectionEntryPoints == null || reflectionEntryPoints.isEmpty) {
24+
reflectionEntryPoints = entryPoints;
3125
}
3226
return new TransformerOptions._internal(
33-
entryPoint, reflectionEntryPoint, modeName);
27+
entryPoints, reflectionEntryPoints, modeName);
3428
}
3529
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
library angular2.transform.common.options;
2+
3+
import 'package:barback/barback.dart';
4+
import 'options.dart';
5+
6+
TransformerOptions parseBarbackSettings(BarbackSettings settings) {
7+
var config = settings.configuration;
8+
var entryPoints = _readFileList(config, ENTRY_POINT_PARAM);
9+
var reflectionEntryPoints =
10+
_readFileList(config, REFLECTION_ENTRY_POINT_PARAM);
11+
return new TransformerOptions(entryPoints,
12+
reflectionEntryPoints: reflectionEntryPoints,
13+
modeName: settings.mode.name);
14+
}
15+
16+
/// Cribbed from the polymer project.
17+
/// [https://github.com/dart-lang/polymer-dart]
18+
List<String> _readFileList(Map config, String paramName) {
19+
var value = config[paramName];
20+
if (value == null) return null;
21+
var files = [];
22+
bool error = false;
23+
if (value is List) {
24+
files = value;
25+
error = value.any((e) => e is! String);
26+
} else if (value is String) {
27+
files = [value];
28+
error = false;
29+
} else {
30+
error = true;
31+
}
32+
if (error) {
33+
print('Invalid value for "$paramName" in the Angular 2 transformer.');
34+
}
35+
return files;
36+
}

modules/angular2/src/transform/di_transformer.dart

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,29 @@ import 'directive_processor/transformer.dart';
88
import 'bind_generator/transformer.dart';
99
import 'reflection_remover/transformer.dart';
1010
import 'common/formatter.dart' as formatter;
11+
import 'common/names.dart';
1112
import 'common/options.dart';
13+
import 'common/options_reader.dart';
1214

1315
export 'common/options.dart';
1416

1517
/// Removes the mirror-based initialization logic and replaces it with static
1618
/// logic.
1719
class DiTransformerGroup extends TransformerGroup {
18-
DiTransformerGroup()
19-
: super([[new DirectiveProcessor(null)], [new DirectiveLinker()]]) {
20+
DiTransformerGroup._(phases) : super(phases) {
2021
formatter.init(new DartFormatter());
2122
}
2223

24+
factory DiTransformerGroup(TransformerOptions options) {
25+
var phases = [
26+
[new ReflectionRemover(options)],
27+
[new DirectiveProcessor(null)],
28+
[new DirectiveLinker()]
29+
];
30+
return new DiTransformerGroup._(phases);
31+
}
32+
2333
factory DiTransformerGroup.asPlugin(BarbackSettings settings) {
24-
return new DiTransformerGroup();
34+
return new DiTransformerGroup(parseBarbackSettings(settings));
2535
}
2636
}

modules/angular2/src/transform/reflection_remover/codegen.dart

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ class Codegen {
1212

1313
/// The prefix used to import our generated file.
1414
final String prefix;
15-
/// The import uri
16-
final String importUri;
15+
/// The import uris
16+
final Iterable<String> importUris;
1717

18-
Codegen(String reflectionEntryPointPath, String newEntryPointPath,
18+
Codegen(String reflectionEntryPointPath, Iterable<String> newEntryPointPaths,
1919
{String prefix})
2020
: this.prefix = prefix == null ? _PREFIX_BASE : prefix,
21-
importUri = path.relative(newEntryPointPath,
22-
from: path.dirname(reflectionEntryPointPath)) {
21+
importUris = newEntryPointPaths.map((p) =>
22+
path.relative(p, from: path.dirname(reflectionEntryPointPath))) {
2323
if (this.prefix.isEmpty) throw new ArgumentError.value('(empty)', 'prefix');
2424
}
2525

@@ -43,7 +43,10 @@ class Codegen {
4343
/// The code generated here should follow the example of code generated for
4444
/// an [ImportDirective] node.
4545
String codegenImport() {
46-
return 'import \'${importUri}\' as ${prefix};';
46+
var count = 0;
47+
return importUris
48+
.map((importUri) => 'import \'${importUri}\' as ${prefix}${count++};')
49+
.join('');
4750
}
4851

4952
/// Generates code to call the method which sets up Angular2 reflection
@@ -63,7 +66,11 @@ class Codegen {
6366
reflectorExpression = 'reflector';
6467
}
6568

66-
return '${prefix}.${SETUP_METHOD_NAME}(${reflectorExpression});';
69+
var count = 0;
70+
return importUris
71+
.map((_) =>
72+
'${prefix}${count++}.${SETUP_METHOD_NAME}(${reflectorExpression});')
73+
.join('');
6774
}
6875
}
6976

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
library angular2.transform.reflection_remover.remove_reflection_capabilities;
22

3+
import 'dart:async';
34
import 'package:analyzer/analyzer.dart';
5+
import 'package:barback/barback.dart';
6+
import 'package:angular2/src/transform/common/asset_reader.dart';
47

58
import 'codegen.dart';
69
import 'rewriter.dart';
710

8-
/// Finds the call to the Angular2 [ReflectionCapabilities] constructor
9-
/// in [code] and replaces it with a call to `setupReflection` in
10-
/// [newEntryPoint].
11+
/// Finds the call to the Angular2 `ReflectionCapabilities` constructor
12+
/// in [reflectionEntryPoint] and replaces it with a call to
13+
/// `setupReflection` in [newEntryPoint].
1114
///
12-
/// [reflectionEntryPointPath] is the path where [code] is defined and is
13-
/// used to display parsing errors.
14-
///
15-
/// This only searches [code] not `part`s, `import`s, `export`s, etc.
16-
String removeReflectionCapabilities(
17-
String code, String reflectionEntryPointPath, String newEntryPointPath) {
18-
var codegen = new Codegen(reflectionEntryPointPath, newEntryPointPath);
15+
/// This only searches the code in [reflectionEntryPoint], not `part`s,
16+
/// `import`s, `export`s, etc.
17+
Future<String> removeReflectionCapabilities(AssetReader reader,
18+
AssetId reflectionEntryPoint, Iterable<AssetId> newEntryPoints) async {
19+
var code = await reader.readAsString(reflectionEntryPoint);
20+
var reflectionEntryPointPath = reflectionEntryPoint.path;
21+
var newEntryPointPaths = newEntryPoints.map((id) => id.path);
22+
23+
var codegen = new Codegen(reflectionEntryPointPath, newEntryPointPaths);
1924
return new Rewriter(code, codegen)
2025
.rewrite(parseCompilationUnit(code, name: reflectionEntryPointPath));
2126
}

modules/angular2/src/transform/reflection_remover/transformer.dart

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
library angular2.transform.reflection_remover.transformer;
22

33
import 'dart:async';
4+
import 'package:angular2/src/transform/common/asset_reader.dart';
45
import 'package:angular2/src/transform/common/logging.dart' as log;
56
import 'package:angular2/src/transform/common/names.dart';
67
import 'package:angular2/src/transform/common/options.dart';
@@ -23,21 +24,24 @@ class ReflectionRemover extends Transformer {
2324
ReflectionRemover(this.options);
2425

2526
@override
26-
bool isPrimary(AssetId id) => options.reflectionEntryPoint == id.path;
27+
bool isPrimary(AssetId id) => options.reflectionEntryPoints != null &&
28+
options.reflectionEntryPoints.contains(id.path);
2729

2830
@override
2931
Future apply(Transform transform) async {
3032
log.init(transform);
3133

3234
try {
33-
var newEntryPoint = new AssetId(
34-
transform.primaryInput.id.package, options.entryPoint)
35-
.changeExtension(DEPS_EXTENSION);
36-
37-
var assetCode = await transform.primaryInput.readAsString();
38-
transform.addOutput(new Asset.fromString(transform.primaryInput.id,
39-
removeReflectionCapabilities(
40-
assetCode, transform.primaryInput.id.path, newEntryPoint.path)));
35+
var newEntryPoints = options.entryPoints.map((entryPoint) {
36+
return new AssetId(transform.primaryInput.id.package, entryPoint)
37+
.changeExtension(DEPS_EXTENSION);
38+
});
39+
var reader = new AssetReader.fromTransform(transform);
40+
41+
var transformedCode = await removeReflectionCapabilities(
42+
reader, transform.primaryInput.id, newEntryPoints);
43+
transform.addOutput(
44+
new Asset.fromString(transform.primaryInput.id, transformedCode));
4145
} catch (ex, stackTrace) {
4246
log.logger.error('Removing reflection failed.\n'
4347
'Exception: $ex\n'

modules/angular2/src/transform/transformer.dart

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'template_compiler/transformer.dart';
1111
import 'common/formatter.dart' as formatter;
1212
import 'common/names.dart';
1313
import 'common/options.dart';
14+
import 'common/options_reader.dart';
1415

1516
export 'common/options.dart';
1617

@@ -21,25 +22,17 @@ class AngularTransformerGroup extends TransformerGroup {
2122
}
2223

2324
factory AngularTransformerGroup(TransformerOptions options) {
24-
var phases = [[new DirectiveProcessor(options)], [new DirectiveLinker()]];
25-
if (options.modeName == TRANSFORM_MODE) {
26-
phases.addAll([
27-
[new BindGenerator(options)],
28-
[new TemplateCompiler(options)],
29-
[new ReflectionRemover(options)]
30-
]);
31-
}
25+
var phases = [
26+
[new ReflectionRemover(options)],
27+
[new DirectiveProcessor(options)],
28+
[new DirectiveLinker()],
29+
[new BindGenerator(options)],
30+
[new TemplateCompiler(options)]
31+
];
3232
return new AngularTransformerGroup._(phases);
3333
}
3434

3535
factory AngularTransformerGroup.asPlugin(BarbackSettings settings) {
36-
return new AngularTransformerGroup(_parseOptions(settings));
36+
return new AngularTransformerGroup(parseBarbackSettings(settings));
3737
}
3838
}
39-
40-
TransformerOptions _parseOptions(BarbackSettings settings) {
41-
var config = settings.configuration;
42-
return new TransformerOptions(config[ENTRY_POINT_PARAM],
43-
reflectionEntryPoint: config[REFLECTION_ENTRY_POINT_PARAM],
44-
modeName: settings.mode.name);
45-
}

modules/angular2/test/transform/integration/all_tests.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import '../common/read_file.dart';
1111

1212
var formatter = new DartFormatter();
1313
var transform = new AngularTransformerGroup(new TransformerOptions(
14-
'web/index.dart',
15-
reflectionEntryPoint: 'web/index.dart', modeName: TRANSFORM_MODE));
14+
['web/index.dart'],
15+
reflectionEntryPoints: ['web/index.dart'], modeName: TRANSFORM_MODE));
1616

1717
class IntegrationTestConfig {
1818
final String name;

modules/angular2/test/transform/integration/simple_annotation_files/expected/index.ng_deps.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,15 @@ library web_foo.ng_deps.dart;
33
import 'index.dart';
44
import 'package:angular2/src/core/application.dart';
55
import 'package:angular2/src/reflection/reflection.dart';
6-
import 'package:angular2/src/reflection/reflection_capabilities.dart';
6+
import 'index.ng_deps.dart' as ngStaticInit0;
77
import 'bar.dart';
88
import 'bar.ng_deps.dart' as i0;
99
import 'package:angular2/src/core/application.ng_deps.dart' as i1;
10-
import 'package:angular2/src/reflection/reflection_capabilities.ng_deps.dart'
11-
as i2;
1210

1311
bool _visited = false;
1412
void initReflector(reflector) {
1513
if (_visited) return;
1614
_visited = true;
1715
i0.initReflector(reflector);
1816
i1.initReflector(reflector);
19-
i2.initReflector(reflector);
2017
}

modules/angular2/test/transform/reflection_remover/all_tests.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'reflection_remover_files/expected/index.dart' as expected;
99
import '../common/read_file.dart';
1010

1111
void allTests() {
12-
var codegen = new Codegen('web/index.dart', 'web/index.ng_deps.dart');
12+
var codegen = new Codegen('web/index.dart', ['web/index.ng_deps.dart']);
1313

1414
it('should remove uses of mirrors & insert calls to generated code.', () {
1515
var code =

0 commit comments

Comments
 (0)