Skip to content

Commit 132a437

Browse files
authored
fix(flags): allow options after variadic options (#865)
Fixes #716
1 parent c518882 commit 132a437

File tree

3 files changed

+56
-6
lines changed

3 files changed

+56
-6
lines changed

command/test/option/variadic_test.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,23 @@ test("command optionVariadic exactLastOptionalVariadic", async () => {
113113

114114
assertEquals(
115115
options,
116-
// @TODO: fix variadic types.
117-
// deno-lint-ignore no-explicit-any
118-
{ variadicOption: [1, "abc", true, false, true, false] as any },
116+
{ variadicOption: [1, "abc", true, false, true, false] },
117+
);
118+
assertEquals(args, []);
119+
});
120+
121+
test("should allow passing an option after an variadic option", async () => {
122+
const { options, args } = await new Command()
123+
.option("-v, --variadic-option <...value:string>", "description ...")
124+
.option("-s, --string <value:string>", "description ...")
125+
.parse(["-v", "1", "abc", "-s", "string value"]);
126+
127+
assertEquals(
128+
options,
129+
{
130+
variadicOption: ["1", "abc"],
131+
string: "string value",
132+
},
119133
);
120134
assertEquals(args, []);
121135
});

flags/flags.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -500,14 +500,19 @@ function parseArgs<TFlagOptions extends FlagOptions>(
500500
if (!option.args?.length) {
501501
return false;
502502
}
503-
const nextValue = currentValue ?? args[argsIndex + 1];
503+
const nextValue = next();
504504
if (!nextValue) {
505505
return false;
506506
}
507507
if (option.args.length > 1 && optionArgsIndex >= option.args.length) {
508508
return false;
509509
}
510-
if (!arg.optional) {
510+
let nextOption: FlagOptions | undefined;
511+
if (
512+
!arg.optional &&
513+
(!arg.variadic ||
514+
!(nextOption = getOption(opts.flags ?? [], nextValue)))
515+
) {
511516
return true;
512517
}
513518
// require optional values to be called with an equal sign: foo=bar
@@ -517,7 +522,10 @@ function parseArgs<TFlagOptions extends FlagOptions>(
517522
) {
518523
return false;
519524
}
520-
if (arg.optional || arg.variadic) {
525+
if (
526+
(arg.optional || arg.variadic) &&
527+
!(nextOption ?? getOption(opts.flags ?? [], nextValue))
528+
) {
521529
return nextValue[0] !== "-" ||
522530
typeof currentValue !== "undefined" ||
523531
(arg.type === "number" && !isNaN(Number(nextValue)));

flags/test/option/variadic_test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,31 @@ test("flags optionVariadic exactLastOptionalVariadic", () => {
168168
assertEquals(unknown, []);
169169
assertEquals(literal, []);
170170
});
171+
172+
test("should allow passing an option after an variadic option", () => {
173+
const { flags, unknown, literal } = parseFlags([
174+
"-e",
175+
"1",
176+
"abc",
177+
"-s",
178+
"string value",
179+
], {
180+
flags: [{
181+
name: "variadic-option",
182+
type: "string",
183+
aliases: ["e"],
184+
variadic: true,
185+
}, {
186+
name: "string",
187+
aliases: ["s"],
188+
type: "string",
189+
}],
190+
});
191+
192+
assertEquals(flags, {
193+
variadicOption: ["1", "abc"],
194+
string: "string value",
195+
});
196+
assertEquals(unknown, []);
197+
assertEquals(literal, []);
198+
});

0 commit comments

Comments
 (0)