Skip to content

Commit 0520ca6

Browse files
author
Tim Blasi
committed
feat(dart/transform): Add DirectiveMetadataExtractor transform step
Add a step that reads `DirectiveMetadata` object off annotated classes into `.ng_meta.dart` files. These will be used by the `TemplateCompiler` step as inputs to the Angular 2 render compiler. Update one test to avoid unsupported functionality, format others.
1 parent 8e1d53b commit 0520ca6

File tree

27 files changed

+214
-78
lines changed

27 files changed

+214
-78
lines changed
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
library angular2.transform.template_compiler.directive_metadata_reader;
1+
library angular2.transform.common.directive_metadata_reader;
22

33
import 'package:analyzer/analyzer.dart';
44
import 'package:angular2/src/render/api.dart';
5-
import 'package:angular2/src/transform/common/logging.dart';
6-
import 'package:angular2/src/transform/common/parser.dart';
5+
import 'logging.dart';
6+
import 'parser.dart';
77

88
/// Reads [DirectiveMetadata] from the `attributes` of `t`.
99
DirectiveMetadata readDirectiveMetadata(RegisteredType t) {

modules/angular2/src/transform/common/names.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const SETUP_METHOD_NAME = 'initReflector';
44
const REFLECTOR_VAR_NAME = 'reflector';
55
const TRANSFORM_DYNAMIC_MODE = 'transform_dynamic';
66
const DEPS_EXTENSION = '.ng_deps.dart';
7+
const META_EXTENSION = '.ng_meta.dart';
78
const REFLECTION_CAPABILITIES_NAME = 'ReflectionCapabilities';
89
const REGISTER_TYPE_METHOD_NAME = 'registerType';
910
const REGISTER_GETTERS_METHOD_NAME = 'registerGetters';
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
library angular2.transform.directive_metadata_extractor.extractor;
2+
3+
import 'dart:async';
4+
5+
import 'package:angular2/src/render/api.dart';
6+
import 'package:angular2/src/transform/common/asset_reader.dart';
7+
import 'package:angular2/src/transform/common/directive_metadata_reader.dart';
8+
import 'package:angular2/src/transform/common/parser.dart';
9+
import 'package:barback/barback.dart';
10+
11+
/// Returns a map from a class name (that is, its `Identifier` stringified)
12+
/// to its [DirectiveMetadata].
13+
/// Will return `null` if there are no `Directive`-annotated classes in
14+
/// `entryPoint`.
15+
Future<Map<String, DirectiveMetadata>> extractDirectiveMetadata(
16+
AssetReader reader, AssetId entryPoint) async {
17+
var parser = new Parser(reader);
18+
NgDeps ngDeps = await parser.parse(entryPoint);
19+
if (ngDeps == null || ngDeps.registeredTypes.isEmpty) return null;
20+
var retVal = <String, DirectiveMetadata>{};
21+
ngDeps.registeredTypes.forEach((rType) {
22+
var meta = readDirectiveMetadata(rType);
23+
if (meta != null) {
24+
retVal['${rType.typeName}'] = meta;
25+
}
26+
});
27+
return retVal;
28+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
library angular2.transform.directive_metadata_extractor.transformer;
2+
3+
import 'dart:async';
4+
import 'dart:convert';
5+
6+
import 'package:angular2/src/render/dom/convert.dart';
7+
import 'package:angular2/src/transform/common/asset_reader.dart';
8+
import 'package:angular2/src/transform/common/logging.dart' as log;
9+
import 'package:angular2/src/transform/common/names.dart';
10+
import 'package:barback/barback.dart';
11+
12+
import 'extractor.dart';
13+
14+
/// Transformer responsible for processing .ng_deps.dart files created by
15+
/// {@link DirectiveProcessor} and creating associated `.ng_meta.dart` files.
16+
/// These files contain commented Json-formatted representations of all
17+
/// `Directive`s in the associated file.
18+
class DirectiveMetadataExtractor extends Transformer {
19+
DirectiveMetadataExtractor();
20+
21+
@override
22+
bool isPrimary(AssetId id) => id.path.endsWith(DEPS_EXTENSION);
23+
24+
@override
25+
Future apply(Transform transform) async {
26+
log.init(transform);
27+
28+
try {
29+
var reader = new AssetReader.fromTransform(transform);
30+
var fromAssetId = transform.primaryInput.id;
31+
32+
var metadataMap = await extractDirectiveMetadata(reader, fromAssetId);
33+
if (metadataMap != null) {
34+
var jsonMap = <String, Map>{};
35+
metadataMap.forEach((k, v) {
36+
jsonMap[k] = directiveMetadataToMap(v);
37+
});
38+
transform.addOutput(new Asset.fromString(
39+
_outputAssetId(fromAssetId), '// ${JSON.encode(jsonMap)}'));
40+
}
41+
} catch (ex, stackTrace) {
42+
log.logger.error('Extracting ng metadata failed.\n'
43+
'Exception: $ex\n'
44+
'Stack Trace: $stackTrace');
45+
}
46+
return null;
47+
}
48+
}
49+
50+
AssetId _outputAssetId(AssetId inputAssetId) {
51+
assert(inputAssetId.path.endsWith(DEPS_EXTENSION));
52+
var pathIn = inputAssetId.path;
53+
return new AssetId(inputAssetId.package,
54+
'${pathIn.substring(0, pathIn.length - DEPS_EXTENSION.length)}'
55+
'${META_EXTENSION}');
56+
}

modules/angular2/src/transform/transformer.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:barback/barback.dart';
44
import 'package:dart_style/dart_style.dart';
55

66
import 'directive_linker/transformer.dart';
7+
import 'directive_metadata_extractor/transformer.dart';
78
import 'directive_processor/transformer.dart';
89
import 'bind_generator/transformer.dart';
910
import 'reflection_remover/transformer.dart';
@@ -24,7 +25,7 @@ class AngularTransformerGroup extends TransformerGroup {
2425
var phases = [
2526
[new ReflectionRemover(options)],
2627
[new DirectiveProcessor(options)],
27-
[new DirectiveLinker()],
28+
[new DirectiveLinker(), new DirectiveMetadataExtractor()],
2829
[new BindGenerator(options)],
2930
[new TemplateCompiler(options)]
3031
];
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
library angular2.test.transform.directive_metadata_extractor.all_tests;
2+
3+
import 'dart:async';
4+
import 'package:angular2/src/render/api.dart';
5+
import 'package:angular2/src/transform/common/directive_metadata_reader.dart';
6+
import 'package:angular2/src/transform/common/logging.dart';
7+
import 'package:angular2/src/transform/common/parser.dart';
8+
import 'package:barback/barback.dart';
9+
import 'package:dart_style/dart_style.dart';
10+
import 'package:guinness/guinness.dart';
11+
12+
import '../common/read_file.dart';
13+
14+
var formatter = new DartFormatter();
15+
16+
void allTests() {
17+
var reader = new TestAssetReader();
18+
var parser = new Parser(reader);
19+
20+
beforeEach(() => setLogger(new PrintLogger()));
21+
22+
Future<DirectiveMetadata> readMetadata(inputPath) async {
23+
var ngDeps = await parser.parse(new AssetId('a', inputPath));
24+
return readDirectiveMetadata(ngDeps.registeredTypes.first);
25+
}
26+
27+
it('should parse selectors', () async {
28+
var metadata = await readMetadata(
29+
'directive_metadata_extractor/directive_metadata_files/selector.ng_deps.dart');
30+
expect(metadata.selector).toEqual('hello-app');
31+
});
32+
33+
it('should parse compile children values', () async {
34+
var metadata = await readMetadata('directive_metadata_extractor/'
35+
'directive_metadata_files/compile_children.ng_deps.dart');
36+
expect(metadata.compileChildren).toBeTrue();
37+
38+
metadata = await readMetadata(
39+
'directive_metadata_extractor/directive_metadata_files/selector.ng_deps.dart');
40+
expect(metadata.compileChildren).toBeFalse();
41+
});
42+
43+
it('should parse properties.', () async {
44+
var metadata = await readMetadata('directive_metadata_extractor/'
45+
'directive_metadata_files/properties.ng_deps.dart');
46+
expect(metadata.properties).toBeNotNull();
47+
expect(metadata.properties.length).toBe(2);
48+
expect(metadata.properties).toContain('key1');
49+
expect(metadata.properties['key1']).toEqual('val1');
50+
expect(metadata.properties).toContain('key2');
51+
expect(metadata.properties['key2']).toEqual('val2');
52+
});
53+
54+
it('should parse host listeners.', () async {
55+
var metadata = await readMetadata('directive_metadata_extractor/'
56+
'directive_metadata_files/host_listeners.ng_deps.dart');
57+
expect(metadata.hostListeners).toBeNotNull();
58+
expect(metadata.hostListeners.length).toBe(2);
59+
expect(metadata.hostListeners).toContain('change');
60+
expect(metadata.hostListeners['change']).toEqual('onChange(\$event)');
61+
expect(metadata.hostListeners).toContain('keyDown');
62+
expect(metadata.hostListeners['keyDown']).toEqual('onKeyDown(\$event)');
63+
});
64+
65+
it('should fail when a class is annotated with multiple Directives.',
66+
() async {
67+
var ngDeps = await parser.parse(new AssetId('a',
68+
'directive_metadata_extractor/'
69+
'directive_metadata_files/too_many_directives.ng_deps.dart'));
70+
expect(() => readDirectiveMetadata(ngDeps.registeredTypes.first))
71+
.toThrowWith(anInstanceOf: PrintLoggerError);
72+
});
73+
}

0 commit comments

Comments
 (0)