Skip to content

Commit 4909fed

Browse files
committed
feat(core): add support for ambient directives to dart transformers
Closes #5129
1 parent adc0e32 commit 4909fed

7 files changed

Lines changed: 136 additions & 17 deletions

File tree

modules/playground/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ dependency_overrides:
1717
path: ../angular2_material
1818
transformers:
1919
- angular2:
20-
ambient_directives: 'angular2/lib/src/core/directives.dart:CORE_DIRECTIVES'
20+
ambient_directives: 'package:angular2/src/core/directives.dart#CORE_DIRECTIVES'
2121
entry_points:
2222
- web/src/gestures/index.dart
2323
- web/src/hello_world/index.dart

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const FORMAT_CODE_PARAM = 'format_code';
1111
const REFLECT_PROPERTIES_AS_ATTRIBUTES = 'reflect_properties_as_attributes';
1212
// TODO(kegluenq): Remove this after 30 Nov (i/5108).
1313
const REFLECT_PROPERTIES_AS_ATTRIBUTES_OLD = 'reflectPropertiesAsAttributes';
14+
const AMBIENT_DIRECTIVES = 'ambient_directives';
1415
const INIT_REFLECTOR_PARAM = 'init_reflector';
1516
const INLINE_VIEWS_PARAM = 'inline_views';
1617
const MIRROR_MODE_PARAM = 'mirror_mode';
@@ -39,6 +40,10 @@ class TransformerOptions {
3940
/// as attributes on DOM elements, which may aid in application debugging.
4041
final bool reflectPropertiesAsAttributes;
4142

43+
/// A set of directives that will be automatically passed-in to the template compiler
44+
/// Format of an item in the list: angular2/lib/src/core/directives.dart#CORE_DIRECTIVES
45+
final List<String> ambientDirectives;
46+
4247
/// Whether to format generated code.
4348
/// Code that is only modified will never be formatted because doing so may
4449
/// invalidate the source maps generated by `dart2js` and/or other tools.
@@ -59,6 +64,7 @@ class TransformerOptions {
5964
this.initReflector,
6065
this.annotationMatcher,
6166
{this.reflectPropertiesAsAttributes,
67+
this.ambientDirectives,
6268
this.inlineViews,
6369
this.formatCode});
6470

@@ -69,6 +75,7 @@ class TransformerOptions {
6975
List<ClassDescriptor> customAnnotationDescriptors: const [],
7076
bool inlineViews: false,
7177
bool reflectPropertiesAsAttributes: true,
78+
List<String> ambientDirectives,
7279
bool formatCode: false}) {
7380
var annotationMatcher = new AnnotationMatcher()
7481
..addAll(customAnnotationDescriptors);
@@ -78,6 +85,7 @@ class TransformerOptions {
7885
return new TransformerOptions._internal(entryPoints, entryPointGlobs,
7986
modeName, mirrorMode, initReflector, annotationMatcher,
8087
reflectPropertiesAsAttributes: reflectPropertiesAsAttributes,
88+
ambientDirectives: ambientDirectives,
8189
inlineViews: inlineViews,
8290
formatCode: formatCode);
8391
}

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'options.dart';
88
TransformerOptions parseBarbackSettings(BarbackSettings settings) {
99
var config = settings.configuration;
1010
_warnDeprecated(config);
11-
var entryPoints = _readFileList(config, ENTRY_POINT_PARAM);
11+
var entryPoints = _readStringList(config, ENTRY_POINT_PARAM);
1212
var initReflector =
1313
_readBool(config, INIT_REFLECTOR_PARAM, defaultValue: true);
1414
var reflectPropertiesAsAttributes =
@@ -18,6 +18,7 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) {
1818
config, REFLECT_PROPERTIES_AS_ATTRIBUTES_OLD,
1919
defaultValue: false);
2020
}
21+
var ambientDirectives = _readStringList(config, AMBIENT_DIRECTIVES);
2122
var formatCode = _readBool(config, FORMAT_CODE_PARAM, defaultValue: false);
2223
String mirrorModeVal =
2324
config.containsKey(MIRROR_MODE_PARAM) ? config[MIRROR_MODE_PARAM] : '';
@@ -39,6 +40,7 @@ TransformerOptions parseBarbackSettings(BarbackSettings settings) {
3940
initReflector: initReflector,
4041
customAnnotationDescriptors: _readCustomAnnotations(config),
4142
reflectPropertiesAsAttributes: reflectPropertiesAsAttributes,
43+
ambientDirectives: ambientDirectives,
4244
inlineViews: _readBool(config, INLINE_VIEWS_PARAM, defaultValue: false),
4345
formatCode: formatCode);
4446
}
@@ -51,24 +53,24 @@ bool _readBool(Map config, String paramName, {bool defaultValue}) {
5153

5254
/// Cribbed from the polymer project.
5355
/// {@link https://github.com/dart-lang/polymer-dart}
54-
List<String> _readFileList(Map config, String paramName) {
56+
List<String> _readStringList(Map config, String paramName) {
5557
var value = config[paramName];
5658
if (value == null) return null;
57-
var files = [];
59+
var result = [];
5860
bool error = false;
5961
if (value is List) {
60-
files = value;
62+
result = value;
6163
error = value.any((e) => e is! String);
6264
} else if (value is String) {
63-
files = [value];
65+
result = [value];
6466
error = false;
6567
} else {
6668
error = true;
6769
}
6870
if (error) {
6971
print('Invalid value for "$paramName" in the Angular 2 transformer.');
7072
}
71-
return files;
73+
return result;
7274
}
7375

7476
/// Parse the [CUSTOM_ANNOTATIONS_PARAM] options out of the transformer into

modules_dart/transform/lib/src/transform/template_compiler/compile_data_creator.dart

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import 'package:barback/barback.dart';
2020
/// The returned value wraps the [NgDepsModel] at `assetId` as well as these
2121
/// created objects.
2222
Future<CompileDataResults> createCompileData(
23-
AssetReader reader, AssetId assetId) async {
23+
AssetReader reader, AssetId assetId, List<String> ambientDirectives) async {
2424
return logElapsedAsync(() async {
25-
final creator = await _CompileDataCreator.create(reader, assetId);
25+
final creator = await _CompileDataCreator.create(reader, assetId, ambientDirectives);
2626
return creator != null ? creator.createCompileData() : null;
2727
}, operationName: 'createCompileData', assetId: assetId);
2828
}
@@ -41,17 +41,18 @@ class _CompileDataCreator {
4141
final AssetReader reader;
4242
final AssetId entryPoint;
4343
final NgMeta ngMeta;
44+
final List<String> ambientDirectives;
4445

45-
_CompileDataCreator(this.reader, this.entryPoint, this.ngMeta);
46+
_CompileDataCreator(this.reader, this.entryPoint, this.ngMeta, this.ambientDirectives);
4647

4748
static Future<_CompileDataCreator> create(
48-
AssetReader reader, AssetId assetId) async {
49+
AssetReader reader, AssetId assetId, List<String> ambientDirectives) async {
4950
if (!(await reader.hasInput(assetId))) return null;
5051
final json = await reader.readAsString(assetId);
5152
if (json == null || json.isEmpty) return null;
5253

5354
final ngMeta = new NgMeta.fromJson(JSON.decode(json));
54-
return new _CompileDataCreator(reader, assetId, ngMeta);
55+
return new _CompileDataCreator(reader, assetId, ngMeta, ambientDirectives);
5556
}
5657

5758
NgDepsModel get ngDeps => ngMeta.ngDeps;
@@ -64,13 +65,16 @@ class _CompileDataCreator {
6465
final compileData =
6566
<ReflectionInfoModel, NormalizedComponentWithViewDirectives>{};
6667
final ngMetaMap = await _extractNgMeta();
68+
final ambientDirectives = await _readAmbientDirectives();
6769

6870
for (var reflectable in ngDeps.reflectables) {
6971
if (ngMeta.types.containsKey(reflectable.name)) {
7072
final compileDirectiveMetadata = ngMeta.types[reflectable.name];
7173
if (compileDirectiveMetadata.template != null) {
7274
final compileDatum = new NormalizedComponentWithViewDirectives(
7375
compileDirectiveMetadata, <CompileDirectiveMetadata>[]);
76+
compileDatum.directives.addAll(ambientDirectives);
77+
7478
for (var dep in reflectable.directives) {
7579
if (!ngMetaMap.containsKey(dep.prefix)) {
7680
logger.warning(
@@ -99,6 +103,50 @@ class _CompileDataCreator {
99103
return new CompileDataResults._(ngMeta, compileData);
100104
}
101105

106+
Future<List<CompileDirectiveMetadata>> _readAmbientDirectives() async {
107+
if (ambientDirectives == null) return const [];
108+
109+
final res = [];
110+
for (var ad in ambientDirectives) {
111+
final parts = ad.split("#");
112+
if (parts.length != 2) {
113+
logger.warning('The ambient directives configuration option '
114+
'must be in the following format: "URI#TOKEN"');
115+
return const [];
116+
}
117+
res.addAll(await _readAmbientDirectivesFromUri(parts[0], parts[1]));
118+
}
119+
return res;
120+
}
121+
122+
Future<List<CompileDirectiveMetadata>> _readAmbientDirectivesFromUri(String uri, String token) async {
123+
final metaAssetId = fromUri(toMetaExtension(uri));
124+
if (await reader.hasInput(metaAssetId)) {
125+
try {
126+
var jsonString = await reader.readAsString(metaAssetId);
127+
if (jsonString != null && jsonString.isNotEmpty) {
128+
var newMetadata = new NgMeta.fromJson(JSON.decode(jsonString));
129+
130+
if (newMetadata.types.containsKey(token)) {
131+
return [newMetadata.types[token]];
132+
133+
} else if (newMetadata.aliases.containsKey(token)) {
134+
return newMetadata.flatten(token);
135+
136+
} else {
137+
logger.warning('Could not resolve ambient directive ${token} in ${uri}',
138+
asset: metaAssetId);
139+
}
140+
141+
}
142+
} catch (ex, stackTrace) {
143+
logger.warning('Failed to decode: $ex, $stackTrace',
144+
asset: metaAssetId);
145+
}
146+
}
147+
return [];
148+
}
149+
102150
/// Creates a map from import prefix to the asset: uris of all `.dart`
103151
/// libraries visible from `entryPoint`, excluding `dart:` and `.ng_deps.dart`
104152
/// files it imports. Unprefixed imports have the empty string as their key.

modules_dart/transform/lib/src/transform/template_compiler/generator.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ import 'compile_data_creator.dart';
2626
///
2727
/// This method assumes a {@link DomAdapter} has been registered.
2828
Future<Outputs> processTemplates(AssetReader reader, AssetId assetId,
29-
{bool reflectPropertiesAsAttributes: false}) async {
30-
var viewDefResults = await createCompileData(reader, assetId);
29+
{bool reflectPropertiesAsAttributes: false, List<String> ambientDirectives}) async {
30+
var viewDefResults = await createCompileData(reader, assetId, ambientDirectives);
3131
if (viewDefResults == null) return null;
3232
final directiveMetadatas = viewDefResults.ngMeta.types.values;
3333
if (directiveMetadatas.isNotEmpty) {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ class TemplateCompiler extends Transformer {
3737
var primaryId = transform.primaryInput.id;
3838
var reader = new AssetReader.fromTransform(transform);
3939
var outputs = await processTemplates(reader, primaryId,
40-
reflectPropertiesAsAttributes: options.reflectPropertiesAsAttributes);
40+
reflectPropertiesAsAttributes: options.reflectPropertiesAsAttributes,
41+
ambientDirectives: options.ambientDirectives);
4142
var ngDepsCode = _emptyNgDepsContents;
4243
var templatesCode = '';
4344
if (outputs != null) {

modules_dart/transform/test/transform/template_compiler/all_tests.dart

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,10 @@ void allTests() {
7474
updateReader();
7575
});
7676

77-
Future<String> process(AssetId assetId) {
77+
Future<String> process(AssetId assetId, {List<String> ambientDirectives}) {
7878
logger = new RecordingLogger();
79-
return log.setZoned(logger, () => processTemplates(reader, assetId));
79+
return log.setZoned(logger, () => processTemplates(reader, assetId,
80+
ambientDirectives: ambientDirectives));
8081
}
8182

8283
// TODO(tbosch): This is just a temporary test that makes sure that the dart
@@ -346,6 +347,65 @@ void allTests() {
346347

347348
expect(didThrow).toBeFalse();
348349
});
350+
351+
it('should include ambient directives.', () async {
352+
fooComponentMeta.template = new CompileTemplateMetadata(template: '<bar/>');
353+
final viewAnnotation = new AnnotationModel()
354+
..name = 'View'
355+
..isView = true;
356+
357+
barNgMeta.aliases['AMBIENT'] = [barComponentMeta.type.name];
358+
updateReader();
359+
360+
final outputs = await process(fooAssetId, ambientDirectives: ['package:a/bar.dart#AMBIENT']);
361+
final ngDeps = outputs.ngDeps;
362+
expect(ngDeps).toBeNotNull();
363+
expect(outputs.templatesCode)
364+
..toBeNotNull()
365+
..toContain(barComponentMeta.template.template);
366+
});
367+
368+
it('should include ambient directives when it it a list.', () async {
369+
fooComponentMeta.template = new CompileTemplateMetadata(template: '<bar/>');
370+
final viewAnnotation = new AnnotationModel()
371+
..name = 'View'
372+
..isView = true;
373+
374+
barNgMeta.types['AMBIENT'] = barComponentMeta;
375+
updateReader();
376+
377+
final outputs = await process(fooAssetId, ambientDirectives: ['package:a/bar.dart#AMBIENT']);
378+
final ngDeps = outputs.ngDeps;
379+
expect(ngDeps).toBeNotNull();
380+
expect(outputs.templatesCode)
381+
..toBeNotNull()
382+
..toContain(barComponentMeta.template.template);
383+
});
384+
385+
it('should work when ambient directives config is null.', () async {
386+
final outputs = await process(fooAssetId, ambientDirectives: null);
387+
final ngDeps = outputs.ngDeps;
388+
expect(ngDeps).toBeNotNull();
389+
});
390+
391+
it('should work when the ambient directives config is not formatted properly.', () async {
392+
final outputs = await process(fooAssetId, ambientDirectives: ['INVALID']);
393+
final ngDeps = outputs.ngDeps;
394+
expect(ngDeps).toBeNotNull();
395+
});
396+
397+
it('should work when the file with ambient directives cannot be found.', () async {
398+
final outputs = await process(
399+
fooAssetId, ambientDirectives: ['package:a/invalid.dart#AMBIENT']);
400+
final ngDeps = outputs.ngDeps;
401+
expect(ngDeps).toBeNotNull();
402+
});
403+
404+
it('should work when the ambient directives token cannot be found.', () async {
405+
final outputs = await process(fooAssetId, ambientDirectives: ['package:a/bar.dart#AMBIENT']);
406+
final ngDeps = outputs.ngDeps;
407+
expect(ngDeps).toBeNotNull();
408+
});
349409
}
350410

351411
void _formatThenExpectEquals(String actual, String expected) {

0 commit comments

Comments
 (0)