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 #4370
This commit is contained in:
		
							parent
							
								
									af9f916a9c
								
							
						
					
					
						commit
						e7d65ad96f
					
				| @ -22,13 +22,16 @@ import 'package:code_transformers/assets.dart'; | |||||||
| /// [NgMeta] if there are no `Directive`-annotated classes in `entryPoint`. | /// [NgMeta] if there are no `Directive`-annotated classes in `entryPoint`. | ||||||
| Future<NgMeta> extractDirectiveMetadata( | Future<NgMeta> extractDirectiveMetadata( | ||||||
|     AssetReader reader, AssetId entryPoint) { |     AssetReader reader, AssetId entryPoint) { | ||||||
|   return _extractDirectiveMetadataRecursive(reader, entryPoint); |   return _extractDirectiveMetadataRecursive( | ||||||
|  |       reader, entryPoint, new Set<AssetId>()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var _nullFuture = new Future.value(null); | final _nullFuture = new Future.value(null); | ||||||
| 
 | 
 | ||||||
| Future<NgMeta> _extractDirectiveMetadataRecursive( | Future<NgMeta> _extractDirectiveMetadataRecursive( | ||||||
|     AssetReader reader, AssetId entryPoint) async { |     AssetReader reader, AssetId entryPoint, Set<AssetId> seen) async { | ||||||
|  |   if (seen.contains(entryPoint)) return _nullFuture; | ||||||
|  |   seen.add(entryPoint); | ||||||
|   var ngMeta = new NgMeta.empty(); |   var ngMeta = new NgMeta.empty(); | ||||||
|   if (!(await reader.hasInput(entryPoint))) return ngMeta; |   if (!(await reader.hasInput(entryPoint))) return ngMeta; | ||||||
| 
 | 
 | ||||||
| @ -51,8 +54,12 @@ Future<NgMeta> _extractDirectiveMetadataRecursive( | |||||||
|     var assetId = uriToAssetId(entryPoint, uri, logger, null /* span */, |     var assetId = uriToAssetId(entryPoint, uri, logger, null /* span */, | ||||||
|         errorOnAbsolute: false); |         errorOnAbsolute: false); | ||||||
|     if (assetId == entryPoint) return _nullFuture; |     if (assetId == entryPoint) return _nullFuture; | ||||||
|     return _extractDirectiveMetadataRecursive(reader, assetId) |     return _extractDirectiveMetadataRecursive(reader, assetId, seen) | ||||||
|         .then(ngMeta.addAll); |         .then((exportedNgMeta) { | ||||||
|  |       if (exportedNgMeta != null) { | ||||||
|  |         ngMeta.addAll(exportedNgMeta); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|   })); |   })); | ||||||
|   return ngMeta; |   return ngMeta; | ||||||
| } | } | ||||||
|  | |||||||
| @ -193,6 +193,20 @@ void allTests() { | |||||||
|       expect(extracted.types['BazComponent'].selector).toEqual('[baz]'); |       expect(extracted.types['BazComponent'].selector).toEqual('[baz]'); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     it('should handle `DirectiveMetadata` export cycles gracefully.', () async { | ||||||
|  |       var extracted = await extractDirectiveMetadata( | ||||||
|  |           reader, | ||||||
|  |           new AssetId('a', | ||||||
|  |               'directive_metadata_extractor/export_cycle_files/baz.ng_deps.dart')); | ||||||
|  |       expect(extracted.types).toContain('FooComponent'); | ||||||
|  |       expect(extracted.types).toContain('BarComponent'); | ||||||
|  |       expect(extracted.types).toContain('BazComponent'); | ||||||
|  | 
 | ||||||
|  |       expect(extracted.types['FooComponent'].selector).toEqual('[foo]'); | ||||||
|  |       expect(extracted.types['BarComponent'].selector).toEqual('[bar]'); | ||||||
|  |       expect(extracted.types['BazComponent'].selector).toEqual('[baz]'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     it( |     it( | ||||||
|         'should include `DirectiveMetadata` from exported files ' |         'should include `DirectiveMetadata` from exported files ' | ||||||
|         'expressed as absolute uris', () async { |         'expressed as absolute uris', () async { | ||||||
|  | |||||||
| @ -0,0 +1,19 @@ | |||||||
|  | library foo.ng_deps.dart; | ||||||
|  | 
 | ||||||
|  | import 'bar.dart'; | ||||||
|  | import 'package:angular2/src/core/metadata.dart'; | ||||||
|  | 
 | ||||||
|  | export 'baz.dart'; | ||||||
|  | import 'baz.ng_deps.dart' as i0; | ||||||
|  | 
 | ||||||
|  | var _visited = false; | ||||||
|  | void initReflector(reflector) { | ||||||
|  |   if (_visited) return; | ||||||
|  |   _visited = true; | ||||||
|  |   reflector | ||||||
|  |     ..registerType( | ||||||
|  |         BarComponent, | ||||||
|  |         new ReflectionInfo(const [const Component(selector: '[bar]')], const [], | ||||||
|  |             () => new BarComponent())); | ||||||
|  |   i0.initReflector(reflector); | ||||||
|  | } | ||||||
| @ -0,0 +1,17 @@ | |||||||
|  | library foo.ng_deps.dart; | ||||||
|  | 
 | ||||||
|  | import 'baz.dart'; | ||||||
|  | import 'package:angular2/src/core/metadata.dart'; | ||||||
|  | 
 | ||||||
|  | export 'foo.dart'; | ||||||
|  | 
 | ||||||
|  | var _visited = false; | ||||||
|  | void initReflector(reflector) { | ||||||
|  |   if (_visited) return; | ||||||
|  |   _visited = true; | ||||||
|  |   reflector | ||||||
|  |     ..registerType( | ||||||
|  |         BazComponent, | ||||||
|  |         new ReflectionInfo(const [const Component(selector: '[baz]')], const [], | ||||||
|  |             () => new BazComponent())); | ||||||
|  | } | ||||||
| @ -0,0 +1,19 @@ | |||||||
|  | library foo.ng_deps.dart; | ||||||
|  | 
 | ||||||
|  | import 'foo.dart'; | ||||||
|  | import 'package:angular2/src/core/metadata.dart'; | ||||||
|  | 
 | ||||||
|  | export 'bar.dart'; | ||||||
|  | import 'bar.ng_deps.dart' as i0; | ||||||
|  | 
 | ||||||
|  | var _visited = false; | ||||||
|  | void initReflector(reflector) { | ||||||
|  |   if (_visited) return; | ||||||
|  |   _visited = true; | ||||||
|  |   reflector | ||||||
|  |     ..registerType( | ||||||
|  |         FooComponent, | ||||||
|  |         new ReflectionInfo(const [const Component(selector: '[foo]')], const [], | ||||||
|  |             () => new FooComponent())); | ||||||
|  |   i0.initReflector(reflector); | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user