perf(compiler): only type check input files when using bazel (#19581)

This helps hazel as it does not check libraries (e.g. the default lib) which are
not input files, but still checks `.d.ts` files that are inputs.

PR Close #19581
This commit is contained in:
Tobias Bosch 2017-10-05 13:48:40 -07:00 committed by Chuck Jazdzewski
parent 03227e65cf
commit 0b06ea177a
2 changed files with 55 additions and 16 deletions

View File

@ -78,8 +78,9 @@ export function compile({allowNonHermeticReads, compilerOpts, tsHost, bazelOpts,
expectedOuts: string[], gatherDiagnostics?: (program: ng.Program) => ng.Diagnostics expectedOuts: string[], gatherDiagnostics?: (program: ng.Program) => ng.Diagnostics
}): {diagnostics: ng.Diagnostics, program: ng.Program} { }): {diagnostics: ng.Diagnostics, program: ng.Program} {
let fileLoader: FileLoader; let fileLoader: FileLoader;
if (inputs) { if (inputs) {
fileLoader = new CachedFileLoader(fileCache, ALLOW_NON_HERMETIC_READS); fileLoader = new CachedFileLoader(fileCache, allowNonHermeticReads);
// Resolve the inputs to absolute paths to match TypeScript internals // Resolve the inputs to absolute paths to match TypeScript internals
const resolvedInputs: {[path: string]: string} = {}; const resolvedInputs: {[path: string]: string} = {};
for (const key of Object.keys(inputs)) { for (const key of Object.keys(inputs)) {
@ -141,10 +142,8 @@ export function compile({allowNonHermeticReads, compilerOpts, tsHost, bazelOpts,
moduleName, containingFile, compilerOptions, generatedFileModuleResolverHost); moduleName, containingFile, compilerOptions, generatedFileModuleResolverHost);
} }
// TODO(alexeagle): does this also work in third_party?
const allowNonHermeticRead = false;
const bazelHost = new CompilerHost( const bazelHost = new CompilerHost(
files, compilerOpts, bazelOpts, tsHost, fileLoader, ALLOW_NON_HERMETIC_READS, files, compilerOpts, bazelOpts, tsHost, fileLoader, allowNonHermeticReads,
generatedFileModuleResolver); generatedFileModuleResolver);
const origBazelHostFileExist = bazelHost.fileExists; const origBazelHostFileExist = bazelHost.fileExists;
bazelHost.fileExists = (fileName: string) => { bazelHost.fileExists = (fileName: string) => {
@ -179,6 +178,10 @@ export function compile({allowNonHermeticReads, compilerOpts, tsHost, bazelOpts,
], ],
}); });
if (!gatherDiagnostics) {
gatherDiagnostics = (program) =>
gatherDiagnosticsForInputsOnly(compilerOpts, bazelOpts, program);
}
const {diagnostics, emitResult, program} = ng.performCompilation( const {diagnostics, emitResult, program} = ng.performCompilation(
{rootNames: files, options: compilerOpts, host: ngHost, emitCallback, gatherDiagnostics}); {rootNames: files, options: compilerOpts, host: ngHost, emitCallback, gatherDiagnostics});
const tsickleEmitResult = emitResult as tsickle.EmitResult; const tsickleEmitResult = emitResult as tsickle.EmitResult;
@ -209,6 +212,36 @@ export function compile({allowNonHermeticReads, compilerOpts, tsHost, bazelOpts,
return {program, diagnostics}; return {program, diagnostics};
} }
function isCompilationTarget(bazelOpts: BazelOptions, sf: ts.SourceFile): boolean {
return !NGC_GEN_FILES.test(sf.fileName) &&
(bazelOpts.compilationTargetSrc.indexOf(sf.fileName) !== -1);
}
function gatherDiagnosticsForInputsOnly(
options: ng.CompilerOptions, bazelOpts: BazelOptions,
ngProgram: ng.Program): (ng.Diagnostic | ts.Diagnostic)[] {
const tsProgram = ngProgram.getTsProgram();
const diagnostics: (ng.Diagnostic | ts.Diagnostic)[] = [];
// These checks mirror ts.getPreEmitDiagnostics, with the important
// exception of avoiding b/30708240, which is that if you call
// program.getDeclarationDiagnostics() it somehow corrupts the emit.
diagnostics.push(...tsProgram.getOptionsDiagnostics());
diagnostics.push(...tsProgram.getGlobalDiagnostics());
for (const sf of tsProgram.getSourceFiles().filter(f => isCompilationTarget(bazelOpts, f))) {
// Note: We only get the diagnostics for individual files
// to e.g. not check libraries.
diagnostics.push(...tsProgram.getSyntacticDiagnostics(sf));
diagnostics.push(...tsProgram.getSemanticDiagnostics(sf));
}
if (!diagnostics.length) {
// only gather the angular diagnostics if we have no diagnostics
// in any other files.
diagnostics.push(...ngProgram.getNgStructuralDiagnostics());
diagnostics.push(...ngProgram.getNgSemanticDiagnostics());
}
return diagnostics;
}
if (require.main === module) { if (require.main === module) {
process.exitCode = main(process.argv.slice(2)); process.exitCode = main(process.argv.slice(2));
} }

View File

@ -56,7 +56,6 @@ class AngularCompilerProgram implements Program {
private _analyzedModules: NgAnalyzedModules|undefined; private _analyzedModules: NgAnalyzedModules|undefined;
private _structuralDiagnostics: Diagnostic[]|undefined; private _structuralDiagnostics: Diagnostic[]|undefined;
private _programWithStubs: ts.Program|undefined; private _programWithStubs: ts.Program|undefined;
private _semanticDiagnostics: {ts: ts.Diagnostic[], ng: Diagnostic[]}|undefined;
private _optionsDiagnostics: Diagnostic[] = []; private _optionsDiagnostics: Diagnostic[] = [];
constructor( constructor(
@ -148,12 +147,28 @@ class AngularCompilerProgram implements Program {
getTsSemanticDiagnostics(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken): getTsSemanticDiagnostics(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken):
ts.Diagnostic[] { ts.Diagnostic[] {
return this.semanticDiagnostics.ts; if (sourceFile) {
return this.tsProgram.getSemanticDiagnostics(sourceFile, cancellationToken);
}
let diags: ts.Diagnostic[] = [];
this.tsProgram.getSourceFiles().forEach(sf => {
if (!GENERATED_FILES.test(sf.fileName)) {
diags.push(...this.tsProgram.getSemanticDiagnostics(sf, cancellationToken));
}
});
return diags;
} }
getNgSemanticDiagnostics(fileName?: string, cancellationToken?: ts.CancellationToken): getNgSemanticDiagnostics(fileName?: string, cancellationToken?: ts.CancellationToken):
Diagnostic[] { Diagnostic[] {
return this.semanticDiagnostics.ng; let diags: ts.Diagnostic[] = [];
this.tsProgram.getSourceFiles().forEach(sf => {
if (GENERATED_FILES.test(sf.fileName) && !sf.isDeclarationFile) {
diags.push(...this.tsProgram.getSemanticDiagnostics(sf, cancellationToken));
}
});
const {ng} = translateDiagnostics(this.typeCheckHost, diags);
return ng;
} }
loadNgStructureAsync(): Promise<void> { loadNgStructureAsync(): Promise<void> {
@ -359,11 +374,6 @@ class AngularCompilerProgram implements Program {
return this._typeCheckHost !; return this._typeCheckHost !;
} }
private get semanticDiagnostics(): {ts: ts.Diagnostic[], ng: Diagnostic[]} {
return this._semanticDiagnostics ||
(this._semanticDiagnostics = this.generateSemanticDiagnostics());
}
private calculateTransforms( private calculateTransforms(
genFiles: Map<string, GeneratedFile>, genFiles: Map<string, GeneratedFile>,
customTransformers?: CustomTransformers): ts.CustomTransformers { customTransformers?: CustomTransformers): ts.CustomTransformers {
@ -546,10 +556,6 @@ class AngularCompilerProgram implements Program {
return sourceFilesToEmit; return sourceFilesToEmit;
} }
private generateSemanticDiagnostics(): {ts: ts.Diagnostic[], ng: Diagnostic[]} {
return translateDiagnostics(this.typeCheckHost, this.tsProgram.getSemanticDiagnostics());
}
private writeFile( private writeFile(
outFileName: string, outData: string, writeByteOrderMark: boolean, outFileName: string, outData: string, writeByteOrderMark: boolean,
onError?: (message: string) => void, genFile?: GeneratedFile, sourceFiles?: ts.SourceFile[]) { onError?: (message: string) => void, genFile?: GeneratedFile, sourceFiles?: ts.SourceFile[]) {