From 827427f35bde61012961c4d4a81d259c1a59cb6c Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 14 Oct 2019 13:45:52 -0700 Subject: [PATCH 1/3] Add test for --tsbuildinfo not as absolute or relative path --- src/harness/fakes.ts | 8 +++- src/testRunner/tsconfig.json | 1 + src/testRunner/unittests/tsbuild/helpers.ts | 2 +- src/testRunner/unittests/tsc/helpers.ts | 4 ++ src/testRunner/unittests/tsc/incremental.ts | 26 ++++++++++++ ...g-filename-for-buildinfo-on-commandline.js | 7 ++++ ...g-filename-for-buildinfo-on-commandline.js | 42 +++++++++++++++++++ 7 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 src/testRunner/unittests/tsc/incremental.ts create mode 100644 tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js create mode 100644 tests/baselines/reference/tsc/incremental/initial-build/when-passing-passing-filename-for-buildinfo-on-commandline.js diff --git a/src/harness/fakes.ts b/src/harness/fakes.ts index adcaef55471..d14d8dd2a71 100644 --- a/src/harness/fakes.ts +++ b/src/harness/fakes.ts @@ -524,7 +524,7 @@ ${indentText}${text}`; export const version = "FakeTSVersion"; - export function patchSolutionBuilderHost(host: ts.SolutionBuilderHost, sys: System) { + export function patchHostForBuildInfoReadWrite(host: ts.CompilerHost | ts.SolutionBuilderHost) { const originalReadFile = host.readFile; host.readFile = (path, encoding) => { const value = originalReadFile.call(host, path, encoding); @@ -537,7 +537,7 @@ ${indentText}${text}`; if (host.writeFile) { const originalWriteFile = host.writeFile; - host.writeFile = (fileName, content, writeByteOrderMark) => { + host.writeFile = (fileName: string, content: string, writeByteOrderMark: boolean) => { if (!ts.isBuildInfoFile(fileName)) return originalWriteFile.call(host, fileName, content, writeByteOrderMark); const buildInfo = ts.getBuildInfo(content); sanitizeBuildInfoProgram(buildInfo); @@ -545,6 +545,10 @@ ${indentText}${text}`; originalWriteFile.call(host, fileName, ts.getBuildInfoText(buildInfo), writeByteOrderMark); }; } + } + + export function patchSolutionBuilderHost(host: ts.SolutionBuilderHost, sys: System) { + patchHostForBuildInfoReadWrite(host); ts.Debug.assert(host.now === undefined); host.now = () => new Date(sys.vfs.time()); diff --git a/src/testRunner/tsconfig.json b/src/testRunner/tsconfig.json index 27a7712a2b1..295fe93f031 100644 --- a/src/testRunner/tsconfig.json +++ b/src/testRunner/tsconfig.json @@ -113,6 +113,7 @@ "unittests/tsbuild/watchEnvironment.ts", "unittests/tsbuild/watchMode.ts", "unittests/tsc/declarationEmit.ts", + "unittests/tsc/incremental.ts", "unittests/tscWatch/consoleClearing.ts", "unittests/tscWatch/emit.ts", "unittests/tscWatch/emitAndErrorUpdates.ts", diff --git a/src/testRunner/unittests/tsbuild/helpers.ts b/src/testRunner/unittests/tsbuild/helpers.ts index 456bf0e2c2b..d0009de7622 100644 --- a/src/testRunner/unittests/tsbuild/helpers.ts +++ b/src/testRunner/unittests/tsbuild/helpers.ts @@ -290,7 +290,7 @@ interface Symbol { baselineSourceMap, modifyFs, baselineReadFileCalls, incrementalScenarios }: VerifyTsBuildInput) { - describe(`tsc --b ${scenario}:: ${subScenario}`, () => { + describe(`tsc ${commandLineArgs.join(" ")} ${scenario}:: ${subScenario}`, () => { let tick: () => void; let sys: TscCompileSystem; before(() => { diff --git a/src/testRunner/unittests/tsc/helpers.ts b/src/testRunner/unittests/tsc/helpers.ts index ad1d64ac285..2ef5f6bc782 100644 --- a/src/testRunner/unittests/tsc/helpers.ts +++ b/src/testRunner/unittests/tsc/helpers.ts @@ -79,6 +79,7 @@ namespace ts { const { fileNames, options, projectReferences } = config; const reportDiagnostic = createDiagnosticReporter(sys, options.pretty); const host = createCompilerHostWorker(options, /*setParentPos*/ undefined, sys); + fakes.patchHostForBuildInfoReadWrite(host); const currentDirectory = host.getCurrentDirectory(); const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames()); changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName)); @@ -102,7 +103,10 @@ namespace ts { function performIncrementalCompilation(sys: TscCompileSystem, config: ParsedCommandLine) { const reportDiagnostic = createDiagnosticReporter(sys, config.options.pretty); const { options, fileNames, projectReferences } = config; + const host = createIncrementalCompilerHost(options, sys); + fakes.patchHostForBuildInfoReadWrite(host); const exitCode = ts.performIncrementalCompilation({ + host, system: sys, rootNames: fileNames, options, diff --git a/src/testRunner/unittests/tsc/incremental.ts b/src/testRunner/unittests/tsc/incremental.ts new file mode 100644 index 00000000000..1f887024fd0 --- /dev/null +++ b/src/testRunner/unittests/tsc/incremental.ts @@ -0,0 +1,26 @@ +namespace ts { + describe("unittests:: tsc:: incremental::", () => { + verifyTscIncrementalEdits({ + scenario: "incremental", + subScenario: "when passing passing filename for buildinfo on commandline", + fs: () => loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": utils.dedent` + { + "compilerOptions": { + "target": "es5", + "module": "commonjs", + }, + "include": [ + "src/**/*.ts" + ] + }`, + }), + commandLineArgs: ["--incremental", "--p", "src/project", "--tsBuildInfoFile", "src/project/.tsbuildinfo"], + incrementalScenarios: [{ + buildKind: BuildKind.IncrementalDtsUnchanged, + modifyFs: noop, + }] + }); + }); +} diff --git a/tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js b/tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js new file mode 100644 index 00000000000..bfc2f0ba185 --- /dev/null +++ b/tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js @@ -0,0 +1,7 @@ +//// [/lib/incremental-declaration-doesnt-changeOutput.txt] +/lib/tsc --incremental --p src/project --tsBuildInfoFile src/project/.tsbuildinfo +exitCode:: 0 + + +//// [/src/project/.tsbuildinfo] file written with same contents +//// [/src/project/src/main.js] file written with same contents diff --git a/tests/baselines/reference/tsc/incremental/initial-build/when-passing-passing-filename-for-buildinfo-on-commandline.js b/tests/baselines/reference/tsc/incremental/initial-build/when-passing-passing-filename-for-buildinfo-on-commandline.js new file mode 100644 index 00000000000..54af1ef615c --- /dev/null +++ b/tests/baselines/reference/tsc/incremental/initial-build/when-passing-passing-filename-for-buildinfo-on-commandline.js @@ -0,0 +1,42 @@ +//// [/lib/initial-buildOutput.txt] +/lib/tsc --incremental --p src/project --tsBuildInfoFile src/project/.tsbuildinfo +exitCode:: 0 + + +//// [/src/project/.tsbuildinfo] +{ + "program": { + "fileInfos": { + "../../lib/lib.d.ts": { + "version": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };", + "signature": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };" + }, + "./src/main.ts": { + "version": "-10726455937-export const x = 10;", + "signature": "-6057683066-export declare const x = 10;\r\n" + } + }, + "options": { + "target": 1, + "module": 1, + "incremental": true, + "project": "./", + "tsBuildInfoFile": "./.tsbuildinfo", + "configFilePath": "./tsconfig.json" + }, + "referencedMap": {}, + "exportedModulesMap": {}, + "semanticDiagnosticsPerFile": [ + "../../lib/lib.d.ts", + "./src/main.ts" + ] + }, + "version": "FakeTSVersion" +} + +//// [/src/project/src/main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.x = 10; + + From 4b10145340e0386f818fdeb380482592119db01f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 14 Oct 2019 14:44:47 -0700 Subject: [PATCH 2/3] Make sure commandline options are absolute paths so they dont conflict with tsbuildinfo paths Fixes #33667 --- src/compiler/builder.ts | 36 +------------------ src/compiler/commandLineParser.ts | 35 ++++++++++++++++++ src/testRunner/unittests/tsc/helpers.ts | 19 ++++++++-- src/tsc/tsc.ts | 14 ++++++-- ...g-filename-for-buildinfo-on-commandline.js | 1 - 5 files changed, 63 insertions(+), 42 deletions(-) diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 7451eb678b4..a1ae9e133fb 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -1118,7 +1118,7 @@ namespace ts { const state: ReusableBuilderProgramState = { fileInfos, - compilerOptions: convertFromReusableCompilerOptions(program.options, toAbsolutePath), + compilerOptions: convertToOptionsWithAbsolutePaths(program.options, toAbsolutePath), referencedMap: getMapOfReferencedSet(program.referencedMap, toPath), exportedModulesMap: getMapOfReferencedSet(program.exportedModulesMap, toPath), semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile && arrayToMap(program.semanticDiagnosticsPerFile, value => toPath(isString(value) ? value : value[0]), value => isString(value) ? emptyArray : value[1]), @@ -1156,40 +1156,6 @@ namespace ts { } } - function convertFromReusableCompilerOptions(options: CompilerOptions, toAbsolutePath: (path: string) => string) { - const result: CompilerOptions = {}; - const optionsNameMap = getOptionNameMap().optionNameMap; - - for (const name in options) { - if (hasProperty(options, name)) { - result[name] = convertFromReusableCompilerOptionValue( - optionsNameMap.get(name.toLowerCase()), - options[name] as CompilerOptionsValue, - toAbsolutePath - ); - } - } - if (result.configFilePath) { - result.configFilePath = toAbsolutePath(result.configFilePath); - } - return result; - } - - function convertFromReusableCompilerOptionValue(option: CommandLineOption | undefined, value: CompilerOptionsValue, toAbsolutePath: (path: string) => string) { - if (option) { - if (option.type === "list") { - const values = value as readonly (string | number)[]; - if (option.element.isFilePath && values.length) { - return values.map(toAbsolutePath); - } - } - else if (option.isFilePath) { - return toAbsolutePath(value as string); - } - } - return value; - } - export function createRedirectedBuilderProgram(state: { program: Program | undefined; compilerOptions: CompilerOptions; }, configFileParsingDiagnostics: readonly Diagnostic[]): BuilderProgram { return { getState: notImplemented, diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index f7ac250984a..596f8651500 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -2041,6 +2041,41 @@ namespace ts { } } + /* @internal */ + export function convertToOptionsWithAbsolutePaths(options: CompilerOptions, toAbsolutePath: (path: string) => string) { + const result: CompilerOptions = {}; + const optionsNameMap = getOptionNameMap().optionNameMap; + + for (const name in options) { + if (hasProperty(options, name)) { + result[name] = convertToOptionValueWithAbsolutePaths( + optionsNameMap.get(name.toLowerCase()), + options[name] as CompilerOptionsValue, + toAbsolutePath + ); + } + } + if (result.configFilePath) { + result.configFilePath = toAbsolutePath(result.configFilePath); + } + return result; + } + + function convertToOptionValueWithAbsolutePaths(option: CommandLineOption | undefined, value: CompilerOptionsValue, toAbsolutePath: (path: string) => string) { + if (option) { + if (option.type === "list") { + const values = value as readonly (string | number)[]; + if (option.element.isFilePath && values.length) { + return values.map(toAbsolutePath); + } + } + else if (option.isFilePath) { + return toAbsolutePath(value as string); + } + } + return value; + } + /** * Parse the contents of a config file (tsconfig.json). * @param json The contents of the config file to parse diff --git a/src/testRunner/unittests/tsc/helpers.ts b/src/testRunner/unittests/tsc/helpers.ts index 2ef5f6bc782..5d5f9517e65 100644 --- a/src/testRunner/unittests/tsc/helpers.ts +++ b/src/testRunner/unittests/tsc/helpers.ts @@ -50,8 +50,15 @@ namespace ts { Debug.assert(commandLine.fileNames.length !== 0 || !!configFileName); + const currentDirectory = sys.getCurrentDirectory(); + const getCanonicalFileName = createGetCanonicalFileName(sys.useCaseSensitiveFileNames); + const commandLineOptions = convertToOptionsWithAbsolutePaths( + commandLine.options, + fileName => toPath(fileName, currentDirectory, getCanonicalFileName) + ); + if (configFileName) { - const configParseResult = Debug.assertDefined(parseConfigFileWithSystem(configFileName, commandLine.options, sys, reportDiagnostic)); + const configParseResult = Debug.assertDefined(parseConfigFileWithSystem(configFileName, commandLineOptions, sys, reportDiagnostic)); if (isIncrementalCompilation(configParseResult.options)) { performIncrementalCompilation(sys, configParseResult); } @@ -61,10 +68,16 @@ namespace ts { } else { if (isIncrementalCompilation(commandLine.options)) { - performIncrementalCompilation(sys, commandLine); + performIncrementalCompilation(sys, { + ...commandLine, + options: commandLineOptions + }); } else { - performCompilation(sys, commandLine); + performCompilation(sys, { + ...commandLine, + options: commandLineOptions + }); } } } diff --git a/src/tsc/tsc.ts b/src/tsc/tsc.ts index b6388528223..61fff1f1005 100644 --- a/src/tsc/tsc.ts +++ b/src/tsc/tsc.ts @@ -120,7 +120,12 @@ namespace ts { return sys.exit(ExitStatus.Success); } - const commandLineOptions = commandLine.options; + const currentDirectory = sys.getCurrentDirectory(); + const getCanonicalFileName = createGetCanonicalFileName(sys.useCaseSensitiveFileNames); + const commandLineOptions = convertToOptionsWithAbsolutePaths( + commandLine.options, + fileName => toPath(fileName, currentDirectory, getCanonicalFileName) + ); if (configFileName) { const configParseResult = parseConfigFileWithSystem(configFileName, commandLineOptions, sys, reportDiagnostic)!; // TODO: GH#18217 if (commandLineOptions.showConfig) { @@ -148,7 +153,7 @@ namespace ts { else { if (commandLineOptions.showConfig) { // eslint-disable-next-line no-null/no-null - sys.write(JSON.stringify(convertToTSConfig(commandLine, combinePaths(sys.getCurrentDirectory(), "tsconfig.json"), sys), null, 4) + sys.newLine); + sys.write(JSON.stringify(convertToTSConfig(commandLine, combinePaths(currentDirectory, "tsconfig.json"), sys), null, 4) + sys.newLine); return sys.exit(ExitStatus.Success); } updateReportDiagnostic(commandLineOptions); @@ -157,7 +162,10 @@ namespace ts { createWatchOfFilesAndCompilerOptions(commandLine.fileNames, commandLineOptions); } else if (isIncrementalCompilation(commandLineOptions)) { - performIncrementalCompilation(commandLine); + performIncrementalCompilation({ + ...commandLine, + options: commandLineOptions + }); } else { performCompilation(commandLine.fileNames, /*references*/ undefined, commandLineOptions); diff --git a/tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js b/tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js index bfc2f0ba185..fae2a9ef15e 100644 --- a/tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js +++ b/tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js @@ -4,4 +4,3 @@ exitCode:: 0 //// [/src/project/.tsbuildinfo] file written with same contents -//// [/src/project/src/main.js] file written with same contents From 758bd99879b3074ced6668f9fe68acb6cfdcd7d3 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 14 Oct 2019 15:00:07 -0700 Subject: [PATCH 3/3] Add test for #30457 --- src/testRunner/unittests/tsc/incremental.ts | 18 +++++++- ...-filename-for-buildinfo-on-commandline.js} | 0 ...-filename-for-buildinfo-on-commandline.js} | 0 .../when-passing-rootDir-from-commandline.js | 41 +++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) rename tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/{when-passing-passing-filename-for-buildinfo-on-commandline.js => when-passing-filename-for-buildinfo-on-commandline.js} (100%) rename tests/baselines/reference/tsc/incremental/initial-build/{when-passing-passing-filename-for-buildinfo-on-commandline.js => when-passing-filename-for-buildinfo-on-commandline.js} (100%) create mode 100644 tests/baselines/reference/tsc/incremental/initial-build/when-passing-rootDir-from-commandline.js diff --git a/src/testRunner/unittests/tsc/incremental.ts b/src/testRunner/unittests/tsc/incremental.ts index 1f887024fd0..86d6cefe3b6 100644 --- a/src/testRunner/unittests/tsc/incremental.ts +++ b/src/testRunner/unittests/tsc/incremental.ts @@ -2,7 +2,7 @@ namespace ts { describe("unittests:: tsc:: incremental::", () => { verifyTscIncrementalEdits({ scenario: "incremental", - subScenario: "when passing passing filename for buildinfo on commandline", + subScenario: "when passing filename for buildinfo on commandline", fs: () => loadProjectFromFiles({ "/src/project/src/main.ts": "export const x = 10;", "/src/project/tsconfig.json": utils.dedent` @@ -22,5 +22,21 @@ namespace ts { modifyFs: noop, }] }); + + verifyTsc({ + scenario: "incremental", + subScenario: "when passing rootDir from commandline", + fs: () => loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": utils.dedent` + { + "compilerOptions": { + "incremental": true, + "outDir": "dist", + }, + }`, + }), + commandLineArgs: ["--p", "src/project", "--rootDir", "src/project/src"], + }); }); } diff --git a/tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js b/tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-filename-for-buildinfo-on-commandline.js similarity index 100% rename from tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-passing-filename-for-buildinfo-on-commandline.js rename to tests/baselines/reference/tsc/incremental/incremental-declaration-doesnt-change/when-passing-filename-for-buildinfo-on-commandline.js diff --git a/tests/baselines/reference/tsc/incremental/initial-build/when-passing-passing-filename-for-buildinfo-on-commandline.js b/tests/baselines/reference/tsc/incremental/initial-build/when-passing-filename-for-buildinfo-on-commandline.js similarity index 100% rename from tests/baselines/reference/tsc/incremental/initial-build/when-passing-passing-filename-for-buildinfo-on-commandline.js rename to tests/baselines/reference/tsc/incremental/initial-build/when-passing-filename-for-buildinfo-on-commandline.js diff --git a/tests/baselines/reference/tsc/incremental/initial-build/when-passing-rootDir-from-commandline.js b/tests/baselines/reference/tsc/incremental/initial-build/when-passing-rootDir-from-commandline.js new file mode 100644 index 00000000000..06a57659b5b --- /dev/null +++ b/tests/baselines/reference/tsc/incremental/initial-build/when-passing-rootDir-from-commandline.js @@ -0,0 +1,41 @@ +//// [/lib/initial-buildOutput.txt] +/lib/tsc --p src/project --rootDir src/project/src +exitCode:: 0 + + +//// [/src/project/dist/main.js] +"use strict"; +exports.__esModule = true; +exports.x = 10; + + +//// [/src/project/tsconfig.tsbuildinfo] +{ + "program": { + "fileInfos": { + "../../lib/lib.d.ts": { + "version": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };", + "signature": "3858781397-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ndeclare const console: { log(msg: any): void; };" + }, + "./src/main.ts": { + "version": "-10726455937-export const x = 10;", + "signature": "-6057683066-export declare const x = 10;\r\n" + } + }, + "options": { + "incremental": true, + "outDir": "./dist", + "project": "./", + "rootDir": "./src", + "configFilePath": "./tsconfig.json" + }, + "referencedMap": {}, + "exportedModulesMap": {}, + "semanticDiagnosticsPerFile": [ + "../../lib/lib.d.ts", + "./src/main.ts" + ] + }, + "version": "FakeTSVersion" +} +