Skip to content

Make sure commandline options are absolute paths so they dont conflict with options from tsbuild info #34403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 1 addition & 35 deletions src/compiler/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand Down Expand Up @@ -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,
Expand Down
35 changes: 35 additions & 0 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't the main loop already run toAbsolutePath on configFilePath with all the other properties?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configFilePath is not in optionDeclarations so it wont get normalized.

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
Expand Down
8 changes: 6 additions & 2 deletions src/harness/fakes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ ${indentText}${text}`;

export const version = "FakeTSVersion";

export function patchSolutionBuilderHost(host: ts.SolutionBuilderHost<ts.BuilderProgram>, sys: System) {
export function patchHostForBuildInfoReadWrite(host: ts.CompilerHost | ts.SolutionBuilderHost<ts.BuilderProgram>) {
const originalReadFile = host.readFile;
host.readFile = (path, encoding) => {
const value = originalReadFile.call(host, path, encoding);
Expand All @@ -537,14 +537,18 @@ ${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);
buildInfo.version = version;
originalWriteFile.call(host, fileName, ts.getBuildInfoText(buildInfo), writeByteOrderMark);
};
}
}

export function patchSolutionBuilderHost(host: ts.SolutionBuilderHost<ts.BuilderProgram>, sys: System) {
patchHostForBuildInfoReadWrite(host);

ts.Debug.assert(host.now === undefined);
host.now = () => new Date(sys.vfs.time());
Expand Down
1 change: 1 addition & 0 deletions src/testRunner/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion src/testRunner/unittests/tsbuild/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand Down
23 changes: 20 additions & 3 deletions src/testRunner/unittests/tsc/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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
});
}
}
}
Expand All @@ -79,6 +92,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));
Expand All @@ -102,7 +116,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,
Expand Down
42 changes: 42 additions & 0 deletions src/testRunner/unittests/tsc/incremental.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace ts {
describe("unittests:: tsc:: incremental::", () => {
verifyTscIncrementalEdits({
scenario: "incremental",
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`
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
},
"include": [
"src/**/*.ts"
]
}`,
}),
commandLineArgs: ["--incremental", "--p", "src/project", "--tsBuildInfoFile", "src/project/.tsbuildinfo"],
incrementalScenarios: [{
buildKind: BuildKind.IncrementalDtsUnchanged,
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"],
});
});
}
14 changes: 11 additions & 3 deletions src/tsc/tsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//// [/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
Original file line number Diff line number Diff line change
@@ -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-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\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;


Original file line number Diff line number Diff line change
@@ -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-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\ndeclare const console: { log(msg: any): void; };",
"signature": "3858781397-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }\ninterface ReadonlyArray<T> {}\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"
}