From 408ecbb6aad7cddd52b7e504847e0316bc4b2cb4 Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Sat, 26 Oct 2024 13:27:56 -0300 Subject: [PATCH 01/10] fix: short params parsing within zig-clap fork --- src/deps/zig-clap/clap/streaming.zig | 105 ++++++++++++++++++--------- 1 file changed, 71 insertions(+), 34 deletions(-) diff --git a/src/deps/zig-clap/clap/streaming.zig b/src/deps/zig-clap/clap/streaming.zig index e861325a7ee5ed..89f87b6975f653 100644 --- a/src/deps/zig-clap/clap/streaming.zig +++ b/src/deps/zig-clap/clap/streaming.zig @@ -118,10 +118,31 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { } return null; }, - .short => return try parser.chainging(.{ - .arg = arg, - .index = 0, - }), + .short => { + if (arg.len == 1) { + // Single short flag + return parser.parseShortFlag(arg[0]) catch |err1| { + if (err1 == error.InvalidArgument) { + if (warn_on_unrecognized_flag) { + Output.warn("unrecognized flag: -{c}\n", .{arg[0]}); + Output.flush(); + } + // Continue parsing after unrecognized flag + return parser.next(); + } + return err1; + }; + } else { + // Multiple short flags combined + parser.state = .{ + .chaining = .{ + .arg = arg, + .index = 0, + }, + }; + return try parser.chainging(parser.state.chaining); + } + }, .positional => if (parser.positionalParam()) |param| { // If we find a positional with the value `--` then we // interpret the rest of the arguments as positional @@ -140,51 +161,67 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { } } + fn parseShortFlag(parser: *@This(), flag: u8) ArgError!Arg(Id) { + for (parser.params) |*param| { + const short = param.names.short orelse continue; + if (short != flag) continue; + + if (param.takes_value == .none) { + return Arg(Id){ .param = param }; + } + + const value = parser.iter.next() orelse { + return parser.err(&[_]u8{flag}, .{ .short = flag }, error.MissingValue); + }; + return Arg(Id){ .param = param, .value = value }; + } + + return parser.err(&[_]u8{flag}, .{ .short = flag }, error.InvalidArgument); + } + fn chainging(parser: *@This(), state: State.Chaining) ArgError!?Arg(Id) { const arg = state.arg; const index = state.index; - const next_index = index + 1; + const flag = arg[index]; - for (parser.params) |*param| { - const short = param.names.short orelse continue; - if (short != arg[index]) - continue; - - // Before we return, we have to set the new state of the clap - defer { - if (arg.len <= next_index or param.takes_value != .none) { - parser.state = .normal; - } else { + const result = parser.parseShortFlag(flag) catch |err1| { + if (err1 == error.InvalidArgument) { + if (warn_on_unrecognized_flag) { + Output.warn("unrecognized flag: -{c}\n", .{flag}); + Output.flush(); + } + // Move to the next flag in the chain + const next_index = index + 1; + if (next_index < arg.len) { parser.state = .{ .chaining = .{ .arg = arg, .index = next_index, }, }; + return parser.chainging(parser.state.chaining); + } else { + parser.state = .normal; + return parser.next(); } } + return err1; + }; - const next_is_eql = if (next_index < arg.len) arg[next_index] == '=' else false; - if (param.takes_value == .none or param.takes_value == .one_optional) { - if (next_is_eql and param.takes_value == .none) - return parser.err(arg, .{ .short = short }, error.DoesntTakeValue); - return Arg(Id){ .param = param }; - } - - if (arg.len <= next_index) { - const value = parser.iter.next() orelse - return parser.err(arg, .{ .short = short }, error.MissingValue); - - return Arg(Id){ .param = param, .value = value }; - } - - if (next_is_eql) - return Arg(Id){ .param = param, .value = arg[next_index + 1 ..] }; - - return Arg(Id){ .param = param, .value = arg[next_index..] }; + // Prepare for the next flag in the chain + const next_index = index + 1; + if (next_index < arg.len) { + parser.state = .{ + .chaining = .{ + .arg = arg, + .index = next_index, + }, + }; + } else { + parser.state = .normal; } - return parser.err(arg, .{ .short = arg[index] }, error.InvalidArgument); + return result; } fn positionalParam(parser: *@This()) ?*const clap.Param(Id) { From 26c228d23921a67a4853ddc3b8276819cfdf5f5b Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Sat, 9 Nov 2024 19:44:36 -0300 Subject: [PATCH 02/10] refactor: maintain compatibility and proper error handling --- src/deps/zig-clap/clap/streaming.zig | 88 ++++++++++++++++------------ 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/src/deps/zig-clap/clap/streaming.zig b/src/deps/zig-clap/clap/streaming.zig index 89f87b6975f653..f873fc704cb2fe 100644 --- a/src/deps/zig-clap/clap/streaming.zig +++ b/src/deps/zig-clap/clap/streaming.zig @@ -120,28 +120,34 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { }, .short => { if (arg.len == 1) { - // Single short flag - return parser.parseShortFlag(arg[0]) catch |err1| { - if (err1 == error.InvalidArgument) { - if (warn_on_unrecognized_flag) { - Output.warn("unrecognized flag: -{c}\n", .{arg[0]}); - Output.flush(); - } - // Continue parsing after unrecognized flag - return parser.next(); + for (parser.params) |*param| { + const short = param.names.short orelse continue; + if (short != arg[0]) continue; + + if (param.takes_value == .none) { + return Arg(Id){ .param = param }; } - return err1; - }; - } else { - // Multiple short flags combined - parser.state = .{ - .chaining = .{ - .arg = arg, - .index = 0, - }, - }; - return try parser.chainging(parser.state.chaining); + + const value = parser.iter.next() orelse { + return parser.err(arg, .{ .short = arg[0] }, error.MissingValue); + }; + return Arg(Id){ .param = param, .value = value }; + } + + if (warn_on_unrecognized_flag) { + Output.warn("unrecognized flag: -{s}\n", .{arg}); + Output.flush(); + } + return parser.next(); } + + parser.state = .{ + .chaining = .{ + .arg = arg, + .index = 0, + }, + }; + return try parser.chainging(parser.state.chaining); }, .positional => if (parser.positionalParam()) |param| { // If we find a positional with the value `--` then we @@ -184,14 +190,12 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { const index = state.index; const flag = arg[index]; - const result = parser.parseShortFlag(flag) catch |err1| { - if (err1 == error.InvalidArgument) { - if (warn_on_unrecognized_flag) { - Output.warn("unrecognized flag: -{c}\n", .{flag}); - Output.flush(); - } - // Move to the next flag in the chain - const next_index = index + 1; + for (parser.params) |*param| { + const short = param.names.short orelse continue; + if (short != flag) continue; + + const next_index = index + 1; + if (param.takes_value == .none) { if (next_index < arg.len) { parser.state = .{ .chaining = .{ @@ -199,16 +203,28 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { .index = next_index, }, }; - return parser.chainging(parser.state.chaining); } else { parser.state = .normal; - return parser.next(); } + return Arg(Id){ .param = param }; } - return err1; - }; - // Prepare for the next flag in the chain + const value = if (next_index < arg.len) + arg[next_index..] + else + parser.iter.next() orelse { + return parser.err(arg, .{ .short = flag }, error.MissingValue); + }; + + parser.state = .normal; + return Arg(Id){ .param = param, .value = value }; + } + + if (warn_on_unrecognized_flag) { + Output.warn("unrecognized flag: -{c}\n", .{flag}); + Output.flush(); + } + const next_index = index + 1; if (next_index < arg.len) { parser.state = .{ @@ -217,11 +233,11 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { .index = next_index, }, }; - } else { - parser.state = .normal; + return parser.chainging(parser.state.chaining); } - return result; + parser.state = .normal; + return parser.next(); } fn positionalParam(parser: *@This()) ?*const clap.Param(Id) { From c16b7daa3f0c6148f04d76c25fbd7b7f56302af7 Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Sat, 9 Nov 2024 19:52:02 -0300 Subject: [PATCH 03/10] test: push 7114 regression test --- test/regression/issue/07114.test.ts | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 test/regression/issue/07114.test.ts diff --git a/test/regression/issue/07114.test.ts b/test/regression/issue/07114.test.ts new file mode 100644 index 00000000000000..de528f4496a250 --- /dev/null +++ b/test/regression/issue/07114.test.ts @@ -0,0 +1,38 @@ +import { expect, test } from "bun:test"; +import { bunEnv, bunExe, tempDirWithFiles } from "harness"; + +test("short flags should be properly parsed", () => { + const dir = tempDirWithFiles("07114", { + "package.json": JSON.stringify({ + name: "short-flags-test", + version: "0.0.0", + }), + }); + + // Test single short flag + const singleFlag = Bun.spawnSync({ + cmd: [bunExe(), "-t"], + cwd: dir, + env: bunEnv, + stderr: "pipe", + }); + expect(singleFlag.stderr.toString()).not.toContain("Invalid argument '-t'"); + + // Test multiple combined short flags + const multipleFlags = Bun.spawnSync({ + cmd: [bunExe(), "-abc"], + cwd: dir, + env: bunEnv, + stderr: "pipe", + }); + expect(multipleFlags.stderr.toString()).not.toContain("Invalid argument"); + + // Test short flag with value + const flagWithValue = Bun.spawnSync({ + cmd: [bunExe(), "-p", "3000"], + cwd: dir, + env: bunEnv, + stderr: "pipe", + }); + expect(flagWithValue.stderr.toString()).not.toContain("Invalid argument '-p'"); +}); From 18e7b76afc0bc70f8bdad0c29d88b4af6da6e004 Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Sat, 9 Nov 2024 20:59:22 -0300 Subject: [PATCH 04/10] chore: fix typo chainging -> chaining --- src/deps/zig-clap/clap/streaming.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/deps/zig-clap/clap/streaming.zig b/src/deps/zig-clap/clap/streaming.zig index f873fc704cb2fe..efe7e4319a3f1a 100644 --- a/src/deps/zig-clap/clap/streaming.zig +++ b/src/deps/zig-clap/clap/streaming.zig @@ -53,7 +53,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { pub fn next(parser: *@This()) ArgError!?Arg(Id) { switch (parser.state) { .normal => return try parser.normal(), - .chaining => |state| return try parser.chainging(state), + .chaining => |state| return try parser.chaining(state), .rest_are_positional => { const param = parser.positionalParam() orelse unreachable; const value = parser.iter.next() orelse return null; @@ -147,7 +147,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { .index = 0, }, }; - return try parser.chainging(parser.state.chaining); + return try parser.chaining(parser.state.chaining); }, .positional => if (parser.positionalParam()) |param| { // If we find a positional with the value `--` then we @@ -185,7 +185,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { return parser.err(&[_]u8{flag}, .{ .short = flag }, error.InvalidArgument); } - fn chainging(parser: *@This(), state: State.Chaining) ArgError!?Arg(Id) { + fn chaining(parser: *@This(), state: State.Chaining) ArgError!?Arg(Id) { const arg = state.arg; const index = state.index; const flag = arg[index]; @@ -233,7 +233,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { .index = next_index, }, }; - return parser.chainging(parser.state.chaining); + return parser.chaining(parser.state.chaining); } parser.state = .normal; From 65e2e07d891dcd36aa6d72793c92eb5865eec04e Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Mon, 11 Nov 2024 13:20:54 -0300 Subject: [PATCH 05/10] chore: remove unused parseShortFlag fn --- src/deps/zig-clap/clap/streaming.zig | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/deps/zig-clap/clap/streaming.zig b/src/deps/zig-clap/clap/streaming.zig index efe7e4319a3f1a..31f9737fc91edc 100644 --- a/src/deps/zig-clap/clap/streaming.zig +++ b/src/deps/zig-clap/clap/streaming.zig @@ -167,24 +167,6 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { } } - fn parseShortFlag(parser: *@This(), flag: u8) ArgError!Arg(Id) { - for (parser.params) |*param| { - const short = param.names.short orelse continue; - if (short != flag) continue; - - if (param.takes_value == .none) { - return Arg(Id){ .param = param }; - } - - const value = parser.iter.next() orelse { - return parser.err(&[_]u8{flag}, .{ .short = flag }, error.MissingValue); - }; - return Arg(Id){ .param = param, .value = value }; - } - - return parser.err(&[_]u8{flag}, .{ .short = flag }, error.InvalidArgument); - } - fn chaining(parser: *@This(), state: State.Chaining) ArgError!?Arg(Id) { const arg = state.arg; const index = state.index; From f352367c6e5ecaeaad46d4bdd51c9b02f97ff6cc Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Mon, 11 Nov 2024 13:37:04 -0300 Subject: [PATCH 06/10] test: pass stderr to lower case --- test/regression/issue/07114.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/regression/issue/07114.test.ts b/test/regression/issue/07114.test.ts index de528f4496a250..43fbec5b8cf039 100644 --- a/test/regression/issue/07114.test.ts +++ b/test/regression/issue/07114.test.ts @@ -16,7 +16,7 @@ test("short flags should be properly parsed", () => { env: bunEnv, stderr: "pipe", }); - expect(singleFlag.stderr.toString()).not.toContain("Invalid argument '-t'"); + expect(singleFlag.stderr.toString().toLowerCase()).not.toContain("invalid argument '-t'"); // Test multiple combined short flags const multipleFlags = Bun.spawnSync({ @@ -25,7 +25,7 @@ test("short flags should be properly parsed", () => { env: bunEnv, stderr: "pipe", }); - expect(multipleFlags.stderr.toString()).not.toContain("Invalid argument"); + expect(multipleFlags.stderr.toString().toLowerCase()).not.toContain("invalid argument"); // Test short flag with value const flagWithValue = Bun.spawnSync({ @@ -34,5 +34,5 @@ test("short flags should be properly parsed", () => { env: bunEnv, stderr: "pipe", }); - expect(flagWithValue.stderr.toString()).not.toContain("Invalid argument '-p'"); + expect(flagWithValue.stderr.toString().toLowerCase()).not.toContain("invalid argument '-p'"); }); From e5ed6c7864fc2b4d9fa74776adb84a58484e6dd2 Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Mon, 11 Nov 2024 13:48:20 -0300 Subject: [PATCH 07/10] test: amend test with flags that requires a value but none was supplied --- src/deps/zig-clap/clap/streaming.zig | 35 ++++------------------------ test/regression/issue/07114.test.ts | 12 +++++++++- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/deps/zig-clap/clap/streaming.zig b/src/deps/zig-clap/clap/streaming.zig index 31f9737fc91edc..366281e6a109eb 100644 --- a/src/deps/zig-clap/clap/streaming.zig +++ b/src/deps/zig-clap/clap/streaming.zig @@ -118,37 +118,10 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { } return null; }, - .short => { - if (arg.len == 1) { - for (parser.params) |*param| { - const short = param.names.short orelse continue; - if (short != arg[0]) continue; - - if (param.takes_value == .none) { - return Arg(Id){ .param = param }; - } - - const value = parser.iter.next() orelse { - return parser.err(arg, .{ .short = arg[0] }, error.MissingValue); - }; - return Arg(Id){ .param = param, .value = value }; - } - - if (warn_on_unrecognized_flag) { - Output.warn("unrecognized flag: -{s}\n", .{arg}); - Output.flush(); - } - return parser.next(); - } - - parser.state = .{ - .chaining = .{ - .arg = arg, - .index = 0, - }, - }; - return try parser.chaining(parser.state.chaining); - }, + .short => return try parser.chaining(.{ + .arg = arg, + .index = 0, + }), .positional => if (parser.positionalParam()) |param| { // If we find a positional with the value `--` then we // interpret the rest of the arguments as positional diff --git a/test/regression/issue/07114.test.ts b/test/regression/issue/07114.test.ts index 43fbec5b8cf039..4e182e2ab972c0 100644 --- a/test/regression/issue/07114.test.ts +++ b/test/regression/issue/07114.test.ts @@ -20,12 +20,13 @@ test("short flags should be properly parsed", () => { // Test multiple combined short flags const multipleFlags = Bun.spawnSync({ - cmd: [bunExe(), "-abc"], + cmd: [bunExe(), "-ab"], cwd: dir, env: bunEnv, stderr: "pipe", }); expect(multipleFlags.stderr.toString().toLowerCase()).not.toContain("invalid argument"); + expect(multipleFlags.stderr.toString().toLowerCase()).not.toContain("requires a value but none was supplied"); // Test short flag with value const flagWithValue = Bun.spawnSync({ @@ -35,4 +36,13 @@ test("short flags should be properly parsed", () => { stderr: "pipe", }); expect(flagWithValue.stderr.toString().toLowerCase()).not.toContain("invalid argument '-p'"); + + // Test short flag that requires a value but none was supplied + const flagWithoutValue = Bun.spawnSync({ + cmd: [bunExe(), "-p"], + cwd: dir, + env: bunEnv, + stderr: "pipe", + }); + expect(flagWithoutValue.stderr.toString().toLowerCase()).toContain("requires a value but none was supplied"); }); From a4e416c9700e6d8da5660c30999932e8cc8ee61f Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Mon, 11 Nov 2024 14:00:42 -0300 Subject: [PATCH 08/10] chore: sync zig-clap fork with upstream --- src/deps/zig-clap/clap.zig | 2 + src/deps/zig-clap/clap/streaming.zig | 67 ++++++++++++++-------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/deps/zig-clap/clap.zig b/src/deps/zig-clap/clap.zig index cea034c1a7853b..84ab8f0e154f16 100644 --- a/src/deps/zig-clap/clap.zig +++ b/src/deps/zig-clap/clap.zig @@ -10,6 +10,8 @@ const Output = @import("../../output.zig"); pub const args = @import("clap/args.zig"); +pub const default_assignment_separators = "="; + test "clap" { testing.refAllDecls(@This()); } diff --git a/src/deps/zig-clap/clap/streaming.zig b/src/deps/zig-clap/clap/streaming.zig index 366281e6a109eb..af64f022e79b3c 100644 --- a/src/deps/zig-clap/clap/streaming.zig +++ b/src/deps/zig-clap/clap/streaming.zig @@ -25,6 +25,12 @@ pub fn Arg(comptime Id: type) type { }; } +pub const ArgError = error{ + DoesntTakeValue, + MissingValue, + InvalidArgument, +}; + /// A command line argument parser which, given an ArgIterator, will parse arguments according /// to the params. StreamingClap parses in an iterating manner, so you have to use a loop together with /// StreamingClap.next to parse all the arguments of your program. @@ -41,13 +47,12 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { }; }; - const ArgError = error{ DoesntTakeValue, MissingValue, InvalidArgument }; - params: []const clap.Param(Id), iter: *ArgIterator, state: State = .normal, positional: ?*const clap.Param(Id) = null, diagnostic: ?*clap.Diagnostic = null, + assignment_separators: []const u8 = clap.default_assignment_separators, /// Get the next Arg that matches a Param. pub fn next(parser: *@This()) ArgError!?Arg(Id) { @@ -143,56 +148,52 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { fn chaining(parser: *@This(), state: State.Chaining) ArgError!?Arg(Id) { const arg = state.arg; const index = state.index; - const flag = arg[index]; + const next_index = index + 1; for (parser.params) |*param| { const short = param.names.short orelse continue; - if (short != flag) continue; + if (short != arg[index]) + continue; - const next_index = index + 1; - if (param.takes_value == .none) { - if (next_index < arg.len) { + // Before we return, we have to set the new state of the clap + defer { + if (arg.len <= next_index or param.takes_value != .none) { + parser.state = .normal; + } else { parser.state = .{ .chaining = .{ .arg = arg, .index = next_index, }, }; - } else { - parser.state = .normal; } - return Arg(Id){ .param = param }; } - const value = if (next_index < arg.len) - arg[next_index..] + const next_is_separator = if (next_index < arg.len) + std.mem.indexOfScalar(u8, parser.assignment_separators, arg[next_index]) != null else - parser.iter.next() orelse { - return parser.err(arg, .{ .short = flag }, error.MissingValue); - }; + false; - parser.state = .normal; - return Arg(Id){ .param = param, .value = value }; - } + if (param.takes_value == .none) { + if (next_is_separator) + return parser.err(arg, .{ .short = short }, error.DoesntTakeValue); + return Arg(Id){ .param = param }; + } - if (warn_on_unrecognized_flag) { - Output.warn("unrecognized flag: -{c}\n", .{flag}); - Output.flush(); - } + if (arg.len <= next_index) { + const value = parser.iter.next() orelse + return parser.err(arg, .{ .short = short }, error.MissingValue); - const next_index = index + 1; - if (next_index < arg.len) { - parser.state = .{ - .chaining = .{ - .arg = arg, - .index = next_index, - }, - }; - return parser.chaining(parser.state.chaining); + return Arg(Id){ .param = param, .value = value }; + } + + if (next_is_separator) + return Arg(Id){ .param = param, .value = arg[next_index + 1 ..] }; + + return Arg(Id){ .param = param, .value = arg[next_index..] }; } - parser.state = .normal; - return parser.next(); + return parser.err(arg, .{ .short = arg[index] }, error.InvalidArgument); } fn positionalParam(parser: *@This()) ?*const clap.Param(Id) { From 4f5fb6dd9616ffcf276b3c5f374e8c631211431a Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Mon, 11 Nov 2024 14:36:51 -0300 Subject: [PATCH 09/10] feat: enable warn_on_unrecognized_flag --- src/deps/zig-clap/clap/streaming.zig | 13 +++++++++++-- test/regression/issue/07114.test.ts | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/deps/zig-clap/clap/streaming.zig b/src/deps/zig-clap/clap/streaming.zig index af64f022e79b3c..2e094dd0dbf3dc 100644 --- a/src/deps/zig-clap/clap/streaming.zig +++ b/src/deps/zig-clap/clap/streaming.zig @@ -12,8 +12,8 @@ const mem = std.mem; const os = std.os; const testing = std.testing; -// Disabled because not all CLI arguments are parsed with Clap. -pub var warn_on_unrecognized_flag = false; +// Enabled because some CLI arguments are parsed with Clap into downstream commands like `bun create` +pub var warn_on_unrecognized_flag = true; /// The result returned from StreamingClap.next pub fn Arg(comptime Id: type) type { @@ -193,6 +193,15 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { return Arg(Id){ .param = param, .value = arg[next_index..] }; } + // Handle unrecognized flags + if (warn_on_unrecognized_flag) { + Output.warn("unrecognized bun flag: -{c}, continuing to parse and evaluate flag downstream...\n", .{arg[index]}); + Output.flush(); + // Continue parsing after unrecognized flag + parser.state = .normal; + return parser.next(); + } + return parser.err(arg, .{ .short = arg[index] }, error.InvalidArgument); } diff --git a/test/regression/issue/07114.test.ts b/test/regression/issue/07114.test.ts index 4e182e2ab972c0..7ba4d200a4985f 100644 --- a/test/regression/issue/07114.test.ts +++ b/test/regression/issue/07114.test.ts @@ -11,7 +11,7 @@ test("short flags should be properly parsed", () => { // Test single short flag const singleFlag = Bun.spawnSync({ - cmd: [bunExe(), "-t"], + cmd: [bunExe(), "-t"], // as in `bun create expo ./awesome-project -t tabs` cwd: dir, env: bunEnv, stderr: "pipe", From 78bb5f3e0acd6ce1fb022f206f5aec8abe6f5eb9 Mon Sep 17 00:00:00 2001 From: Renan Mav Date: Wed, 20 Nov 2024 15:06:49 -0300 Subject: [PATCH 10/10] feat: continue parsing after unrecognized short flag --- src/deps/zig-clap/clap/streaming.zig | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/deps/zig-clap/clap/streaming.zig b/src/deps/zig-clap/clap/streaming.zig index 2e094dd0dbf3dc..1943c9d1f44f78 100644 --- a/src/deps/zig-clap/clap/streaming.zig +++ b/src/deps/zig-clap/clap/streaming.zig @@ -12,8 +12,8 @@ const mem = std.mem; const os = std.os; const testing = std.testing; -// Enabled because some CLI arguments are parsed with Clap into downstream commands like `bun create` -pub var warn_on_unrecognized_flag = true; +// Disabled because not all CLI arguments are parsed with Clap. +pub var warn_on_unrecognized_flag = false; /// The result returned from StreamingClap.next pub fn Arg(comptime Id: type) type { @@ -193,16 +193,14 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { return Arg(Id){ .param = param, .value = arg[next_index..] }; } - // Handle unrecognized flags if (warn_on_unrecognized_flag) { Output.warn("unrecognized bun flag: -{c}, continuing to parse and evaluate flag downstream...\n", .{arg[index]}); Output.flush(); - // Continue parsing after unrecognized flag - parser.state = .normal; - return parser.next(); } - return parser.err(arg, .{ .short = arg[index] }, error.InvalidArgument); + // Continue parsing after unrecognized flag + parser.state = .normal; + return parser.next(); } fn positionalParam(parser: *@This()) ?*const clap.Param(Id) {