From 3215438ddf3f13deb59fb564f826fd8b360c5171 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 20 Oct 2015 11:22:46 -0700 Subject: [PATCH] Dont emit declaration file if there are errors in the source file --- src/compiler/core.ts | 2 +- src/compiler/declarationEmitter.ts | 4 +-- src/compiler/emitter.ts | 2 +- src/compiler/program.ts | 52 +++++++++++++++++++++++++++--- src/compiler/types.ts | 1 + src/compiler/utilities.ts | 1 + 6 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 73e25bc472f..de9a93ee679 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -729,7 +729,7 @@ namespace ts { * List of supported extensions in order of file resolution precedence. */ export const supportedTypeScriptExtensions = ["ts", "tsx", "d.ts"]; - + export function getSupportedExtensions(options?: CompilerOptions): string[] { return options && options.jsExtensions ? supportedTypeScriptExtensions.concat(options.jsExtensions) : supportedTypeScriptExtensions; } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 76c3175dcd5..8b4e1500a1c 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1607,9 +1607,7 @@ namespace ts { /* @internal */ export function writeDeclarationFile(declarationFilePath: string, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[]) { let emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, declarationFilePath, sourceFile); - // TODO(shkamat): Should we not write any declaration file if any of them can produce error, - // or should we just not write this file like we are doing now - if (!emitDeclarationResult.reportedDeclarationError) { + if (!emitDeclarationResult.reportedDeclarationError && !host.isDeclarationEmitBlocked(declarationFilePath, sourceFile)) { let declarationOutput = emitDeclarationResult.referencePathsOutput + getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo); let compilerOptions = host.getCompilerOptions(); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 842bfcfcf7b..3f741437609 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -7601,7 +7601,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitJavaScript(jsFilePath, sourceFile); } - if (compilerOptions.declaration && !host.isEmitBlocked(declarationFilePath)) { + if (compilerOptions.declaration) { writeDeclarationFile(declarationFilePath, sourceFile, host, resolver, diagnostics); } } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 22dca3ace4a..4ab0bf4ccea 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -330,6 +330,7 @@ namespace ts { let files: SourceFile[] = []; let fileProcessingDiagnostics = createDiagnosticCollection(); let programDiagnostics = createDiagnosticCollection(); + let emitBlockingDiagnostics = createDiagnosticCollection(); let hasEmitBlockingDiagnostics: Map = {}; // Map storing if there is emit blocking diagnostics for given input let commonSourceDirectory: string; @@ -393,6 +394,7 @@ namespace ts { getDiagnosticsProducingTypeChecker, getCommonSourceDirectory: () => commonSourceDirectory, emit, + isDeclarationEmitBlocked, getCurrentDirectory: () => host.getCurrentDirectory(), getNodeCount: () => getDiagnosticsProducingTypeChecker().getNodeCount(), getIdentifierCount: () => getDiagnosticsProducingTypeChecker().getIdentifierCount(), @@ -510,7 +512,7 @@ namespace ts { return true; } - function getEmitHost(writeFileCallback?: WriteFileCallback): EmitHost { + function getEmitHost(writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken): EmitHost { return { getCanonicalFileName: fileName => host.getCanonicalFileName(fileName), getCommonSourceDirectory: program.getCommonSourceDirectory, @@ -521,7 +523,8 @@ namespace ts { getSourceFiles: program.getSourceFiles, writeFile: writeFileCallback || ( (fileName, data, writeByteOrderMark, onError) => host.writeFile(fileName, data, writeByteOrderMark, onError)), - isEmitBlocked: emitFileName => hasProperty(hasEmitBlockingDiagnostics, emitFileName), + isEmitBlocked, + isDeclarationEmitBlocked: (emitFileName, sourceFile) => program.isDeclarationEmitBlocked(emitFileName, sourceFile, cancellationToken), }; } @@ -537,6 +540,42 @@ namespace ts { return runWithCancellationToken(() => emitWorker(this, sourceFile, writeFileCallback, cancellationToken)); } + function isDeclarationEmitBlocked(emitFileName: string, sourceFile?: SourceFile, cancellationToken?: CancellationToken): boolean { + if (isEmitBlocked(emitFileName)) { + return true; + } + + // Dont check for emit blocking options diagnostics because that check per emit file is already covered in isEmitBlocked + // We dont want to end up blocking declaration emit of one file because other file results in emit blocking error + if (getOptionsDiagnostics(cancellationToken, /*includeEmitBlockingDiagnostics*/false).length || + getGlobalDiagnostics().length) { + return true; + } + + if (sourceFile) { + // Do not generate declaration file for this if there are any errors in this file or any of the declaration files + return hasSyntaxOrSemanticDiagnostics(sourceFile) || + forEach(files, sourceFile => isDeclarationFile(sourceFile) && hasSyntaxOrSemanticDiagnostics(sourceFile)); + } + + // Check if the bundled emit source files have errors + return forEach(files, sourceFile => { + // Check all the files that will be bundled together as well as all the included declaration files are error free + if (!isExternalModule(sourceFile)) { + return hasSyntaxOrSemanticDiagnostics(sourceFile); + } + }); + + function hasSyntaxOrSemanticDiagnostics(file: SourceFile) { + return !!getSyntacticDiagnostics(file, cancellationToken).length || + !!getSemanticDiagnostics(file, cancellationToken).length; + } + } + + function isEmitBlocked(emitFileName: string): boolean { + return hasProperty(hasEmitBlockingDiagnostics, emitFileName); + } + function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken): EmitResult { // If the noEmitOnError flag is set, then check if we have any errors so far. If so, // immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we @@ -559,7 +598,7 @@ namespace ts { let emitResult = emitFiles( emitResolver, - getEmitHost(writeFileCallback), + getEmitHost(writeFileCallback, cancellationToken), sourceFile); emitTime += new Date().getTime() - start; @@ -821,10 +860,13 @@ namespace ts { }); } - function getOptionsDiagnostics(): Diagnostic[] { + function getOptionsDiagnostics(cancellationToken?: CancellationToken, includeEmitBlockingDiagnostics?: boolean): Diagnostic[] { let allDiagnostics: Diagnostic[] = []; addRange(allDiagnostics, fileProcessingDiagnostics.getGlobalDiagnostics()); addRange(allDiagnostics, programDiagnostics.getGlobalDiagnostics()); + if (!includeEmitBlockingDiagnostics) { + addRange(allDiagnostics, emitBlockingDiagnostics.getGlobalDiagnostics()); + } return sortAndDeduplicateDiagnostics(allDiagnostics); } @@ -1291,7 +1333,7 @@ namespace ts { function createEmitBlockingDiagnostics(emitFileName: string, message: DiagnosticMessage) { hasEmitBlockingDiagnostics[emitFileName] = true; - programDiagnostics.add(createCompilerDiagnostic(message, emitFileName)); + emitBlockingDiagnostics.add(createCompilerDiagnostic(message, emitFileName)); } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c501fd52bc2..b5451c3311d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1358,6 +1358,7 @@ namespace ts { getTypeChecker(): TypeChecker; /* @internal */ getCommonSourceDirectory(): string; + /* @internal */ isDeclarationEmitBlocked(emitFileName: string, sourceFile?: SourceFile, cancellationToken?: CancellationToken): boolean; // For testing purposes only. Should not be used by any other consumers (including the // language service). diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2d6f5410698..0b0c9f2db33 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -40,6 +40,7 @@ namespace ts { getNewLine(): string; isEmitBlocked(emitFileName: string): boolean; + isDeclarationEmitBlocked(emitFileName: string, sourceFile?: SourceFile): boolean; writeFile: WriteFileCallback; }