Skip to content

Commit e7d65ad

Browse files
author
Tim Blasi
committed
fix(dart/transform): Handle export cycles
Currently, an export cycle in dart inputs will cause the transformer to hang indefinitely on the `DirectiveMetadataExtractor` step. Closes angular#4370
1 parent af9f916 commit e7d65ad

File tree

5 files changed

+81
-5
lines changed

5 files changed

+81
-5
lines changed

modules_dart/transform/lib/src/transform/directive_metadata_extractor/extractor.dart

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@ import 'package:code_transformers/assets.dart';
2222
/// [NgMeta] if there are no `Directive`-annotated classes in `entryPoint`.
2323
Future<NgMeta> extractDirectiveMetadata(
2424
AssetReader reader, AssetId entryPoint) {
25-
return _extractDirectiveMetadataRecursive(reader, entryPoint);
25+
return _extractDirectiveMetadataRecursive(
26+
reader, entryPoint, new Set<AssetId>());
2627
}
2728

28-
var _nullFuture = new Future.value(null);
29+
final _nullFuture = new Future.value(null);
2930

3031
Future<NgMeta> _extractDirectiveMetadataRecursive(
31-
AssetReader reader, AssetId entryPoint) async {
32+
AssetReader reader, AssetId entryPoint, Set<AssetId> seen) async {
33+
if (seen.contains(entryPoint)) return _nullFuture;
34+
seen.add(entryPoint);
3235
var ngMeta = new NgMeta.empty();
3336
if (!(await reader.hasInput(entryPoint))) return ngMeta;
3437

@@ -51,8 +54,12 @@ Future<NgMeta> _extractDirectiveMetadataRecursive(
5154
var assetId = uriToAssetId(entryPoint, uri, logger, null /* span */,
5255
errorOnAbsolute: false);
5356
if (assetId == entryPoint) return _nullFuture;
54-
return _extractDirectiveMetadataRecursive(reader, assetId)
55-
.then(ngMeta.addAll);
57+
return _extractDirectiveMetadataRecursive(reader, assetId, seen)
58+
.then((exportedNgMeta) {
59+
if (exportedNgMeta != null) {
60+
ngMeta.addAll(exportedNgMeta);
61+
}
62+
});
5663
}));
5764
return ngMeta;
5865
}

modules_dart/transform/test/transform/directive_metadata_extractor/all_tests.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,20 @@ void allTests() {
193193
expect(extracted.types['BazComponent'].selector).toEqual('[baz]');
194194
});
195195

196+
it('should handle `DirectiveMetadata` export cycles gracefully.', () async {
197+
var extracted = await extractDirectiveMetadata(
198+
reader,
199+
new AssetId('a',
200+
'directive_metadata_extractor/export_cycle_files/baz.ng_deps.dart'));
201+
expect(extracted.types).toContain('FooComponent');
202+
expect(extracted.types).toContain('BarComponent');
203+
expect(extracted.types).toContain('BazComponent');
204+
205+
expect(extracted.types['FooComponent'].selector).toEqual('[foo]');
206+
expect(extracted.types['BarComponent'].selector).toEqual('[bar]');
207+
expect(extracted.types['BazComponent'].selector).toEqual('[baz]');
208+
});
209+
196210
it(
197211
'should include `DirectiveMetadata` from exported files '
198212
'expressed as absolute uris', () async {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
library foo.ng_deps.dart;
2+
3+
import 'bar.dart';
4+
import 'package:angular2/src/core/metadata.dart';
5+
6+
export 'baz.dart';
7+
import 'baz.ng_deps.dart' as i0;
8+
9+
var _visited = false;
10+
void initReflector(reflector) {
11+
if (_visited) return;
12+
_visited = true;
13+
reflector
14+
..registerType(
15+
BarComponent,
16+
new ReflectionInfo(const [const Component(selector: '[bar]')], const [],
17+
() => new BarComponent()));
18+
i0.initReflector(reflector);
19+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
library foo.ng_deps.dart;
2+
3+
import 'baz.dart';
4+
import 'package:angular2/src/core/metadata.dart';
5+
6+
export 'foo.dart';
7+
8+
var _visited = false;
9+
void initReflector(reflector) {
10+
if (_visited) return;
11+
_visited = true;
12+
reflector
13+
..registerType(
14+
BazComponent,
15+
new ReflectionInfo(const [const Component(selector: '[baz]')], const [],
16+
() => new BazComponent()));
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
library foo.ng_deps.dart;
2+
3+
import 'foo.dart';
4+
import 'package:angular2/src/core/metadata.dart';
5+
6+
export 'bar.dart';
7+
import 'bar.ng_deps.dart' as i0;
8+
9+
var _visited = false;
10+
void initReflector(reflector) {
11+
if (_visited) return;
12+
_visited = true;
13+
reflector
14+
..registerType(
15+
FooComponent,
16+
new ReflectionInfo(const [const Component(selector: '[foo]')], const [],
17+
() => new FooComponent()));
18+
i0.initReflector(reflector);
19+
}

0 commit comments

Comments
 (0)