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`. | ||||
| Future<NgMeta> extractDirectiveMetadata( | ||||
|     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( | ||||
|     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(); | ||||
|   if (!(await reader.hasInput(entryPoint))) return ngMeta; | ||||
| 
 | ||||
| @ -51,8 +54,12 @@ Future<NgMeta> _extractDirectiveMetadataRecursive( | ||||
|     var assetId = uriToAssetId(entryPoint, uri, logger, null /* span */, | ||||
|         errorOnAbsolute: false); | ||||
|     if (assetId == entryPoint) return _nullFuture; | ||||
|     return _extractDirectiveMetadataRecursive(reader, assetId) | ||||
|         .then(ngMeta.addAll); | ||||
|     return _extractDirectiveMetadataRecursive(reader, assetId, seen) | ||||
|         .then((exportedNgMeta) { | ||||
|       if (exportedNgMeta != null) { | ||||
|         ngMeta.addAll(exportedNgMeta); | ||||
|       } | ||||
|     }); | ||||
|   })); | ||||
|   return ngMeta; | ||||
| } | ||||
|  | ||||
| @ -193,6 +193,20 @@ void allTests() { | ||||
|       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( | ||||
|         'should include `DirectiveMetadata` from exported files ' | ||||
|         '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