diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 704cdaf23f975..7af7be17f5534 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -612,7 +612,8 @@ namespace ts { */ function getProgramBuildInfo(state: Readonly, getCanonicalFileName: GetCanonicalFileName): ProgramBuildInfo | undefined { if (state.compilerOptions.outFile || state.compilerOptions.out) return undefined; - const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getOutputPathForBuildInfo(state.compilerOptions)!, Debug.assertDefined(state.program).getCurrentDirectory())); + const currentDirectory = Debug.assertDefined(state.program).getCurrentDirectory(); + const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getOutputPathForBuildInfo(state.compilerOptions)!, currentDirectory)); const fileInfos: MapLike = {}; state.fileInfos.forEach((value, key) => { const signature = state.currentAffectedFilesSignatures && state.currentAffectedFilesSignatures.get(key); @@ -621,7 +622,7 @@ namespace ts { const result: ProgramBuildInfo = { fileInfos, - options: convertToReusableCompilerOptions(state.compilerOptions, relativeToBuildInfo) + options: convertToReusableCompilerOptions(state.compilerOptions, relativeToBuildInfoEnsuringAbsolutePath) }; if (state.referencedMap) { const referencedMap: MapLike = {}; @@ -661,6 +662,10 @@ namespace ts { return result; + function relativeToBuildInfoEnsuringAbsolutePath(path: string) { + return relativeToBuildInfo(getNormalizedAbsolutePath(path, currentDirectory)); + } + function relativeToBuildInfo(path: string) { return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory, path, getCanonicalFileName)); } diff --git a/src/testRunner/unittests/tscWatch/helpers.ts b/src/testRunner/unittests/tscWatch/helpers.ts index f8647393cb118..ce5fd9d4725b5 100644 --- a/src/testRunner/unittests/tscWatch/helpers.ts +++ b/src/testRunner/unittests/tscWatch/helpers.ts @@ -35,8 +35,8 @@ namespace ts.tscWatch { close(): void; } - export function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) { - const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, {}, host); + export function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, optionsToExtend?: CompilerOptions, maxNumberOfFilesToIterateForInvalidation?: number) { + const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, optionsToExtend || {}, host); compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation; const watch = createWatchProgram(compilerHost); const result = (() => watch.getCurrentProgram().getProgram()) as Watch; diff --git a/src/testRunner/unittests/tscWatch/incremental.ts b/src/testRunner/unittests/tscWatch/incremental.ts index 15f5a6dbe5fae..6c72a4bfe9c71 100644 --- a/src/testRunner/unittests/tscWatch/incremental.ts +++ b/src/testRunner/unittests/tscWatch/incremental.ts @@ -9,6 +9,7 @@ namespace ts.tscWatch { interface VerifyIncrementalWatchEmitInput { files: ReadonlyArray; + optionsToExtend?: CompilerOptions; expectedInitialEmit: ReadonlyArray; expectedInitialErrors: ReadonlyArray; modifyFs?: (host: WatchedSystem) => void; @@ -32,9 +33,9 @@ namespace ts.tscWatch { }); } - function incrementalBuild(configFile: string, host: WatchedSystem) { + function incrementalBuild(configFile: string, host: WatchedSystem, optionsToExtend?: CompilerOptions) { const reportDiagnostic = createDiagnosticReporter(host); - const config = parseConfigFileWithSystem(configFile, {}, host, reportDiagnostic); + const config = parseConfigFileWithSystem(configFile, optionsToExtend || {}, host, reportDiagnostic); if (config) { performIncrementalCompilation({ rootNames: config.fileNames, @@ -50,12 +51,14 @@ namespace ts.tscWatch { interface VerifyIncrementalWatchEmitWorkerInput { input: VerifyIncrementalWatchEmitInput; - emitAndReportErrors: (configFile: string, host: WatchedSystem) => { close(): void; }; + emitAndReportErrors: (configFile: string, host: WatchedSystem, optionsToExtend?: CompilerOptions) => { close(): void; }; verifyErrors: (host: WatchedSystem, errors: ReadonlyArray) => void; } function verifyIncrementalWatchEmitWorker({ input: { - files, expectedInitialEmit, expectedInitialErrors, modifyFs, expectedIncrementalEmit, expectedIncrementalErrors + files, optionsToExtend, + expectedInitialEmit, expectedInitialErrors, + modifyFs, expectedIncrementalEmit, expectedIncrementalErrors }, emitAndReportErrors, verifyErrors @@ -70,6 +73,7 @@ namespace ts.tscWatch { }; verifyBuild({ host, + optionsToExtend, writtenFiles, emitAndReportErrors, verifyErrors, @@ -80,6 +84,7 @@ namespace ts.tscWatch { modifyFs(host); verifyBuild({ host, + optionsToExtend, writtenFiles, emitAndReportErrors, verifyErrors, @@ -91,15 +96,19 @@ namespace ts.tscWatch { interface VerifyBuildWorker { host: WatchedSystem; + optionsToExtend?: CompilerOptions; writtenFiles: Map; emitAndReportErrors: VerifyIncrementalWatchEmitWorkerInput["emitAndReportErrors"]; verifyErrors: VerifyIncrementalWatchEmitWorkerInput["verifyErrors"]; expectedEmit: ReadonlyArray; expectedErrors: ReadonlyArray; } - function verifyBuild({ host, writtenFiles, emitAndReportErrors, verifyErrors, expectedEmit, expectedErrors }: VerifyBuildWorker) { + function verifyBuild({ + host, optionsToExtend, writtenFiles, emitAndReportErrors, + verifyErrors, expectedEmit, expectedErrors + }: VerifyBuildWorker) { writtenFiles.clear(); - const result = emitAndReportErrors("tsconfig.json", host); + const result = emitAndReportErrors("tsconfig.json", host, optionsToExtend); checkFileEmit(writtenFiles, expectedEmit); verifyErrors(host, expectedErrors); result.close(); @@ -159,60 +168,69 @@ namespace ts.tscWatch { content: "var y = 20;\n" }; describe("own file emit without errors", () => { - const modifiedFile2Content = file2.content.replace("y", "z").replace("20", "10"); - verifyIncrementalWatchEmit({ - files: [libFile, file1, file2, configFile], - expectedInitialEmit: [ - file1Js, - file2Js, - { - path: `${project}/tsconfig.tsbuildinfo`, - content: getBuildInfoText({ - program: { - fileInfos: { - [libFilePath]: libFileInfo, - [file1Path]: getFileInfo(file1.content), - [file2Path]: getFileInfo(file2.content) - }, - options: { - incremental: true, - configFilePath: "./tsconfig.json" - }, - referencedMap: {}, - exportedModulesMap: {}, - semanticDiagnosticsPerFile: [libFilePath, file1Path, file2Path] - }, - version - }) - } - ], - expectedInitialErrors: emptyArray, - modifyFs: host => host.writeFile(file2.path, modifiedFile2Content), - expectedIncrementalEmit: [ - file1Js, - { path: file2Js.path, content: file2Js.content.replace("y", "z").replace("20", "10") }, - { - path: `${project}/tsconfig.tsbuildinfo`, - content: getBuildInfoText({ - program: { - fileInfos: { - [libFilePath]: libFileInfo, - [file1Path]: getFileInfo(file1.content), - [file2Path]: getFileInfo(modifiedFile2Content) + function verify(optionsToExtend?: CompilerOptions, expectedBuildinfoOptions?: CompilerOptions) { + const modifiedFile2Content = file2.content.replace("y", "z").replace("20", "10"); + verifyIncrementalWatchEmit({ + files: [libFile, file1, file2, configFile], + optionsToExtend, + expectedInitialEmit: [ + file1Js, + file2Js, + { + path: `${project}/tsconfig.tsbuildinfo`, + content: getBuildInfoText({ + program: { + fileInfos: { + [libFilePath]: libFileInfo, + [file1Path]: getFileInfo(file1.content), + [file2Path]: getFileInfo(file2.content) + }, + options: { + incremental: true, + ...expectedBuildinfoOptions, + configFilePath: "./tsconfig.json" + }, + referencedMap: {}, + exportedModulesMap: {}, + semanticDiagnosticsPerFile: [libFilePath, file1Path, file2Path] }, - options: { - incremental: true, - configFilePath: "./tsconfig.json" + version + }) + } + ], + expectedInitialErrors: emptyArray, + modifyFs: host => host.writeFile(file2.path, modifiedFile2Content), + expectedIncrementalEmit: [ + file1Js, + { path: file2Js.path, content: file2Js.content.replace("y", "z").replace("20", "10") }, + { + path: `${project}/tsconfig.tsbuildinfo`, + content: getBuildInfoText({ + program: { + fileInfos: { + [libFilePath]: libFileInfo, + [file1Path]: getFileInfo(file1.content), + [file2Path]: getFileInfo(modifiedFile2Content) + }, + options: { + incremental: true, + ...expectedBuildinfoOptions, + configFilePath: "./tsconfig.json" + }, + referencedMap: {}, + exportedModulesMap: {}, + semanticDiagnosticsPerFile: [libFilePath, file1Path, file2Path] }, - referencedMap: {}, - exportedModulesMap: {}, - semanticDiagnosticsPerFile: [libFilePath, file1Path, file2Path] - }, - version - }) - } - ], - expectedIncrementalErrors: emptyArray, + version + }) + } + ], + expectedIncrementalErrors: emptyArray, + }); + } + verify(); + describe("with commandline parameters that are not relative", () => { + verify({ project: "tsconfig.json" }, { project: "./tsconfig.json" }); }); }); @@ -337,6 +355,7 @@ namespace ts.tscWatch { expectedInitialErrors: emptyArray }); }); + }); describe("module compilation", () => { diff --git a/src/testRunner/unittests/tscWatch/programUpdates.ts b/src/testRunner/unittests/tscWatch/programUpdates.ts index b322c08bfe7f8..3fd542642605f 100644 --- a/src/testRunner/unittests/tscWatch/programUpdates.ts +++ b/src/testRunner/unittests/tscWatch/programUpdates.ts @@ -931,7 +931,7 @@ namespace ts.tscWatch { content: generateTSConfig(options, emptyArray, "\n") }; const host = createWatchedSystem([file1, file2, libFile, tsconfig], { currentDirectory: proj }); - const watch = createWatchOfConfigFile(tsconfig.path, host, /*maxNumberOfFilesToIterateForInvalidation*/1); + const watch = createWatchOfConfigFile(tsconfig.path, host, /*optionsToExtend*/ undefined, /*maxNumberOfFilesToIterateForInvalidation*/1); checkProgramActualFiles(watch(), [file1.path, file2.path, libFile.path]); outputFiles.forEach(f => host.fileExists(f));