Skip to content

Commit f7e95b9

Browse files
authored
Made boolean CLI option values optional, if no value is supplied they default to true (#446)
1 parent 9b558d2 commit f7e95b9

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

src/CommandLineParser.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ type ParseResult<T> =
1010
{ isValid: true; result: T }
1111
| { isValid: false, errorMessage: string};
1212

13+
type ArgumentParseResult<T> =
14+
{ isValid: true; result: T; increment?: number }
15+
| { isValid: false, errorMessage: string };
16+
1317
interface ParsedCommandLine extends ts.ParsedCommandLine {
1418
options: CompilerOptions;
1519
}
@@ -190,10 +194,11 @@ function parseTSTLOptions(commandLine: ts.ParsedCommandLine, args: string[]): CL
190194
const argumentName = args[i].substr(2);
191195
const option = optionDeclarations[argumentName];
192196
if (option) {
193-
const argumentResult = getArgumentValue(argumentName, args[i + 1]);
194-
i++; // Skip the value from being considered as argument name
197+
const argumentResult = getArgumentValue(argumentName, i, args);
195198
if (argumentResult.isValid === true) {
196199
result[argumentName] = argumentResult.result;
200+
// Skip value from being considered as option
201+
i += argumentResult.increment !== undefined ? argumentResult.increment : 1;
197202
} else {
198203
return { isValid: false, errorMessage: argumentResult.errorMessage };
199204
}
@@ -209,10 +214,11 @@ function parseTSTLOptions(commandLine: ts.ParsedCommandLine, args: string[]): CL
209214
}
210215

211216
if (argumentName) {
212-
const argumentResult = getArgumentValue(argumentName, args[i + 1]);
213-
i++; // Skip the value from being considered as argument name
217+
const argumentResult = getArgumentValue(argumentName, i, args);
214218
if (argumentResult.isValid === true) {
215219
result[argumentName] = argumentResult.result;
220+
// Skip value from being considered as option
221+
i += argumentResult.increment !== undefined ? argumentResult.increment : 1;
216222
} else {
217223
return { isValid: false, errorMessage: argumentResult.errorMessage };
218224
}
@@ -232,13 +238,24 @@ function parseTSTLOptions(commandLine: ts.ParsedCommandLine, args: string[]): CL
232238
return { isValid: true, result: commandLine };
233239
}
234240

235-
function getArgumentValue(argumentName: string, argument: string): ParseResult<string | boolean>
241+
function getArgumentValue(
242+
argumentName: string,
243+
argumentIndex: number,
244+
args: string[]
245+
): ArgumentParseResult<string | boolean>
236246
{
247+
const option = optionDeclarations[argumentName];
248+
const argument = args[argumentIndex + 1];
249+
250+
if (option.type === "boolean" && (argument === undefined || argument.startsWith("-"))) {
251+
// Set boolean arguments without supplied value to true
252+
return { isValid: true, result: true, increment: 0 };
253+
}
254+
237255
if (argument === undefined) {
238256
return { isValid: false, errorMessage: `Missing value for parameter ${argumentName}`};
239257
}
240258

241-
const option = optionDeclarations[argumentName];
242259
const value = readValue(argument, option.type, argumentName);
243260

244261
if (option.choices) {

test/unit/commandLineParser.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ export class CommandLineParserTests
6666
@TestCase([""], false)
6767
@TestCase(["--noHeader", "true"], true)
6868
@TestCase(["--noHeader", "false"], false)
69+
@TestCase(["--noHeader"], true)
70+
@TestCase(["--noHeader", "--noHoisting"], true)
6971
@Test("CLI parser noHeader")
7072
public cliParserNoHeader(args: string[], expected: boolean): void {
7173
const result = parseCommandLine(args);
@@ -76,6 +78,21 @@ export class CommandLineParserTests
7678
}
7779
}
7880

81+
@TestCase([""], false)
82+
@TestCase(["--noHoisting", "true"], true)
83+
@TestCase(["--noHoisting", "false"], false)
84+
@TestCase(["--noHoisting"], true)
85+
@TestCase(["--noHoisting", "--noHeader"], true)
86+
@Test("CLI parser noHoisting")
87+
public cliParserNoHoisting(args: string[], expected: boolean): void {
88+
const result = parseCommandLine(args);
89+
if (result.isValid === true) {
90+
Expect(result.result.options.noHoisting).toBe(expected);
91+
} else {
92+
Expect(result.isValid).toBeTruthy();
93+
}
94+
}
95+
7996
@TestCase([""], false)
8097
@TestCase(["--project", "tsconfig.json"], true)
8198
@TestCase(["-p", "tsconfig.json"], true)
@@ -89,6 +106,21 @@ export class CommandLineParserTests
89106
}
90107
}
91108

109+
@Test("CLI Parser Multiple Options")
110+
public cliParserMultipleOptions(): void {
111+
const commandLine = "--project tsconfig.json --noHeader --noHoisting -lt 5.3";
112+
const result = parseCommandLine(commandLine.split(" "));
113+
114+
if (result.isValid === true) {
115+
Expect(result.result.options.project).toBeDefined();
116+
Expect(result.result.options.noHeader).toBe(true);
117+
Expect(result.result.options.noHoisting).toBe(true);
118+
Expect(result.result.options.luaTarget).toBe(LuaTarget.Lua53);
119+
} else {
120+
Expect(result.isValid).toBeTruthy();
121+
}
122+
}
123+
92124
@TestCase([""], false)
93125
@TestCase(["--help"], true)
94126
@TestCase(["-h"], true)

0 commit comments

Comments
 (0)