Skip to content

Commit 960b4d0

Browse files
Janne252Perryvw
authored andcommitted
Fix tsconfig overridden by defaults (#165)
* Common type of yargs options object Export optionDeclarations so that tests can reference them Parse cmd args without defaults to prevent overriding tsconfig values Apply defaults to the options last Support for spaces in project filepath: Remove double quotes from project file path when present * Upgrade yargs from 11.1.1 to 12.0.1, reason: Missing default for a boolean arg is read as default: false This seems to be fixed in 12.0.1. * Test for verifying a mixed configuration that consists of: Command line args, tsconfig.json, and TSTL defaults is parsed properly. * More sensible test paths
1 parent afd66f5 commit 960b4d0

File tree

5 files changed

+141
-54
lines changed

5 files changed

+141
-54
lines changed

package-lock.json

Lines changed: 52 additions & 44 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@
4242
},
4343
"dependencies": {
4444
"typescript": "^2.9.2",
45-
"yargs": "^11.1.0"
45+
"yargs": "^12.0.1"
4646
},
4747
"devDependencies": {
4848
"@types/glob": "^5.0.35",
4949
"@types/node": "^9.6.23",
50-
"@types/yargs": "^11.0.0",
50+
"@types/yargs": "^11.1.1",
5151
"alsatian": "^2.2.1",
5252
"circular-json": "^0.5.5",
5353
"codecov": "3.0.2",

src/CommandLineParser.ts

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ export class CLIError extends Error {
1717

1818
}
1919

20-
const optionDeclarations: { [key: string]: yargs.Options } = {
20+
export interface YargsOptions {
21+
[key: string]: yargs.Options;
22+
}
23+
24+
export const optionDeclarations: YargsOptions = {
2125
luaLibImport: {
2226
choices: ["inline", "require", "none"],
2327
default: "inline",
@@ -38,11 +42,33 @@ const optionDeclarations: { [key: string]: yargs.Options } = {
3842
},
3943
};
4044

45+
/**
46+
* Removes defaults from the arguments.
47+
* Returns a tuple where [0] is a copy of the options without defaults and [1] is the extracted defaults.
48+
*/
49+
function getYargOptionsWithoutDefaults(options: YargsOptions): [YargsOptions, yargs.Arguments] {
50+
// options is a deep object, Object.assign or {...options} still keeps the referece
51+
const copy = JSON.parse(JSON.stringify(options));
52+
53+
const optionDefaults: yargs.Arguments = {_: null, $0: null};
54+
for (const optionName in copy) {
55+
const section = copy[optionName];
56+
57+
optionDefaults[optionName] = section.default;
58+
delete section.default;
59+
}
60+
61+
return [copy, optionDefaults];
62+
}
63+
4164
/**
4265
* Pares the supplied arguments.
4366
* The result will include arguments supplied via CLI and arguments from tsconfig.
4467
*/
4568
export function parseCommandLine(args: string[]): ParsedCommandLine {
69+
// Get a copy of the options without defaults to prevent defaults overriding project config
70+
const [tstlOptions, tstlDefaults] = getYargOptionsWithoutDefaults(optionDeclarations);
71+
4672
const parsedArgs = yargs
4773
.usage("Syntax: tstl [options] [files...]\n\n" +
4874
"In addition to the options listed below you can also pass options" +
@@ -51,7 +77,7 @@ export function parseCommandLine(args: string[]): ParsedCommandLine {
5177
.example("tstl path/to/file.ts [...]", "Compile files")
5278
.example("tstl -p path/to/tsconfig.json", "Compile project")
5379
.wrap(yargs.terminalWidth())
54-
.options(optionDeclarations)
80+
.options(tstlOptions)
5581
.fail((msg, err) => {
5682
throw new CLIError(msg);
5783
})
@@ -82,6 +108,9 @@ export function parseCommandLine(args: string[]): ParsedCommandLine {
82108
// Add TSTL options from tsconfig
83109
addTSTLOptions(commandLine);
84110

111+
// Add TSTL defaults last
112+
addTSTLOptions(commandLine, tstlDefaults);
113+
85114
// Run diagnostics again to check for errors in tsconfig
86115
runDiagnostics(commandLine);
87116

@@ -158,13 +187,15 @@ export function findConfigFile(commandLine: ts.ParsedCommandLine): void {
158187
if (!commandLine.options.project) {
159188
throw new CLIError(`error no base path provided, could not find config.`);
160189
}
161-
let configPath;
162-
/* istanbul ignore else: Testing else part is not really possible via automated tests */
163-
if (path.isAbsolute(commandLine.options.project)) {
164-
configPath = commandLine.options.project;
165-
} else {
190+
let configPath = commandLine.options.project;
191+
// If the project path is wrapped in double quotes, remove them
192+
if (/^".*"$/.test(configPath)) {
193+
configPath = configPath.substring(1, configPath.length - 1);
194+
}
195+
/* istanbul ignore if: Testing else part is not really possible via automated tests */
196+
if (!path.isAbsolute(configPath)) {
166197
// TODO check if commandLine.options.project can even contain non absolute paths
167-
configPath = path.join(process.cwd(), commandLine.options.project);
198+
configPath = path.join(process.cwd(), configPath);
168199
}
169200
if (fs.statSync(configPath).isDirectory()) {
170201
configPath = path.join(configPath, "tsconfig.json");
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Expect, Test, TestCase, Teardown } from "alsatian";
2+
import * as path from 'path';
3+
import * as fs from 'fs';
4+
import * as ts from "typescript";
5+
6+
import { CompilerOptions, findConfigFile, parseCommandLine, ParsedCommandLine, optionDeclarations } from "../../../../../src/CommandLineParser";
7+
import { LuaLibImportKind } from "../../../../../src/Transpiler";
8+
9+
export class MixedConfigurationTests {
10+
11+
@Test("tsconfig.json mixed with cmd line args")
12+
public tsconfigMixedWithCmdLineArgs() {
13+
const rootPath = __dirname;
14+
const tsConfigPath = path.join(rootPath, "project-tsconfig.json");
15+
const expectedTsConfig = ts.parseJsonConfigFileContent(
16+
ts.parseConfigFileTextToJson(tsConfigPath, fs.readFileSync(tsConfigPath).toString()).config,
17+
ts.sys,
18+
path.dirname(tsConfigPath)
19+
);
20+
21+
const parsedArgs = parseCommandLine([
22+
"-p",
23+
`"${tsConfigPath}"`,
24+
"--luaLibImport",
25+
LuaLibImportKind.Inline,
26+
`${path.join(rootPath, 'test.ts')}`,
27+
]);
28+
29+
Expect(parsedArgs.options).toEqual(<CompilerOptions>{
30+
...expectedTsConfig.options,
31+
// Overridden by cmd args (set to "none" in project-tsconfig.json)
32+
luaLibImport: LuaLibImportKind.Inline,
33+
// Only set in tsconfig, TSTL default is "JIT"
34+
luaTarget: "5.1",
35+
// Only present in TSTL dfaults
36+
noHeader: optionDeclarations["noHeader"].default,
37+
project: tsConfigPath
38+
});
39+
}
40+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"outDir": "./dist/foo/bar",
4+
"rootDir": "./src/foo/bar"
5+
},
6+
"luaTarget": "5.1",
7+
"luaLibImport": "none"
8+
}

0 commit comments

Comments
 (0)