fix(ivy): let ngcc transform @angular/core typings with relative imports (#27055)
PR Close #27055
This commit is contained in:
		
							parent
							
								
									c8c8648abf
								
							
						
					
					
						commit
						0d9b27ff26
					
				| @ -33,6 +33,12 @@ ivy-ngcc | ||||
|   grep "ApplicationModule.ngModuleDef = ɵngcc0.defineNgModule" node_modules/@angular/core/esm5/src/application_module.js | ||||
|   if [[ $? != 0 ]]; then exit 1; fi | ||||
| 
 | ||||
| # Did it transform @angular/core typing files correctly? | ||||
|   grep "import [*] as ɵngcc0 from './r3_symbols';" node_modules/@angular/core/src/application_module.d.ts | ||||
|   if [[ $? != 0 ]]; then exit 1; fi | ||||
|   grep "static ngInjectorDef: ɵngcc0.InjectorDef<ApplicationModule>;" node_modules/@angular/core/src/application_module.d.ts | ||||
|   if [[ $? != 0 ]]; then exit 1; fi | ||||
| 
 | ||||
| # Can it be safely run again (as a noop)? | ||||
| ivy-ngcc | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										31
									
								
								packages/compiler-cli/src/ngcc/src/packages/bundle.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								packages/compiler-cli/src/ngcc/src/packages/bundle.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| /** | ||||
|  * @license | ||||
|  * Copyright Google Inc. All Rights Reserved. | ||||
|  * | ||||
|  * Use of this source code is governed by an MIT-style license that can be | ||||
|  * found in the LICENSE file at https://angular.io/license
 | ||||
|  */ | ||||
| 
 | ||||
| import * as ts from 'typescript'; | ||||
| 
 | ||||
| /** | ||||
|  * A bundle represents the currently compiled entry point format, containing | ||||
|  * information that is necessary for compiling @angular/core with ngcc. | ||||
|  */ | ||||
| export interface BundleInfo { | ||||
|   isCore: boolean; | ||||
|   isFlat: boolean; | ||||
|   rewriteCoreImportsTo: ts.SourceFile|null; | ||||
|   rewriteCoreDtsImportsTo: ts.SourceFile|null; | ||||
| } | ||||
| 
 | ||||
| export function createBundleInfo( | ||||
|     isCore: boolean, rewriteCoreImportsTo: ts.SourceFile | null, | ||||
|     rewriteCoreDtsImportsTo: ts.SourceFile | null): BundleInfo { | ||||
|   return { | ||||
|     isCore, | ||||
|     isFlat: rewriteCoreImportsTo === null, | ||||
|     rewriteCoreImportsTo: rewriteCoreImportsTo, | ||||
|     rewriteCoreDtsImportsTo: rewriteCoreDtsImportsTo, | ||||
|   }; | ||||
| } | ||||
| @ -20,6 +20,7 @@ import {EsmRenderer} from '../rendering/esm_renderer'; | ||||
| import {FileInfo, Renderer} from '../rendering/renderer'; | ||||
| 
 | ||||
| import {checkMarkerFile, writeMarkerFile} from './build_marker'; | ||||
| import {BundleInfo, createBundleInfo} from './bundle'; | ||||
| import {EntryPoint, EntryPointFormat} from './entry_point'; | ||||
| 
 | ||||
| /** | ||||
| @ -70,27 +71,40 @@ export class Transformer { | ||||
|     const host = ts.createCompilerHost(options); | ||||
|     const rootDirs = this.getRootDirs(host, options); | ||||
|     const isCore = entryPoint.name === '@angular/core'; | ||||
|     const r3SymbolsPath = isCore ? this.findR3SymbolsPath(dirname(entryPointFilePath)) : null; | ||||
|     const r3SymbolsPath = | ||||
|         isCore ? this.findR3SymbolsPath(dirname(entryPointFilePath), 'r3_symbols.js') : null; | ||||
|     const rootPaths = r3SymbolsPath ? [entryPointFilePath, r3SymbolsPath] : [entryPointFilePath]; | ||||
|     const packageProgram = ts.createProgram(rootPaths, options, host); | ||||
|     console.time(entryPoint.name + '(dtsmappper creation)'); | ||||
|     const dtsFilePath = entryPoint.typings; | ||||
|     const dtsProgram = transformDts ? ts.createProgram([entryPoint.typings], options, host) : null; | ||||
|     console.timeEnd(entryPoint.name + '(dtsmappper creation)'); | ||||
|     const reflectionHost = this.getHost(isCore, format, packageProgram, dtsFilePath, dtsProgram); | ||||
|     const r3SymbolsFile = r3SymbolsPath && packageProgram.getSourceFile(r3SymbolsPath) || null; | ||||
| 
 | ||||
|     // Create the program for processing DTS files if enabled for this format.
 | ||||
|     const dtsFilePath = entryPoint.typings; | ||||
|     let dtsProgram: ts.Program|null = null; | ||||
|     let r3SymbolsDtsFile: ts.SourceFile|null = null; | ||||
|     if (transformDts) { | ||||
|       console.time(`${entryPoint.name} (dtsMapper creation)`); | ||||
|       const r3SymbolsDtsPath = | ||||
|           isCore ? this.findR3SymbolsPath(dirname(dtsFilePath), 'r3_symbols.d.ts') : null; | ||||
|       const rootDtsPaths = r3SymbolsDtsPath ? [dtsFilePath, r3SymbolsDtsPath] : [dtsFilePath]; | ||||
| 
 | ||||
|       dtsProgram = ts.createProgram(rootDtsPaths, options, host); | ||||
|       r3SymbolsDtsFile = r3SymbolsDtsPath && dtsProgram.getSourceFile(r3SymbolsDtsPath) || null; | ||||
|       console.timeEnd(`${entryPoint.name} (dtsMapper creation)`); | ||||
|     } | ||||
| 
 | ||||
|     const bundle = createBundleInfo(isCore, r3SymbolsFile, r3SymbolsDtsFile); | ||||
|     const reflectionHost = this.getHost(isCore, format, packageProgram, dtsFilePath, dtsProgram); | ||||
| 
 | ||||
|     // Parse and analyze the files.
 | ||||
|     const {decorationAnalyses, switchMarkerAnalyses} = | ||||
|         this.analyzeProgram(packageProgram, reflectionHost, rootDirs, isCore); | ||||
| 
 | ||||
|     console.time(entryPoint.name + '(rendering)'); | ||||
|     console.time(`${entryPoint.name} (rendering)`); | ||||
|     // Transform the source files and source maps.
 | ||||
|     const renderer = this.getRenderer( | ||||
|         format, packageProgram, reflectionHost, isCore, r3SymbolsFile, transformDts); | ||||
|     const renderer = this.getRenderer(format, packageProgram, reflectionHost, bundle, transformDts); | ||||
|     const renderedFiles = | ||||
|         renderer.renderProgram(packageProgram, decorationAnalyses, switchMarkerAnalyses); | ||||
|     console.timeEnd(entryPoint.name + '(rendering)'); | ||||
|     console.timeEnd(`${entryPoint.name} (rendering)`); | ||||
| 
 | ||||
|     // Write out all the transformed files.
 | ||||
|     renderedFiles.forEach(file => this.writeFile(file)); | ||||
| @ -125,17 +139,15 @@ export class Transformer { | ||||
|   } | ||||
| 
 | ||||
|   getRenderer( | ||||
|       format: string, program: ts.Program, host: NgccReflectionHost, isCore: boolean, | ||||
|       rewriteCoreImportsTo: ts.SourceFile|null, transformDts: boolean): Renderer { | ||||
|       format: string, program: ts.Program, host: NgccReflectionHost, bundle: BundleInfo, | ||||
|       transformDts: boolean): Renderer { | ||||
|     switch (format) { | ||||
|       case 'esm2015': | ||||
|       case 'fesm2015': | ||||
|         return new EsmRenderer( | ||||
|             host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath, transformDts); | ||||
|         return new EsmRenderer(host, bundle, this.sourcePath, this.targetPath, transformDts); | ||||
|       case 'esm5': | ||||
|       case 'fesm5': | ||||
|         return new Esm5Renderer( | ||||
|             host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath, transformDts); | ||||
|         return new Esm5Renderer(host, bundle, this.sourcePath, this.targetPath, transformDts); | ||||
|       default: | ||||
|         throw new Error(`Renderer for "${format}" not yet implemented.`); | ||||
|     } | ||||
| @ -162,8 +174,8 @@ export class Transformer { | ||||
|     writeFileSync(file.path, file.contents, 'utf8'); | ||||
|   } | ||||
| 
 | ||||
|   findR3SymbolsPath(directory: string): string|null { | ||||
|     const r3SymbolsFilePath = resolve(directory, 'r3_symbols.js'); | ||||
|   findR3SymbolsPath(directory: string, fileName: string): string|null { | ||||
|     const r3SymbolsFilePath = resolve(directory, fileName); | ||||
|     if (existsSync(r3SymbolsFilePath)) { | ||||
|       return r3SymbolsFilePath; | ||||
|     } | ||||
| @ -181,7 +193,7 @@ export class Transformer { | ||||
|             }); | ||||
| 
 | ||||
|     for (const subDirectory of subDirectories) { | ||||
|       const r3SymbolsFilePath = this.findR3SymbolsPath(resolve(directory, subDirectory)); | ||||
|       const r3SymbolsFilePath = this.findR3SymbolsPath(resolve(directory, subDirectory), fileName); | ||||
|       if (r3SymbolsFilePath) { | ||||
|         return r3SymbolsFilePath; | ||||
|       } | ||||
|  | ||||
| @ -9,14 +9,14 @@ import * as ts from 'typescript'; | ||||
| import MagicString from 'magic-string'; | ||||
| import {NgccReflectionHost} from '../host/ngcc_host'; | ||||
| import {CompiledClass} from '../analysis/decoration_analyzer'; | ||||
| import {BundleInfo} from '../packages/bundle'; | ||||
| import {EsmRenderer} from './esm_renderer'; | ||||
| 
 | ||||
| export class Esm5Renderer extends EsmRenderer { | ||||
|   constructor( | ||||
|       protected host: NgccReflectionHost, protected isCore: boolean, | ||||
|       protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string, | ||||
|       protected targetPath: string, transformDts: boolean) { | ||||
|     super(host, isCore, rewriteCoreImportsTo, sourcePath, targetPath, transformDts); | ||||
|       protected host: NgccReflectionHost, protected bundle: BundleInfo, | ||||
|       protected sourcePath: string, protected targetPath: string, transformDts: boolean) { | ||||
|     super(host, bundle, sourcePath, targetPath, transformDts); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|  | ||||
| @ -9,14 +9,14 @@ import * as ts from 'typescript'; | ||||
| import MagicString from 'magic-string'; | ||||
| import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host'; | ||||
| import {CompiledClass} from '../analysis/decoration_analyzer'; | ||||
| import {BundleInfo} from '../packages/bundle'; | ||||
| import {Renderer} from './renderer'; | ||||
| 
 | ||||
| export class EsmRenderer extends Renderer { | ||||
|   constructor( | ||||
|       protected host: NgccReflectionHost, protected isCore: boolean, | ||||
|       protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string, | ||||
|       protected targetPath: string, transformDts: boolean) { | ||||
|     super(host, isCore, rewriteCoreImportsTo, sourcePath, targetPath, transformDts); | ||||
|       protected host: NgccReflectionHost, protected bundle: BundleInfo, | ||||
|       protected sourcePath: string, protected targetPath: string, transformDts: boolean) { | ||||
|     super(host, bundle, sourcePath, targetPath, transformDts); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|  | ||||
| @ -19,6 +19,7 @@ import {translateStatement, translateType} from '../../../ngtsc/translator'; | ||||
| import {NgccImportManager} from './ngcc_import_manager'; | ||||
| import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/decoration_analyzer'; | ||||
| import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer'; | ||||
| import {BundleInfo} from '../packages/bundle'; | ||||
| import {IMPORT_PREFIX} from '../constants'; | ||||
| import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host'; | ||||
| 
 | ||||
| @ -55,9 +56,9 @@ interface DtsClassInfo { | ||||
|  */ | ||||
| export abstract class Renderer { | ||||
|   constructor( | ||||
|       protected host: NgccReflectionHost, protected isCore: boolean, | ||||
|       protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string, | ||||
|       protected targetPath: string, protected transformDts: boolean) {} | ||||
|       protected host: NgccReflectionHost, protected bundle: BundleInfo, | ||||
|       protected sourcePath: string, protected targetPath: string, protected transformDts: boolean) { | ||||
|   } | ||||
| 
 | ||||
|   renderProgram( | ||||
|       program: ts.Program, decorationAnalyses: DecorationAnalyses, | ||||
| @ -101,7 +102,7 @@ export abstract class Renderer { | ||||
| 
 | ||||
|     if (compiledFile) { | ||||
|       const importManager = | ||||
|           new NgccImportManager(!this.rewriteCoreImportsTo, this.isCore, IMPORT_PREFIX); | ||||
|           new NgccImportManager(this.bundle.isFlat, this.bundle.isCore, IMPORT_PREFIX); | ||||
|       const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); | ||||
| 
 | ||||
|       compiledFile.compiledClasses.forEach(clazz => { | ||||
| @ -116,8 +117,8 @@ export abstract class Renderer { | ||||
|           compiledFile.sourceFile); | ||||
| 
 | ||||
|       this.addImports( | ||||
|           outputText, | ||||
|           importManager.getAllImports(compiledFile.sourceFile.fileName, this.rewriteCoreImportsTo)); | ||||
|           outputText, importManager.getAllImports( | ||||
|                           compiledFile.sourceFile.fileName, this.bundle.rewriteCoreImportsTo)); | ||||
| 
 | ||||
|       // TODO: remove contructor param metadata and property decorators (we need info from the
 | ||||
|       // handlers to do this)
 | ||||
| @ -130,7 +131,7 @@ export abstract class Renderer { | ||||
|   renderDtsFile(dtsFile: ts.SourceFile, dtsClasses: DtsClassInfo[]): FileInfo[] { | ||||
|     const input = this.extractSourceMap(dtsFile); | ||||
|     const outputText = new MagicString(input.source); | ||||
|     const importManager = new NgccImportManager(false, this.isCore, IMPORT_PREFIX); | ||||
|     const importManager = new NgccImportManager(false, this.bundle.isCore, IMPORT_PREFIX); | ||||
| 
 | ||||
|     dtsClasses.forEach(dtsClass => { | ||||
|       const endOfClass = dtsClass.dtsDeclaration.getEnd(); | ||||
| @ -142,7 +143,8 @@ export abstract class Renderer { | ||||
|     }); | ||||
| 
 | ||||
|     this.addImports( | ||||
|         outputText, importManager.getAllImports(dtsFile.fileName, this.rewriteCoreImportsTo)); | ||||
|         outputText, | ||||
|         importManager.getAllImports(dtsFile.fileName, this.bundle.rewriteCoreDtsImportsTo)); | ||||
| 
 | ||||
|     return this.renderSourceAndMap(dtsFile, input, outputText); | ||||
|   } | ||||
|  | ||||
| @ -12,6 +12,7 @@ import MagicString from 'magic-string'; | ||||
| import {makeProgram} from '../helpers/utils'; | ||||
| import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; | ||||
| import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; | ||||
| import {createBundleInfo} from '../../src/packages/bundle'; | ||||
| import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; | ||||
| import {EsmRenderer} from '../../src/rendering/esm_renderer'; | ||||
| 
 | ||||
| @ -23,7 +24,8 @@ function setup(file: {name: string, contents: string}, transformDts: boolean = f | ||||
|   const decorationAnalyses = | ||||
|       new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program); | ||||
|   const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); | ||||
|   const renderer = new EsmRenderer(host, false, null, dir, dir, false); | ||||
|   const bundle = createBundleInfo(false, null, null); | ||||
|   const renderer = new EsmRenderer(host, bundle, dir, dir, false); | ||||
|   return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses}; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -10,6 +10,7 @@ import MagicString from 'magic-string'; | ||||
| import {makeProgram, getDeclaration} from '../helpers/utils'; | ||||
| import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; | ||||
| import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; | ||||
| import {createBundleInfo} from '../../src/packages/bundle'; | ||||
| import {Esm5ReflectionHost} from '../../src/host/esm5_host'; | ||||
| import {Esm5Renderer} from '../../src/rendering/esm5_renderer'; | ||||
| 
 | ||||
| @ -20,7 +21,8 @@ function setup(file: {name: string, contents: string}) { | ||||
|   const decorationAnalyses = | ||||
|       new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program); | ||||
|   const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); | ||||
|   const renderer = new Esm5Renderer(host, false, null, '', '', false); | ||||
|   const bundle = createBundleInfo(false, null, null); | ||||
|   const renderer = new Esm5Renderer(host, bundle, '', '', false); | ||||
|   return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses}; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -13,13 +13,13 @@ import {fromObject, generateMapFileComment} from 'convert-source-map'; | ||||
| import {makeProgram} from '../helpers/utils'; | ||||
| import {CompiledClass, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; | ||||
| import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; | ||||
| import {BundleInfo, createBundleInfo} from '../../src/packages/bundle'; | ||||
| import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; | ||||
| import {Renderer} from '../../src/rendering/renderer'; | ||||
| 
 | ||||
| class TestRenderer extends Renderer { | ||||
|   constructor( | ||||
|       host: Esm2015ReflectionHost, isCore: boolean, rewriteCoreImportsTo: ts.SourceFile|null) { | ||||
|     super(host, isCore, rewriteCoreImportsTo, '/src', '/dist', false); | ||||
|   constructor(host: Esm2015ReflectionHost, bundle: BundleInfo) { | ||||
|     super(host, bundle, '/src', '/dist', false); | ||||
|   } | ||||
|   addImports(output: MagicString, imports: {name: string, as: string}[]) { | ||||
|     output.prepend('\n// ADD IMPORTS\n'); | ||||
| @ -42,14 +42,15 @@ function createTestRenderer( | ||||
|     files: {name: string, contents: string}[], | ||||
|     options: {isCore?: boolean, rewriteCoreImportsTo?: string} = {}) { | ||||
|   const program = makeProgram(...files); | ||||
|   const host = new Esm2015ReflectionHost(options.isCore || false, program.getTypeChecker()); | ||||
|   const decorationAnalyses = | ||||
|       new DecorationAnalyzer(program.getTypeChecker(), host, [''], options.isCore || false) | ||||
|           .analyzeProgram(program); | ||||
|   const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); | ||||
|   const rewriteCoreImportsTo = | ||||
|       options.rewriteCoreImportsTo ? program.getSourceFile(options.rewriteCoreImportsTo) ! : null; | ||||
|   const renderer = new TestRenderer(host, options.isCore || false, rewriteCoreImportsTo); | ||||
|   const bundle = createBundleInfo(options.isCore || false, rewriteCoreImportsTo, null); | ||||
|   const host = new Esm2015ReflectionHost(bundle.isCore, program.getTypeChecker()); | ||||
|   const decorationAnalyses = | ||||
|       new DecorationAnalyzer(program.getTypeChecker(), host, [''], bundle.isCore) | ||||
|           .analyzeProgram(program); | ||||
|   const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); | ||||
|   const renderer = new TestRenderer(host, bundle); | ||||
|   spyOn(renderer, 'addImports').and.callThrough(); | ||||
|   spyOn(renderer, 'addDefinitions').and.callThrough(); | ||||
|   spyOn(renderer, 'removeDecorators').and.callThrough(); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user