diff --git a/packages/bazel/src/ngc-wrapped/index.ts b/packages/bazel/src/ngc-wrapped/index.ts index bf605271c1..85db0169d1 100644 --- a/packages/bazel/src/ngc-wrapped/index.ts +++ b/packages/bazel/src/ngc-wrapped/index.ts @@ -78,8 +78,9 @@ export function compile({allowNonHermeticReads, compilerOpts, tsHost, bazelOpts, expectedOuts: string[], gatherDiagnostics?: (program: ng.Program) => ng.Diagnostics }): {diagnostics: ng.Diagnostics, program: ng.Program} { let fileLoader: FileLoader; + 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 const resolvedInputs: {[path: string]: string} = {}; for (const key of Object.keys(inputs)) { @@ -141,10 +142,8 @@ export function compile({allowNonHermeticReads, compilerOpts, tsHost, bazelOpts, moduleName, containingFile, compilerOptions, generatedFileModuleResolverHost); } - // TODO(alexeagle): does this also work in third_party? - const allowNonHermeticRead = false; const bazelHost = new CompilerHost( - files, compilerOpts, bazelOpts, tsHost, fileLoader, ALLOW_NON_HERMETIC_READS, + files, compilerOpts, bazelOpts, tsHost, fileLoader, allowNonHermeticReads, generatedFileModuleResolver); const origBazelHostFileExist = bazelHost.fileExists; 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( {rootNames: files, options: compilerOpts, host: ngHost, emitCallback, gatherDiagnostics}); const tsickleEmitResult = emitResult as tsickle.EmitResult; @@ -209,6 +212,36 @@ export function compile({allowNonHermeticReads, compilerOpts, tsHost, bazelOpts, 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) { process.exitCode = main(process.argv.slice(2)); } diff --git a/packages/compiler-cli/src/transformers/program.ts b/packages/compiler-cli/src/transformers/program.ts index e2deb7c13a..a84fd695d3 100644 --- a/packages/compiler-cli/src/transformers/program.ts +++ b/packages/compiler-cli/src/transformers/program.ts @@ -56,7 +56,6 @@ class AngularCompilerProgram implements Program { private _analyzedModules: NgAnalyzedModules|undefined; private _structuralDiagnostics: Diagnostic[]|undefined; private _programWithStubs: ts.Program|undefined; - private _semanticDiagnostics: {ts: ts.Diagnostic[], ng: Diagnostic[]}|undefined; private _optionsDiagnostics: Diagnostic[] = []; constructor( @@ -148,12 +147,28 @@ class AngularCompilerProgram implements Program { getTsSemanticDiagnostics(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken): 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): 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 { @@ -359,11 +374,6 @@ class AngularCompilerProgram implements Program { return this._typeCheckHost !; } - private get semanticDiagnostics(): {ts: ts.Diagnostic[], ng: Diagnostic[]} { - return this._semanticDiagnostics || - (this._semanticDiagnostics = this.generateSemanticDiagnostics()); - } - private calculateTransforms( genFiles: Map, customTransformers?: CustomTransformers): ts.CustomTransformers { @@ -546,10 +556,6 @@ class AngularCompilerProgram implements Program { return sourceFilesToEmit; } - private generateSemanticDiagnostics(): {ts: ts.Diagnostic[], ng: Diagnostic[]} { - return translateDiagnostics(this.typeCheckHost, this.tsProgram.getSemanticDiagnostics()); - } - private writeFile( outFileName: string, outData: string, writeByteOrderMark: boolean, onError?: (message: string) => void, genFile?: GeneratedFile, sourceFiles?: ts.SourceFile[]) {