Skip to content

Commit 99ef96d

Browse files
committed
feat: Fix the null value verification of the flag
1 parent ce59e2b commit 99ef96d

2 files changed

Lines changed: 61 additions & 4 deletions

File tree

packages/cli/src/args.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,20 +147,23 @@ export function parseFlags(argv: string[], options: OptionDef[]): GlobalFlags {
147147
);
148148
}
149149

150+
// Switch-style flags (--quiet, --dry-run): no value. Value flags need a non-flag next token.
150151
if (schema.booleans.has(camelKey)) {
151152
(flags as Record<string, unknown>)[camelKey] = true;
152153
i++;
153154
continue;
154155
}
155156

157+
// --prompt <text>, --watermark <bool>, …
156158
if (value === undefined) {
157159
i++;
158-
value = argv[i];
160+
const next = argv[i];
161+
if (next === undefined || next.startsWith("-")) {
162+
throw new BailianError(`Flag --${key} requires a value.`, ExitCode.USAGE);
163+
}
164+
value = next;
159165
}
160166

161-
if (value === undefined)
162-
throw new BailianError(`Flag --${key} requires a value.`, ExitCode.USAGE);
163-
164167
if (schema.arrays.has(camelKey)) {
165168
const arr = (flags as Record<string, unknown>)[camelKey] as string[] | undefined;
166169
if (arr) arr.push(value);

packages/cli/tests/args.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const IMAGE_GENERATE_OPTIONS = [
77
{ flag: "--prompt <text>", description: "Image description", required: true },
88
{ flag: "--model <model>", description: "Model ID" },
99
{ flag: "--watermark <bool>", description: BOOL_FLAG_WATERMARK },
10+
{ flag: "--no-wait", description: "Return task ID immediately without waiting" },
1011
];
1112

1213
test("parseFlags rejects unknown long flags", () => {
@@ -39,3 +40,56 @@ test("parseFlags accepts defined command and global flags", () => {
3940
expect(flags.prompt).toBe("cat");
4041
expect(flags.watermark).toBe("false");
4142
});
43+
44+
test("parseFlags rejects value flag when next token is another flag", () => {
45+
const opts = [...GLOBAL_OPTIONS, ...IMAGE_GENERATE_OPTIONS];
46+
for (const argv of [
47+
["--watermark", "--prompt", "cat"],
48+
["--watermark", "-h"],
49+
["--prompt", "cat", "--watermark", "--model", "qwen-image-2.0"],
50+
]) {
51+
expect(() => parseFlags(argv, opts)).toThrowError(
52+
expect.objectContaining({
53+
name: "BailianError",
54+
exitCode: ExitCode.USAGE,
55+
message: expect.stringContaining("Flag --watermark requires a value"),
56+
}),
57+
);
58+
}
59+
});
60+
61+
test("parseFlags rejects trailing value flag without value", () => {
62+
expect(() =>
63+
parseFlags(["--prompt", "cat", "--watermark"], [...GLOBAL_OPTIONS, ...IMAGE_GENERATE_OPTIONS]),
64+
).toThrowError(
65+
expect.objectContaining({
66+
message: expect.stringContaining("Flag --watermark requires a value"),
67+
}),
68+
);
69+
});
70+
71+
test("parseFlags allows boolean flags without values adjacent to other flags", () => {
72+
const opts = [...GLOBAL_OPTIONS, ...IMAGE_GENERATE_OPTIONS];
73+
const flags = parseFlags(
74+
["--quiet", "--dry-run", "--no-wait", "--prompt", "cat", "--watermark", "false"],
75+
opts,
76+
);
77+
expect(flags.quiet).toBe(true);
78+
expect(flags.dryRun).toBe(true);
79+
expect(flags.noWait).toBe(true);
80+
expect(flags.prompt).toBe("cat");
81+
expect(flags.watermark).toBe("false");
82+
});
83+
84+
test("parseFlags does not treat the next flag as a boolean flag value", () => {
85+
const opts = [...GLOBAL_OPTIONS, ...IMAGE_GENERATE_OPTIONS];
86+
expect(() => parseFlags(["--dry-run", "--prompt"], opts)).toThrowError(
87+
expect.objectContaining({
88+
message: expect.stringContaining("Flag --prompt requires a value"),
89+
}),
90+
);
91+
// --dry-run is boolean: no value check; parsing continues to --prompt.
92+
const flags = parseFlags(["--dry-run", "--prompt", "cat"], opts);
93+
expect(flags.dryRun).toBe(true);
94+
expect(flags.prompt).toBe("cat");
95+
});

0 commit comments

Comments
 (0)