diff --git a/src/runtime/cli/Arguments.rs b/src/runtime/cli/Arguments.rs index 14e20c0e7b5a..5403fbbfd98a 100644 --- a/src/runtime/cli/Arguments.rs +++ b/src/runtime/cli/Arguments.rs @@ -1345,7 +1345,7 @@ pub fn parse(cmd: CommandTag, ctx: Context<'_>) -> crate::Result, opts: &mut api::TransformOptions, ctx: Context<'_>, - diag: &mut clap::Diagnostic, ) { ctx.bundler_options.transform_only = args.flag(b"--no-bundle"); ctx.bundler_options.bytecode = args.flag(b"--bytecode"); @@ -1994,7 +1993,7 @@ fn parse_build_command_options( } } b"bun" => api::Target::Bun, - _ => cli::invalid_target(diag, target), + _ => cli::invalid_target(target), })); if opts.target.unwrap() == api::Target::Bun { @@ -2003,12 +2002,7 @@ fn parse_build_command_options( if ctx.bundler_options.bytecode { Output::err_generic( "target must be 'bun' when bytecode is true. Received: {}", - format_args!( - "{:?}", - ::from_api( - opts.target - ) - ), + format_args!("{}", BStr::new(target)), ); Global::exit(1); } @@ -2016,12 +2010,7 @@ fn parse_build_command_options( if ctx.bundler_options.bake { Output::err_generic( "target must be 'bun' when using --app. Received: {}", - format_args!( - "{:?}", - ::from_api( - opts.target - ) - ), + format_args!("{}", BStr::new(target)), ); } } @@ -2383,8 +2372,8 @@ fn parse_build_command_options( Output::err_generic( "Cannot use client-side --target={} with --server-components", format_args!( - "{:?}", - ::from_api(Some(target)) + "{}", + BStr::new(args.option(b"--target").unwrap_or_default()) ), ); Global::crash(); diff --git a/src/runtime/cli/mod.rs b/src/runtime/cli/mod.rs index d1ab71efe869..6ab0ade0f5c9 100644 --- a/src/runtime/cli/mod.rs +++ b/src/runtime/cli/mod.rs @@ -524,8 +524,11 @@ impl colon_list_type::ColonListValue for &'static [u8] { } #[cold] -pub(crate) fn invalid_target(diag: &mut bun_clap::Diagnostic, _target: &[u8]) -> ! { - let _ = diag.report(Output::error_writer(), bun_clap::Error::InvalidArgument); +pub(crate) fn invalid_target(target: &[u8]) -> ! { + Output::err_generic( + "Invalid value for --target: {}. Must be 'browser', 'node', 'macro', or 'bun'.", + (bun::fmt::quote(target),), + ); Global::exit(1); } diff --git a/test/bundler/cli.test.ts b/test/bundler/cli.test.ts index 350841445132..190f589ce049 100644 --- a/test/bundler/cli.test.ts +++ b/test/bundler/cli.test.ts @@ -516,4 +516,43 @@ describe("CLI argument error messages", () => { expect(stderr).toContain("key=value"); expect(exitCode).toBe(1); }); + + test.each(["nodejs", "web", "deno", ""])( + "--target with an unrecognized value names the flag and echoes %j back", + async value => { + using dir = tempDir("build-target-err", { "in.js": "console.log(1)" }); + await using proc = Bun.spawn({ + cmd: [bunExe(), "build", `--target=${value}`, "in.js"], + env: bunEnv, + cwd: String(dir), + stdout: "pipe", + stderr: "pipe", + }); + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + expect({ stdout, stderr }).toEqual({ + stdout: "", + stderr: expect.stringContaining(`--target: "${value}"`), + }); + expect(stderr).toContain("'browser', 'node', 'macro', or 'bun'"); + expect(exitCode).toBe(1); + }, + ); + + test("--bytecode with a non-bun --target echoes the value in its user-facing spelling", async () => { + using dir = tempDir("build-bytecode-target-err", { "in.js": "console.log(1)" }); + await using proc = Bun.spawn({ + cmd: [bunExe(), "build", "--bytecode", "--target=browser", "in.js"], + env: bunEnv, + cwd: String(dir), + stdout: "pipe", + stderr: "pipe", + }); + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + expect({ stdout, stderr }).toEqual({ + stdout: "", + stderr: expect.stringContaining("Received: browser"), + }); + expect(stderr).not.toContain("Browser"); + expect(exitCode).toBe(1); + }); });