fix(compiler): report errors properly in G3 in certain conditions (#20041)
Condition: static analysis error, given: - noResolve:true - generateCodeForLibraries: false - CompilerHost.getSourceFile throws on non existent files All of these are true in G3. PR Close #20041
This commit is contained in:
parent
951bd33b09
commit
54480f7dfc
|
@ -456,13 +456,13 @@ class AngularCompilerProgram implements Program {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let rootNames = this.rootNames;
|
let rootNames = [...this.rootNames];
|
||||||
if (this.options.generateCodeForLibraries !== false) {
|
if (this.options.generateCodeForLibraries !== false) {
|
||||||
// if we should generateCodeForLibraries, never include
|
// if we should generateCodeForLibraries, never include
|
||||||
// generated files in the program as otherwise we will
|
// generated files in the program as otherwise we will
|
||||||
// ovewrite them and typescript will report the error
|
// ovewrite them and typescript will report the error
|
||||||
// TS5055: Cannot write file ... because it would overwrite input file.
|
// TS5055: Cannot write file ... because it would overwrite input file.
|
||||||
rootNames = this.rootNames.filter(fn => !GENERATED_FILES.test(fn));
|
rootNames = rootNames.filter(fn => !GENERATED_FILES.test(fn));
|
||||||
}
|
}
|
||||||
if (this.options.noResolve) {
|
if (this.options.noResolve) {
|
||||||
this.rootNames.forEach(rootName => {
|
this.rootNames.forEach(rootName => {
|
||||||
|
|
|
@ -78,6 +78,15 @@ describe('ng program', () => {
|
||||||
return {emitResult, program};
|
return {emitResult, program};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveFiles(rootNames: string[]) {
|
||||||
|
const preOptions = testSupport.createCompilerOptions();
|
||||||
|
const preHost = ts.createCompilerHost(preOptions);
|
||||||
|
// don't resolve symlinks
|
||||||
|
preHost.realpath = (f) => f;
|
||||||
|
const preProgram = ts.createProgram(rootNames, preOptions, preHost);
|
||||||
|
return preProgram.getSourceFiles().map(sf => sf.fileName);
|
||||||
|
}
|
||||||
|
|
||||||
describe('reuse of old program', () => {
|
describe('reuse of old program', () => {
|
||||||
it('should reuse generated code for libraries from old programs', () => {
|
it('should reuse generated code for libraries from old programs', () => {
|
||||||
compileLib('lib');
|
compileLib('lib');
|
||||||
|
@ -373,13 +382,7 @@ describe('ng program', () => {
|
||||||
testSupport.writeFiles({
|
testSupport.writeFiles({
|
||||||
'src/main.ts': createModuleAndCompSource('main'),
|
'src/main.ts': createModuleAndCompSource('main'),
|
||||||
});
|
});
|
||||||
const preOptions = testSupport.createCompilerOptions();
|
const allRootNames = resolveFiles([path.resolve(testSupport.basePath, 'src/main.ts')]);
|
||||||
const preHost = ts.createCompilerHost(preOptions);
|
|
||||||
// don't resolve symlinks
|
|
||||||
preHost.realpath = (f) => f;
|
|
||||||
const preProgram =
|
|
||||||
ts.createProgram([path.resolve(testSupport.basePath, 'src/main.ts')], preOptions, preHost);
|
|
||||||
const allRootNames = preProgram.getSourceFiles().map(sf => sf.fileName);
|
|
||||||
|
|
||||||
// now do the actual test with noResolve
|
// now do the actual test with noResolve
|
||||||
const program = compile(undefined, {noResolve: true}, allRootNames);
|
const program = compile(undefined, {noResolve: true}, allRootNames);
|
||||||
|
@ -932,23 +935,41 @@ describe('ng program', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to use a program with structural errors as oldProgram', () => {
|
it('should be able report structural errors with noResolve:true and generateCodeForLibraries:false ' +
|
||||||
testSupport.write('src/index.ts', fileWithStructuralError);
|
'even if getSourceFile throws for non existent files',
|
||||||
|
() => {
|
||||||
|
testSupport.write('src/index.ts', fileWithGoodContent);
|
||||||
|
|
||||||
const options = testSupport.createCompilerOptions();
|
// compile angular and produce .ngsummary.json / ngfactory.d.ts files
|
||||||
const host = ng.createCompilerHost({options});
|
compile();
|
||||||
const program1 = ng.createProgram(
|
|
||||||
{rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')], options, host});
|
|
||||||
expect(program1.getNgStructuralDiagnostics().length).toBe(1);
|
|
||||||
|
|
||||||
testSupport.write('src/index.ts', fileWithGoodContent);
|
testSupport.write('src/ok.ts', fileWithGoodContent);
|
||||||
const program2 = ng.createProgram({
|
testSupport.write('src/error.ts', fileWithStructuralError);
|
||||||
rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')],
|
|
||||||
options,
|
// Make sure the ok.ts file is before the error.ts file,
|
||||||
host,
|
// so we added a .ngfactory.ts file for it.
|
||||||
oldProgram: program1
|
const allRootNames = resolveFiles(
|
||||||
});
|
['src/ok.ts', 'src/error.ts'].map(fn => path.resolve(testSupport.basePath, fn)));
|
||||||
expectNoDiagnosticsInProgram(options, program2);
|
|
||||||
});
|
const options = testSupport.createCompilerOptions({
|
||||||
|
noResolve: true,
|
||||||
|
generateCodeForLibraries: false,
|
||||||
|
});
|
||||||
|
const host = ng.createCompilerHost({options});
|
||||||
|
const originalGetSourceFile = host.getSourceFile;
|
||||||
|
host.getSourceFile =
|
||||||
|
(fileName: string, languageVersion: ts.ScriptTarget,
|
||||||
|
onError?: ((message: string) => void) | undefined): ts.SourceFile => {
|
||||||
|
// We should never try to load .ngfactory.ts files
|
||||||
|
if (fileName.match(/\.ngfactory\.ts$/)) {
|
||||||
|
throw new Error(`Non existent ngfactory file: ` + fileName);
|
||||||
|
}
|
||||||
|
return originalGetSourceFile.call(host, fileName, languageVersion, onError);
|
||||||
|
};
|
||||||
|
const program = ng.createProgram({rootNames: allRootNames, options, host});
|
||||||
|
const structuralErrors = program.getNgStructuralDiagnostics();
|
||||||
|
expect(structuralErrors.length).toBe(1);
|
||||||
|
expect(structuralErrors[0].messageText).toContain('Function calls are not supported.');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue