Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 6 additions & 17 deletions src/runtime/cli/Arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1345,7 +1345,7 @@ pub fn parse(cmd: CommandTag, ctx: Context<'_>) -> crate::Result<api::TransformO
ctx.bundler_options.ignore_dce_annotations = args.flag(b"--ignore-dce-annotations");

if cmd == CommandTag::BuildCommand {
parse_build_command_options(cmd, &args, &mut opts, ctx, &mut diag);
parse_build_command_options(cmd, &args, &mut opts, ctx);
}

if opts.entry_points.is_empty() {
Expand Down Expand Up @@ -1853,7 +1853,6 @@ fn parse_build_command_options(
args: &clap::Args<clap::Help>,
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");
Expand Down Expand Up @@ -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 {
Expand All @@ -2003,25 +2002,15 @@ fn parse_build_command_options(
if ctx.bundler_options.bytecode {
Output::err_generic(
"target must be 'bun' when bytecode is true. Received: {}",
format_args!(
"{:?}",
<bun_ast::Target as bun_options_types::TargetExt>::from_api(
opts.target
)
),
format_args!("{}", BStr::new(target)),
);
Global::exit(1);
}

if ctx.bundler_options.bake {
Output::err_generic(
"target must be 'bun' when using --app. Received: {}",
format_args!(
"{:?}",
<bun_ast::Target as bun_options_types::TargetExt>::from_api(
opts.target
)
),
format_args!("{}", BStr::new(target)),
);
}
}
Expand Down Expand Up @@ -2383,8 +2372,8 @@ fn parse_build_command_options(
Output::err_generic(
"Cannot use client-side --target={} with --server-components",
format_args!(
"{:?}",
<bun_ast::Target as bun_options_types::TargetExt>::from_api(Some(target))
"{}",
BStr::new(args.option(b"--target").unwrap_or_default())
),
);
Global::crash();
Expand Down
7 changes: 5 additions & 2 deletions src/runtime/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
39 changes: 39 additions & 0 deletions test/bundler/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
Loading