From 99ef96d20981e9b142f086214628e6f53cd4514f Mon Sep 17 00:00:00 2001 From: qcq01083097 Date: Fri, 5 Jun 2026 11:14:17 +0800 Subject: [PATCH] feat: Fix the null value verification of the flag --- packages/cli/src/args.ts | 11 ++++--- packages/cli/tests/args.test.ts | 54 +++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/args.ts b/packages/cli/src/args.ts index 3065a4e..16320cb 100644 --- a/packages/cli/src/args.ts +++ b/packages/cli/src/args.ts @@ -147,20 +147,23 @@ export function parseFlags(argv: string[], options: OptionDef[]): GlobalFlags { ); } + // Switch-style flags (--quiet, --dry-run): no value. Value flags need a non-flag next token. if (schema.booleans.has(camelKey)) { (flags as Record)[camelKey] = true; i++; continue; } + // --prompt , --watermark , … if (value === undefined) { i++; - value = argv[i]; + const next = argv[i]; + if (next === undefined || next.startsWith("-")) { + throw new BailianError(`Flag --${key} requires a value.`, ExitCode.USAGE); + } + value = next; } - if (value === undefined) - throw new BailianError(`Flag --${key} requires a value.`, ExitCode.USAGE); - if (schema.arrays.has(camelKey)) { const arr = (flags as Record)[camelKey] as string[] | undefined; if (arr) arr.push(value); diff --git a/packages/cli/tests/args.test.ts b/packages/cli/tests/args.test.ts index 890deeb..b32d208 100644 --- a/packages/cli/tests/args.test.ts +++ b/packages/cli/tests/args.test.ts @@ -7,6 +7,7 @@ const IMAGE_GENERATE_OPTIONS = [ { flag: "--prompt ", description: "Image description", required: true }, { flag: "--model ", description: "Model ID" }, { flag: "--watermark ", description: BOOL_FLAG_WATERMARK }, + { flag: "--no-wait", description: "Return task ID immediately without waiting" }, ]; test("parseFlags rejects unknown long flags", () => { @@ -39,3 +40,56 @@ test("parseFlags accepts defined command and global flags", () => { expect(flags.prompt).toBe("cat"); expect(flags.watermark).toBe("false"); }); + +test("parseFlags rejects value flag when next token is another flag", () => { + const opts = [...GLOBAL_OPTIONS, ...IMAGE_GENERATE_OPTIONS]; + for (const argv of [ + ["--watermark", "--prompt", "cat"], + ["--watermark", "-h"], + ["--prompt", "cat", "--watermark", "--model", "qwen-image-2.0"], + ]) { + expect(() => parseFlags(argv, opts)).toThrowError( + expect.objectContaining({ + name: "BailianError", + exitCode: ExitCode.USAGE, + message: expect.stringContaining("Flag --watermark requires a value"), + }), + ); + } +}); + +test("parseFlags rejects trailing value flag without value", () => { + expect(() => + parseFlags(["--prompt", "cat", "--watermark"], [...GLOBAL_OPTIONS, ...IMAGE_GENERATE_OPTIONS]), + ).toThrowError( + expect.objectContaining({ + message: expect.stringContaining("Flag --watermark requires a value"), + }), + ); +}); + +test("parseFlags allows boolean flags without values adjacent to other flags", () => { + const opts = [...GLOBAL_OPTIONS, ...IMAGE_GENERATE_OPTIONS]; + const flags = parseFlags( + ["--quiet", "--dry-run", "--no-wait", "--prompt", "cat", "--watermark", "false"], + opts, + ); + expect(flags.quiet).toBe(true); + expect(flags.dryRun).toBe(true); + expect(flags.noWait).toBe(true); + expect(flags.prompt).toBe("cat"); + expect(flags.watermark).toBe("false"); +}); + +test("parseFlags does not treat the next flag as a boolean flag value", () => { + const opts = [...GLOBAL_OPTIONS, ...IMAGE_GENERATE_OPTIONS]; + expect(() => parseFlags(["--dry-run", "--prompt"], opts)).toThrowError( + expect.objectContaining({ + message: expect.stringContaining("Flag --prompt requires a value"), + }), + ); + // --dry-run is boolean: no value check; parsing continues to --prompt. + const flags = parseFlags(["--dry-run", "--prompt", "cat"], opts); + expect(flags.dryRun).toBe(true); + expect(flags.prompt).toBe("cat"); +});