diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 4490c240886..7b4b4f03be3 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -562,6 +562,7 @@ namespace ts { const prependNodes = createPrependNodes(config.projectReferences, getCommandLine, f => host.readFile(f)); const jsPrepend = createUnparsedJsSourceFile(ownPrependInput); const sourceFilesForJsEmit = createSourceFilesForPrologues(buildInfo.bundle.js); + let currentBuildInfoType: "js" | "dts" = "js"; const emitHost: EmitHost = { getPrependNodes: memoize(() => [...prependNodes, jsPrepend]), getProjectReferences: () => config.projectReferences, @@ -576,14 +577,36 @@ namespace ts { getLibFileFromReference: notImplemented, isSourceFileFromExternalLibrary: returnFalse, writeFile: (name, text, writeByteOrderMark) => { - if (name !== buildInfoPath) { - outputFiles.push({ name, text, writeByteOrderMark }); - } - else { - // Add dts and sources build info since we are not touching that file - const buildInfo = JSON.parse(text) as BuildInfo; - newBundle.js = buildInfo.bundle && buildInfo.bundle.js; - writeByteOrderMarkBuildInfo = writeByteOrderMarkBuildInfo || writeByteOrderMark; + switch (name) { + case jsFilePath: + if (jsFileText !== text) { + outputFiles.push({ name, text, writeByteOrderMark }); + } + break; + case sourceMapFilePath: + if (sourceMapText !== text) { + outputFiles.push({ name, text, writeByteOrderMark }); + } + break; + case buildInfoPath: + if (currentBuildInfoType === "js" || stripInternal) { + const buildInfo = JSON.parse(text) as BuildInfo; + newBundle[currentBuildInfoType] = buildInfo.bundle && buildInfo.bundle[currentBuildInfoType]; + writeByteOrderMarkBuildInfo = writeByteOrderMarkBuildInfo || writeByteOrderMark; + } + break; + case declarationFilePath: + if (stripInternal && declarationText !== text) { + outputFiles.push({ name, text, writeByteOrderMark }); + } + break; + case declarationMapPath: + if (declarationMapText !== text) { + outputFiles.push({ name, text, writeByteOrderMark }); + } + break; + default: + Debug.assertNever(name as never); } }, isEmitBlocked: returnFalse, @@ -597,23 +620,11 @@ namespace ts { emitFiles(notImplementedResolver, emitHost, /*targetSourceFile*/ undefined, /*emitOnlyDtsFiles*/ false, getTransformers(optionsWithoutDeclaration)); // Emit d.ts map if (shouldHaveDeclarationText) { + currentBuildInfoType = "dts"; const dtsPrepends = prependNodes.map(prepend => createUnparsedSourceFile(prepend, "dts", stripInternal)); emitHost.getPrependNodes = memoize(() => [...dtsPrepends, createUnparsedDtsSourceFile(ownPrependInput)]); emitHost.getCompilerOptions = () => config.options; emitHost.getSourceFiles = () => emptyArray; - emitHost.writeFile = (name, text, writeByteOrderMark) => { - // Same dts ignore - if (!stripInternal && (fileExtensionIs(name, Extension.Dts) || name === buildInfoPath)) return; - // Even though dts file hasnt changed, whether def is internal or not could change, so write the dts and update buildInfo - if (name !== buildInfoPath) { - outputFiles.push({ name, text, writeByteOrderMark }); - } - else { - const buildInfo = JSON.parse(text) as BuildInfo; - newBundle.dts = buildInfo.bundle && buildInfo.bundle.dts; - writeByteOrderMarkBuildInfo = writeByteOrderMarkBuildInfo || writeByteOrderMark; - } - }; emitFiles(notImplementedResolver, emitHost, /*targetSourceFile*/ undefined, /*emitOnlyDtsFiles*/ true); } outputFiles.push({ name: buildInfoPath!, text: getBuildInfoText({ program: buildInfo.program, bundle: newBundle }), writeByteOrderMark: writeByteOrderMarkBuildInfo }); diff --git a/src/testRunner/unittests/tsbuild/outFile.ts b/src/testRunner/unittests/tsbuild/outFile.ts index ca5b28ca440..67d666b8cd4 100644 --- a/src/testRunner/unittests/tsbuild/outFile.ts +++ b/src/testRunner/unittests/tsbuild/outFile.ts @@ -88,14 +88,12 @@ namespace ts { modifyAgainFs, additionalSourceFiles, dependOrdered, - unchangedDtsWritesThirdDts, }: { scenario: string; modifyFs: (fs: vfs.FileSystem) => void; modifyAgainFs?: (fs: vfs.FileSystem) => void; additionalSourceFiles?: ReadonlyArray; dependOrdered?: boolean; - unchangedDtsWritesThirdDts?: boolean; }) { const incrementalDtsChanged: ExpectedBuildOutputPerState = { expectedDiagnostics: dependOrdered ? @@ -161,7 +159,7 @@ namespace ts { [Diagnostics.Updating_unchanged_output_timestamps_of_project_0, sources[project.second][source.config]], [Diagnostics.Project_0_is_out_of_date_because_output_javascript_and_source_map_if_specified_of_its_dependency_1_has_changed, relSources[project.third][source.config], "src/second"], [Diagnostics.Updating_output_javascript_and_javascript_source_map_if_specified_of_project_0, sources[project.third][source.config]], - ...getUnchangedOutputTimeStampUpdateOfProjectThree(), + [Diagnostics.Updating_unchanged_output_timestamps_of_project_0, sources[project.third][source.config]], ] : [ getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]), @@ -170,7 +168,7 @@ namespace ts { [Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, relSources[project.second][source.config], relSources[project.second][source.ts][part.one], relOutputFiles[project.second][ext.js]], [Diagnostics.Project_0_is_out_of_date_because_output_javascript_and_source_map_if_specified_of_its_dependency_1_has_changed, relSources[project.third][source.config], "src/first"], [Diagnostics.Updating_output_javascript_and_javascript_source_map_if_specified_of_project_0, sources[project.third][source.config]], - ...getUnchangedOutputTimeStampUpdateOfProjectThree(), + [Diagnostics.Updating_unchanged_output_timestamps_of_project_0, sources[project.third][source.config]], ], expectedReadFiles: getReadFilesMap( [ @@ -312,12 +310,6 @@ namespace ts { withoutBuildInfo: incrementalDtsUnchangedWithoutBuildInfo } }); - - function getUnchangedOutputTimeStampUpdateOfProjectThree(): ReadonlyArray { - return !unchangedDtsWritesThirdDts ? - [[Diagnostics.Updating_unchanged_output_timestamps_of_project_0, sources[project.third][source.config]]] : - emptyArray; - } } verifyOutFileScenario({ @@ -645,27 +637,23 @@ ${internal} enum internalEnum { a, b, c }`); scenario: "stripInternal", modifyFs: fs => stripInternalScenario(fs), modifyAgainFs: fs => replaceText(fs, sources[project.first][source.ts][part.one], `/*@internal*/ interface`, "interface"), - unchangedDtsWritesThirdDts: true }); verifyOutFileScenario({ scenario: "stripInternal with comments emit enabled", modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ true), modifyAgainFs: fs => replaceText(fs, sources[project.first][source.ts][part.one], `/*@internal*/ interface`, "interface"), - unchangedDtsWritesThirdDts: true }); verifyOutFileScenario({ scenario: "stripInternal jsdoc style comment", modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true), modifyAgainFs: fs => replaceText(fs, sources[project.first][source.ts][part.one], `/**@internal*/ interface`, "interface"), - unchangedDtsWritesThirdDts: true }); verifyOutFileScenario({ scenario: "stripInternal jsdoc style with comments emit enabled", modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ true, /*jsDocStyle*/ true), - unchangedDtsWritesThirdDts: true }); function makeOneTwoThreeDependOrder(fs: vfs.FileSystem) { @@ -684,7 +672,6 @@ ${internal} enum internalEnum { a, b, c }`); modifyFs: fs => stripInternalWithDependentOrder(fs), modifyAgainFs: fs => replaceText(fs, sources[project.first][source.ts][part.one], `/*@internal*/ interface`, "interface"), dependOrdered: true, - unchangedDtsWritesThirdDts: true }); verifyOutFileScenario({ @@ -692,7 +679,6 @@ ${internal} enum internalEnum { a, b, c }`); modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ true), modifyAgainFs: fs => replaceText(fs, sources[project.first][source.ts][part.one], `/*@internal*/ interface`, "interface"), dependOrdered: true, - unchangedDtsWritesThirdDts: true }); verifyOutFileScenario({ @@ -700,14 +686,12 @@ ${internal} enum internalEnum { a, b, c }`); modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true), modifyAgainFs: fs => replaceText(fs, sources[project.first][source.ts][part.one], `/**@internal*/ interface`, "interface"), dependOrdered: true, - unchangedDtsWritesThirdDts: true }); verifyOutFileScenario({ scenario: "stripInternal jsdoc style with comments emit enabled when one-two-three are prepended in order", modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ true, /*jsDocStyle*/ true), dependOrdered: true, - unchangedDtsWritesThirdDts: true }); }); }