Skip to content

Commit 0d9b27f

Browse files
JoostKmhevery
authored andcommitted
fix(ivy): let ngcc transform @angular/core typings with relative imports (#27055)
PR Close #27055
1 parent c8c8648 commit 0d9b27f

9 files changed

Lines changed: 100 additions & 44 deletions

File tree

integration/ngcc/test.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ ivy-ngcc
3333
grep "ApplicationModule.ngModuleDef = ɵngcc0.defineNgModule" node_modules/@angular/core/esm5/src/application_module.js
3434
if [[ $? != 0 ]]; then exit 1; fi
3535

36+
# Did it transform @angular/core typing files correctly?
37+
grep "import [*] as ɵngcc0 from './r3_symbols';" node_modules/@angular/core/src/application_module.d.ts
38+
if [[ $? != 0 ]]; then exit 1; fi
39+
grep "static ngInjectorDef: ɵngcc0.InjectorDef<ApplicationModule>;" node_modules/@angular/core/src/application_module.d.ts
40+
if [[ $? != 0 ]]; then exit 1; fi
41+
3642
# Can it be safely run again (as a noop)?
3743
ivy-ngcc
3844

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import * as ts from 'typescript';
10+
11+
/**
12+
* A bundle represents the currently compiled entry point format, containing
13+
* information that is necessary for compiling @angular/core with ngcc.
14+
*/
15+
export interface BundleInfo {
16+
isCore: boolean;
17+
isFlat: boolean;
18+
rewriteCoreImportsTo: ts.SourceFile|null;
19+
rewriteCoreDtsImportsTo: ts.SourceFile|null;
20+
}
21+
22+
export function createBundleInfo(
23+
isCore: boolean, rewriteCoreImportsTo: ts.SourceFile | null,
24+
rewriteCoreDtsImportsTo: ts.SourceFile | null): BundleInfo {
25+
return {
26+
isCore,
27+
isFlat: rewriteCoreImportsTo === null,
28+
rewriteCoreImportsTo: rewriteCoreImportsTo,
29+
rewriteCoreDtsImportsTo: rewriteCoreDtsImportsTo,
30+
};
31+
}

packages/compiler-cli/src/ngcc/src/packages/transformer.ts

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {EsmRenderer} from '../rendering/esm_renderer';
2020
import {FileInfo, Renderer} from '../rendering/renderer';
2121

2222
import {checkMarkerFile, writeMarkerFile} from './build_marker';
23+
import {BundleInfo, createBundleInfo} from './bundle';
2324
import {EntryPoint, EntryPointFormat} from './entry_point';
2425

2526
/**
@@ -70,27 +71,40 @@ export class Transformer {
7071
const host = ts.createCompilerHost(options);
7172
const rootDirs = this.getRootDirs(host, options);
7273
const isCore = entryPoint.name === '@angular/core';
73-
const r3SymbolsPath = isCore ? this.findR3SymbolsPath(dirname(entryPointFilePath)) : null;
74+
const r3SymbolsPath =
75+
isCore ? this.findR3SymbolsPath(dirname(entryPointFilePath), 'r3_symbols.js') : null;
7476
const rootPaths = r3SymbolsPath ? [entryPointFilePath, r3SymbolsPath] : [entryPointFilePath];
7577
const packageProgram = ts.createProgram(rootPaths, options, host);
76-
console.time(entryPoint.name + '(dtsmappper creation)');
78+
const r3SymbolsFile = r3SymbolsPath && packageProgram.getSourceFile(r3SymbolsPath) || null;
79+
80+
// Create the program for processing DTS files if enabled for this format.
7781
const dtsFilePath = entryPoint.typings;
78-
const dtsProgram = transformDts ? ts.createProgram([entryPoint.typings], options, host) : null;
79-
console.timeEnd(entryPoint.name + '(dtsmappper creation)');
82+
let dtsProgram: ts.Program|null = null;
83+
let r3SymbolsDtsFile: ts.SourceFile|null = null;
84+
if (transformDts) {
85+
console.time(`${entryPoint.name} (dtsMapper creation)`);
86+
const r3SymbolsDtsPath =
87+
isCore ? this.findR3SymbolsPath(dirname(dtsFilePath), 'r3_symbols.d.ts') : null;
88+
const rootDtsPaths = r3SymbolsDtsPath ? [dtsFilePath, r3SymbolsDtsPath] : [dtsFilePath];
89+
90+
dtsProgram = ts.createProgram(rootDtsPaths, options, host);
91+
r3SymbolsDtsFile = r3SymbolsDtsPath && dtsProgram.getSourceFile(r3SymbolsDtsPath) || null;
92+
console.timeEnd(`${entryPoint.name} (dtsMapper creation)`);
93+
}
94+
95+
const bundle = createBundleInfo(isCore, r3SymbolsFile, r3SymbolsDtsFile);
8096
const reflectionHost = this.getHost(isCore, format, packageProgram, dtsFilePath, dtsProgram);
81-
const r3SymbolsFile = r3SymbolsPath && packageProgram.getSourceFile(r3SymbolsPath) || null;
8297

8398
// Parse and analyze the files.
8499
const {decorationAnalyses, switchMarkerAnalyses} =
85100
this.analyzeProgram(packageProgram, reflectionHost, rootDirs, isCore);
86101

87-
console.time(entryPoint.name + '(rendering)');
102+
console.time(`${entryPoint.name} (rendering)`);
88103
// Transform the source files and source maps.
89-
const renderer = this.getRenderer(
90-
format, packageProgram, reflectionHost, isCore, r3SymbolsFile, transformDts);
104+
const renderer = this.getRenderer(format, packageProgram, reflectionHost, bundle, transformDts);
91105
const renderedFiles =
92106
renderer.renderProgram(packageProgram, decorationAnalyses, switchMarkerAnalyses);
93-
console.timeEnd(entryPoint.name + '(rendering)');
107+
console.timeEnd(`${entryPoint.name} (rendering)`);
94108

95109
// Write out all the transformed files.
96110
renderedFiles.forEach(file => this.writeFile(file));
@@ -125,17 +139,15 @@ export class Transformer {
125139
}
126140

127141
getRenderer(
128-
format: string, program: ts.Program, host: NgccReflectionHost, isCore: boolean,
129-
rewriteCoreImportsTo: ts.SourceFile|null, transformDts: boolean): Renderer {
142+
format: string, program: ts.Program, host: NgccReflectionHost, bundle: BundleInfo,
143+
transformDts: boolean): Renderer {
130144
switch (format) {
131145
case 'esm2015':
132146
case 'fesm2015':
133-
return new EsmRenderer(
134-
host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath, transformDts);
147+
return new EsmRenderer(host, bundle, this.sourcePath, this.targetPath, transformDts);
135148
case 'esm5':
136149
case 'fesm5':
137-
return new Esm5Renderer(
138-
host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath, transformDts);
150+
return new Esm5Renderer(host, bundle, this.sourcePath, this.targetPath, transformDts);
139151
default:
140152
throw new Error(`Renderer for "${format}" not yet implemented.`);
141153
}
@@ -162,8 +174,8 @@ export class Transformer {
162174
writeFileSync(file.path, file.contents, 'utf8');
163175
}
164176

165-
findR3SymbolsPath(directory: string): string|null {
166-
const r3SymbolsFilePath = resolve(directory, 'r3_symbols.js');
177+
findR3SymbolsPath(directory: string, fileName: string): string|null {
178+
const r3SymbolsFilePath = resolve(directory, fileName);
167179
if (existsSync(r3SymbolsFilePath)) {
168180
return r3SymbolsFilePath;
169181
}
@@ -181,7 +193,7 @@ export class Transformer {
181193
});
182194

183195
for (const subDirectory of subDirectories) {
184-
const r3SymbolsFilePath = this.findR3SymbolsPath(resolve(directory, subDirectory));
196+
const r3SymbolsFilePath = this.findR3SymbolsPath(resolve(directory, subDirectory), fileName);
185197
if (r3SymbolsFilePath) {
186198
return r3SymbolsFilePath;
187199
}

packages/compiler-cli/src/ngcc/src/rendering/esm5_renderer.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import * as ts from 'typescript';
99
import MagicString from 'magic-string';
1010
import {NgccReflectionHost} from '../host/ngcc_host';
1111
import {CompiledClass} from '../analysis/decoration_analyzer';
12+
import {BundleInfo} from '../packages/bundle';
1213
import {EsmRenderer} from './esm_renderer';
1314

1415
export class Esm5Renderer extends EsmRenderer {
1516
constructor(
16-
protected host: NgccReflectionHost, protected isCore: boolean,
17-
protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string,
18-
protected targetPath: string, transformDts: boolean) {
19-
super(host, isCore, rewriteCoreImportsTo, sourcePath, targetPath, transformDts);
17+
protected host: NgccReflectionHost, protected bundle: BundleInfo,
18+
protected sourcePath: string, protected targetPath: string, transformDts: boolean) {
19+
super(host, bundle, sourcePath, targetPath, transformDts);
2020
}
2121

2222
/**

packages/compiler-cli/src/ngcc/src/rendering/esm_renderer.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import * as ts from 'typescript';
99
import MagicString from 'magic-string';
1010
import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host';
1111
import {CompiledClass} from '../analysis/decoration_analyzer';
12+
import {BundleInfo} from '../packages/bundle';
1213
import {Renderer} from './renderer';
1314

1415
export class EsmRenderer extends Renderer {
1516
constructor(
16-
protected host: NgccReflectionHost, protected isCore: boolean,
17-
protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string,
18-
protected targetPath: string, transformDts: boolean) {
19-
super(host, isCore, rewriteCoreImportsTo, sourcePath, targetPath, transformDts);
17+
protected host: NgccReflectionHost, protected bundle: BundleInfo,
18+
protected sourcePath: string, protected targetPath: string, transformDts: boolean) {
19+
super(host, bundle, sourcePath, targetPath, transformDts);
2020
}
2121

2222
/**

packages/compiler-cli/src/ngcc/src/rendering/renderer.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {translateStatement, translateType} from '../../../ngtsc/translator';
1919
import {NgccImportManager} from './ngcc_import_manager';
2020
import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/decoration_analyzer';
2121
import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer';
22+
import {BundleInfo} from '../packages/bundle';
2223
import {IMPORT_PREFIX} from '../constants';
2324
import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host';
2425

@@ -55,9 +56,9 @@ interface DtsClassInfo {
5556
*/
5657
export abstract class Renderer {
5758
constructor(
58-
protected host: NgccReflectionHost, protected isCore: boolean,
59-
protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string,
60-
protected targetPath: string, protected transformDts: boolean) {}
59+
protected host: NgccReflectionHost, protected bundle: BundleInfo,
60+
protected sourcePath: string, protected targetPath: string, protected transformDts: boolean) {
61+
}
6162

6263
renderProgram(
6364
program: ts.Program, decorationAnalyses: DecorationAnalyses,
@@ -101,7 +102,7 @@ export abstract class Renderer {
101102

102103
if (compiledFile) {
103104
const importManager =
104-
new NgccImportManager(!this.rewriteCoreImportsTo, this.isCore, IMPORT_PREFIX);
105+
new NgccImportManager(this.bundle.isFlat, this.bundle.isCore, IMPORT_PREFIX);
105106
const decoratorsToRemove = new Map<ts.Node, ts.Node[]>();
106107

107108
compiledFile.compiledClasses.forEach(clazz => {
@@ -116,8 +117,8 @@ export abstract class Renderer {
116117
compiledFile.sourceFile);
117118

118119
this.addImports(
119-
outputText,
120-
importManager.getAllImports(compiledFile.sourceFile.fileName, this.rewriteCoreImportsTo));
120+
outputText, importManager.getAllImports(
121+
compiledFile.sourceFile.fileName, this.bundle.rewriteCoreImportsTo));
121122

122123
// TODO: remove contructor param metadata and property decorators (we need info from the
123124
// handlers to do this)
@@ -130,7 +131,7 @@ export abstract class Renderer {
130131
renderDtsFile(dtsFile: ts.SourceFile, dtsClasses: DtsClassInfo[]): FileInfo[] {
131132
const input = this.extractSourceMap(dtsFile);
132133
const outputText = new MagicString(input.source);
133-
const importManager = new NgccImportManager(false, this.isCore, IMPORT_PREFIX);
134+
const importManager = new NgccImportManager(false, this.bundle.isCore, IMPORT_PREFIX);
134135

135136
dtsClasses.forEach(dtsClass => {
136137
const endOfClass = dtsClass.dtsDeclaration.getEnd();
@@ -142,7 +143,8 @@ export abstract class Renderer {
142143
});
143144

144145
this.addImports(
145-
outputText, importManager.getAllImports(dtsFile.fileName, this.rewriteCoreImportsTo));
146+
outputText,
147+
importManager.getAllImports(dtsFile.fileName, this.bundle.rewriteCoreDtsImportsTo));
146148

147149
return this.renderSourceAndMap(dtsFile, input, outputText);
148150
}

packages/compiler-cli/src/ngcc/test/rendering/esm2015_renderer_spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import MagicString from 'magic-string';
1212
import {makeProgram} from '../helpers/utils';
1313
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
1414
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
15+
import {createBundleInfo} from '../../src/packages/bundle';
1516
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
1617
import {EsmRenderer} from '../../src/rendering/esm_renderer';
1718

@@ -23,7 +24,8 @@ function setup(file: {name: string, contents: string}, transformDts: boolean = f
2324
const decorationAnalyses =
2425
new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program);
2526
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
26-
const renderer = new EsmRenderer(host, false, null, dir, dir, false);
27+
const bundle = createBundleInfo(false, null, null);
28+
const renderer = new EsmRenderer(host, bundle, dir, dir, false);
2729
return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses};
2830
}
2931

packages/compiler-cli/src/ngcc/test/rendering/esm5_renderer_spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import MagicString from 'magic-string';
1010
import {makeProgram, getDeclaration} from '../helpers/utils';
1111
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
1212
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
13+
import {createBundleInfo} from '../../src/packages/bundle';
1314
import {Esm5ReflectionHost} from '../../src/host/esm5_host';
1415
import {Esm5Renderer} from '../../src/rendering/esm5_renderer';
1516

@@ -20,7 +21,8 @@ function setup(file: {name: string, contents: string}) {
2021
const decorationAnalyses =
2122
new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program);
2223
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
23-
const renderer = new Esm5Renderer(host, false, null, '', '', false);
24+
const bundle = createBundleInfo(false, null, null);
25+
const renderer = new Esm5Renderer(host, bundle, '', '', false);
2426
return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses};
2527
}
2628

packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import {fromObject, generateMapFileComment} from 'convert-source-map';
1313
import {makeProgram} from '../helpers/utils';
1414
import {CompiledClass, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
1515
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
16+
import {BundleInfo, createBundleInfo} from '../../src/packages/bundle';
1617
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
1718
import {Renderer} from '../../src/rendering/renderer';
1819

1920
class TestRenderer extends Renderer {
20-
constructor(
21-
host: Esm2015ReflectionHost, isCore: boolean, rewriteCoreImportsTo: ts.SourceFile|null) {
22-
super(host, isCore, rewriteCoreImportsTo, '/src', '/dist', false);
21+
constructor(host: Esm2015ReflectionHost, bundle: BundleInfo) {
22+
super(host, bundle, '/src', '/dist', false);
2323
}
2424
addImports(output: MagicString, imports: {name: string, as: string}[]) {
2525
output.prepend('\n// ADD IMPORTS\n');
@@ -42,14 +42,15 @@ function createTestRenderer(
4242
files: {name: string, contents: string}[],
4343
options: {isCore?: boolean, rewriteCoreImportsTo?: string} = {}) {
4444
const program = makeProgram(...files);
45-
const host = new Esm2015ReflectionHost(options.isCore || false, program.getTypeChecker());
45+
const rewriteCoreImportsTo =
46+
options.rewriteCoreImportsTo ? program.getSourceFile(options.rewriteCoreImportsTo) ! : null;
47+
const bundle = createBundleInfo(options.isCore || false, rewriteCoreImportsTo, null);
48+
const host = new Esm2015ReflectionHost(bundle.isCore, program.getTypeChecker());
4649
const decorationAnalyses =
47-
new DecorationAnalyzer(program.getTypeChecker(), host, [''], options.isCore || false)
50+
new DecorationAnalyzer(program.getTypeChecker(), host, [''], bundle.isCore)
4851
.analyzeProgram(program);
4952
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
50-
const rewriteCoreImportsTo =
51-
options.rewriteCoreImportsTo ? program.getSourceFile(options.rewriteCoreImportsTo) ! : null;
52-
const renderer = new TestRenderer(host, options.isCore || false, rewriteCoreImportsTo);
53+
const renderer = new TestRenderer(host, bundle);
5354
spyOn(renderer, 'addImports').and.callThrough();
5455
spyOn(renderer, 'addDefinitions').and.callThrough();
5556
spyOn(renderer, 'removeDecorators').and.callThrough();

0 commit comments

Comments
 (0)