diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index efd5183ca6a..86c90ff6f1c 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1608,12 +1608,14 @@ namespace ts { /* @internal */ export function writeDeclarationFile(declarationFilePath: string, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[]) { let emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, declarationFilePath, sourceFile); - if (!emitDeclarationResult.reportedDeclarationError && !host.isDeclarationEmitBlocked(declarationFilePath, sourceFile)) { + let emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isDeclarationEmitBlocked(declarationFilePath, sourceFile); + if (!emitSkipped) { let declarationOutput = emitDeclarationResult.referencePathsOutput + getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo); let compilerOptions = host.getCompilerOptions(); writeFile(host, diagnostics, declarationFilePath, declarationOutput, compilerOptions.emitBOM); } + return emitSkipped; function getDeclarationOutput(synchronousDeclarationOutput: string, moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]) { let appliedSyncOutputPos = 0; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 29c7629e207..84a8eb7c6a6 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -323,27 +323,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi let modulekind = compilerOptions.module ? compilerOptions.module : languageVersion === ScriptTarget.ES6 ? ModuleKind.ES6 : ModuleKind.None; let sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined; let diagnostics: Diagnostic[] = []; + let emitSkipped = false; let newLine = host.getNewLine(); if (targetSourceFile === undefined) { forEach(host.getSourceFiles(), sourceFile => { if (shouldEmitToOwnFile(sourceFile, compilerOptions)) { - emitFile(getEmitFileNames(sourceFile, host), sourceFile); + emitSkipped = emitFile(getEmitFileNames(sourceFile, host), sourceFile) || emitSkipped; } }); if (compilerOptions.outFile || compilerOptions.out) { - emitFile(getBundledEmitFileNames(compilerOptions)); + emitSkipped = emitFile(getBundledEmitFileNames(compilerOptions)) || emitSkipped; } } else { // targetSourceFile is specified (e.g calling emitter from language service or calling getSemanticDiagnostic from language service) if (shouldEmitToOwnFile(targetSourceFile, compilerOptions)) { - emitFile(getEmitFileNames(targetSourceFile, host), targetSourceFile); + emitSkipped = emitFile(getEmitFileNames(targetSourceFile, host), targetSourceFile) || emitSkipped; } else if (!isDeclarationFile(targetSourceFile) && (compilerOptions.outFile || compilerOptions.out)) { - emitFile(getBundledEmitFileNames(compilerOptions)); + emitSkipped = emitFile(getBundledEmitFileNames(compilerOptions)) || emitSkipped; } } @@ -351,7 +352,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi diagnostics = sortAndDeduplicateDiagnostics(diagnostics); return { - emitSkipped: false, + emitSkipped, diagnostics, sourceMaps: sourceMapDataList }; @@ -7597,13 +7598,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath}: { jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string }, sourceFile?: SourceFile) { // Make sure not to write js File and source map file if any of them cannot be written - if (!host.isEmitBlocked(jsFilePath) && (!sourceMapFilePath || !host.isEmitBlocked(sourceMapFilePath))) { + let emitSkipped = host.isEmitBlocked(jsFilePath) || (sourceMapFilePath && host.isEmitBlocked(sourceMapFilePath)); + if (!emitSkipped) { emitJavaScript(jsFilePath, sourceMapFilePath, sourceFile); } if (compilerOptions.declaration) { - writeDeclarationFile(declarationFilePath, sourceFile, host, resolver, diagnostics); + emitSkipped = writeDeclarationFile(declarationFilePath, sourceFile, host, resolver, diagnostics) || emitSkipped; } + + return emitSkipped; } } } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index b4c9bc2eea7..87ca7fb2a44 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -293,7 +293,7 @@ namespace ts { program.getSemanticDiagnostics(sourceFile, cancellationToken)); if (program.getCompilerOptions().declaration) { - diagnostics.concat(program.getDeclarationDiagnostics(sourceFile, cancellationToken)); + diagnostics = diagnostics.concat(program.getDeclarationDiagnostics(sourceFile, cancellationToken)); } return sortAndDeduplicateDiagnostics(diagnostics); diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 4ebc1976217..fab3f649f2a 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1121,7 +1121,7 @@ namespace Harness { let emitResult = program.emit(); - let errors = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); + let errors = ts.getPreEmitDiagnostics(program); this.lastErrors = errors; let result = new CompilerResult(fileOutputs, errors, program, Harness.IO.getCurrentDirectory(), emitResult.sourceMaps); @@ -1666,7 +1666,7 @@ namespace Harness { let encoded_actual = Utils.encodeString(actual); if (expected != encoded_actual) { // Overwrite & issue error - let errMsg = "The baseline file " + relativeFileName + " has changed.\nExpected:\n" + expected + "\nActual:\n" + encoded_actual; + let errMsg = "The baseline file " + relativeFileName + " has changed."; throw new Error(errMsg); } } diff --git a/tests/baselines/reference/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.baseline b/tests/baselines/reference/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.baseline new file mode 100644 index 00000000000..5db889dc01d --- /dev/null +++ b/tests/baselines/reference/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.baseline @@ -0,0 +1,8 @@ +EmitSkipped: true +Diagnostics: + Cannot write file 'tests/cases/fourslash/b.js' which is one of the input files. + +EmitSkipped: false +FileName : tests/cases/fourslash/a.js +function foo2() { return 30; } // no error - should emit a.js + diff --git a/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline b/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline index f854a619a47..2f27152892b 100644 --- a/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline +++ b/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline @@ -1,4 +1,6 @@ -EmitSkipped: false +EmitSkipped: true +Diagnostics: + Exported variable 'foo' has or is using private name 'C'. FileName : tests/cases/fourslash/inputFile.js var M; (function (M) { diff --git a/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline b/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline index 463dfe6899a..a3a9023f75b 100644 --- a/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline +++ b/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline @@ -1,4 +1,6 @@ -EmitSkipped: false +EmitSkipped: true +Diagnostics: + Exported variable 'foo' has or is using private name 'C'. FileName : tests/cases/fourslash/inputFile.js define(["require", "exports"], function (require, exports) { var C = (function () { diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline index b6249822131..88bc5c50727 100644 --- a/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline @@ -1,4 +1,6 @@ -EmitSkipped: false +EmitSkipped: true +Diagnostics: + Type 'string' is not assignable to type 'number'. FileName : tests/cases/fourslash/inputFile.js var x = "hello world"; diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline index 38a695301d2..63747de55de 100644 --- a/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrorsForMultipleFiles2.baseline @@ -1,4 +1,6 @@ -EmitSkipped: false +EmitSkipped: true +Diagnostics: + Type 'string' is not assignable to type 'boolean'. FileName : out.js // File to emit, does not contain semantic errors, but --out is passed // expected to not generate declarations because of the semantic errors in the other file diff --git a/tests/cases/fourslash/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.ts b/tests/cases/fourslash/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.ts new file mode 100644 index 00000000000..138b4de6f46 --- /dev/null +++ b/tests/cases/fourslash/compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.ts @@ -0,0 +1,13 @@ +/// + +// @BaselineFile: compileOnSaveWorksWhenEmitBlockingErrorOnOtherFile.baseline +// @jsExtensions: js +// @Filename: b.js +// @emitThisFile: true +////function foo() { } // This has error because js file cannot be overwritten - emitSkipped should be true + +// @Filename: a.ts +// @emitThisFile: true +////function foo2() { return 30; } // no error - should emit a.js + +verify.baselineGetEmitOutput(); \ No newline at end of file