Skip to content

Commit c76da27

Browse files
tboschIgorMinar
authored andcommitted
fix(compiler): support noResolve (#19301)
PR Close #19301
1 parent 04997c8 commit c76da27

File tree

2 files changed

+62
-16
lines changed

2 files changed

+62
-16
lines changed

packages/compiler-cli/src/transformers/program.ts

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Serializer, StubEmitFlags, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isSyntaxError} from '@angular/compiler';
9+
import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Serializer, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isSyntaxError} from '@angular/compiler';
1010
import * as fs from 'fs';
1111
import * as path from 'path';
1212
import * as ts from 'typescript';
@@ -63,7 +63,6 @@ class AngularCompilerProgram implements Program {
6363
({content, fileName}) => this.summariesFromPreviousCompilations.set(fileName, content));
6464
}
6565

66-
this.rootNames = rootNames = rootNames.filter(r => !GENERATED_FILES.test(r));
6766
if (options.flatModuleOutFile) {
6867
const {host: bundleHost, indexName, errors} = createBundleIndexHost(options, rootNames, host);
6968
if (errors) {
@@ -133,14 +132,15 @@ class AngularCompilerProgram implements Program {
133132
if (this._analyzedModules) {
134133
throw new Error('Angular structure already loaded');
135134
}
136-
const {tmpProgram, analyzedFiles, hostAdapter} = this._createProgramWithBasicStubs();
135+
const {tmpProgram, analyzedFiles, hostAdapter, rootNames} = this._createProgramWithBasicStubs();
137136
return this._compiler.loadFilesAsync(analyzedFiles)
138137
.catch(this.catchAnalysisError.bind(this))
139138
.then(analyzedModules => {
140139
if (this._analyzedModules) {
141140
throw new Error('Angular structure loaded both synchronously and asynchronsly');
142141
}
143-
this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, hostAdapter);
142+
this._updateProgramWithTypeCheckStubs(
143+
tmpProgram, analyzedModules, hostAdapter, rootNames);
144144
});
145145
}
146146

@@ -177,7 +177,7 @@ class AngularCompilerProgram implements Program {
177177
program: this.tsProgram,
178178
host: this.host,
179179
options: this.options,
180-
writeFile: createWriteFileCallback(emitFlags, this.host, outSrcMapping),
180+
writeFile: createWriteFileCallback(genFiles, this.host, outSrcMapping),
181181
emitOnlyDtsFiles: (emitFlags & (EmitFlags.DTS | EmitFlags.JS)) == EmitFlags.DTS,
182182
customTransformers: this.calculateTransforms(genFiles, customTransformers)
183183
});
@@ -291,20 +291,21 @@ class AngularCompilerProgram implements Program {
291291
if (this._analyzedModules) {
292292
return;
293293
}
294-
const {tmpProgram, analyzedFiles, hostAdapter} = this._createProgramWithBasicStubs();
294+
const {tmpProgram, analyzedFiles, hostAdapter, rootNames} = this._createProgramWithBasicStubs();
295295
let analyzedModules: NgAnalyzedModules;
296296
try {
297297
analyzedModules = this._compiler.loadFilesSync(analyzedFiles);
298298
} catch (e) {
299299
analyzedModules = this.catchAnalysisError(e);
300300
}
301-
this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, hostAdapter);
301+
this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, hostAdapter, rootNames);
302302
}
303303

304304
private _createProgramWithBasicStubs(): {
305305
tmpProgram: ts.Program,
306306
analyzedFiles: NgAnalyzedFile[],
307-
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter
307+
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter,
308+
rootNames: string[],
308309
} {
309310
if (this._analyzedModules) {
310311
throw new Error(`Internal Error: already initalized!`);
@@ -330,17 +331,31 @@ class AngularCompilerProgram implements Program {
330331
this._typeCheckHost = hostAdapter;
331332
this._structuralDiagnostics = [];
332333

333-
const tmpProgram = ts.createProgram(this.rootNames, this.options, hostAdapter, oldTsProgram);
334-
return {tmpProgram, analyzedFiles, hostAdapter};
334+
let rootNames =
335+
this.rootNames.filter(fn => !GENERATED_FILES.test(fn) || !hostAdapter.isSourceFile(fn));
336+
if (this.options.noResolve) {
337+
this.rootNames.forEach(rootName => {
338+
const sf =
339+
hostAdapter.getSourceFile(rootName, this.options.target || ts.ScriptTarget.Latest);
340+
sf.referencedFiles.forEach((fileRef) => {
341+
if (GENERATED_FILES.test(fileRef.fileName)) {
342+
rootNames.push(fileRef.fileName);
343+
}
344+
});
345+
});
346+
}
347+
348+
const tmpProgram = ts.createProgram(rootNames, this.options, hostAdapter, oldTsProgram);
349+
return {tmpProgram, analyzedFiles, hostAdapter, rootNames};
335350
}
336351

337352
private _updateProgramWithTypeCheckStubs(
338353
tmpProgram: ts.Program, analyzedModules: NgAnalyzedModules,
339-
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter) {
354+
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter, rootNames: string[]) {
340355
this._analyzedModules = analyzedModules;
341356
const genFiles = this._compiler.emitTypeCheckStubs(analyzedModules);
342357
genFiles.forEach(gf => hostAdapter.updateGeneratedFile(gf));
343-
this._tsProgram = ts.createProgram(this.rootNames, this.options, hostAdapter, tmpProgram);
358+
this._tsProgram = ts.createProgram(rootNames, this.options, hostAdapter, tmpProgram);
344359
// Note: the new ts program should be completely reusable by TypeScript as:
345360
// - we cache all the files in the hostAdapter
346361
// - new new stubs use the exactly same imports/exports as the old once (we assert that in
@@ -453,17 +468,24 @@ function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions {
453468
}
454469

455470
function createWriteFileCallback(
456-
emitFlags: EmitFlags, host: ts.CompilerHost,
471+
generatedFiles: GeneratedFile[], host: ts.CompilerHost,
457472
outSrcMapping: Array<{sourceFile: ts.SourceFile, outFileName: string}>) {
473+
const genFileByFileName = new Map<string, GeneratedFile>();
474+
generatedFiles.forEach(genFile => genFileByFileName.set(genFile.genFileUrl, genFile));
458475
return (fileName: string, data: string, writeByteOrderMark: boolean,
459476
onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => {
460477
const sourceFile = sourceFiles && sourceFiles.length == 1 ? sourceFiles[0] : null;
461-
const isGenerated = GENERATED_FILES.test(fileName);
462478
if (sourceFile) {
463479
outSrcMapping.push({outFileName: fileName, sourceFile});
464480
}
465-
if (isGenerated && !(emitFlags & EmitFlags.Codegen)) {
466-
return;
481+
const isGenerated = GENERATED_FILES.test(fileName);
482+
if (isGenerated && sourceFile) {
483+
// Filter out generated files for which we didn't generate code.
484+
// This can happen as the stub caclulation is not completely exact.
485+
const genFile = genFileByFileName.get(sourceFile.fileName);
486+
if (!genFile || !genFile.stmts || genFile.stmts.length === 0) {
487+
return;
488+
}
467489
}
468490
host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles);
469491
};

packages/compiler-cli/test/transformers/program_spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,28 @@ describe('ng program', () => {
208208
done();
209209
});
210210
});
211+
212+
it('should work with noResolve', () => {
213+
// create a temporary ts program to get the list of all files from angular...
214+
testSupport.writeFiles({
215+
'src/main.ts': createModuleAndCompSource('main'),
216+
});
217+
const preOptions = testSupport.createCompilerOptions();
218+
const preHost = ts.createCompilerHost(preOptions);
219+
// don't resolve symlinks
220+
preHost.realpath = (f) => f;
221+
const preProgram =
222+
ts.createProgram([path.resolve(testSupport.basePath, 'src/main.ts')], preOptions, preHost);
223+
const allRootNames = preProgram.getSourceFiles().map(sf => sf.fileName);
224+
225+
// now do the actual test with noResolve
226+
const options = testSupport.createCompilerOptions({noResolve: true});
227+
const host = ng.createCompilerHost({options});
228+
const program = ng.createProgram({rootNames: allRootNames, options, host});
229+
expectNoDiagnosticsInProgram(options, program);
230+
program.emit();
231+
232+
testSupport.shouldExist('built/src/main.ngfactory.js');
233+
testSupport.shouldExist('built/src/main.ngfactory.d.ts');
234+
});
211235
});

0 commit comments

Comments
 (0)