-
Notifications
You must be signed in to change notification settings - Fork 5k
fix(cli): support 'bun node <file>' — node emulation via argv[1] #37277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2987,6 +2987,56 @@ impl RunCommand { | |
| // values. Explicit `--env-file` is still honored. #6338 | ||
| ctx.args.disable_default_env_files = true; | ||
|
|
||
| // `bun node <file>`: argv[1]=="node" made which() take the node | ||
| // emulation path, but the literal "node" positional is still in | ||
| // ctx.positionals[0] — clap's stop_after_positional_at=1 parked | ||
| // everything after it in passthrough, so node flags like `-e` were | ||
| // never parsed either. Remove the "node" placeholder and re-parse the | ||
| // passthrough head as node flags. argv0=node (symlink) keeps | ||
| // IS_NODE_ARG false and never takes this path. | ||
| if crate::cli::IS_NODE_ARG.load(::core::sync::atomic::Ordering::Relaxed) { | ||
| if ctx.positionals.first().is_some_and(|p| p.as_ref() == b"node") { | ||
| ctx.positionals.remove(0); | ||
| // Re-parse node flags parked in passthrough (they were never | ||
| // seen by clap): -e/--eval <code>, -p/--print <code>, | ||
| // --version, --revision, --help. | ||
| while let Some(first) = ctx.passthrough.first().cloned() { | ||
| let first: &[u8] = &first; | ||
| if first == b"--" { | ||
| ctx.passthrough.remove(0); | ||
| break; | ||
| } | ||
| if first == b"-e" || first == b"--eval" { | ||
| ctx.passthrough.remove(0); | ||
| if !ctx.passthrough.is_empty() { | ||
| ctx.runtime_options.eval.script = ctx.passthrough.remove(0); | ||
| } | ||
| } else if first == b"-p" || first == b"--print" { | ||
| ctx.passthrough.remove(0); | ||
| if !ctx.passthrough.is_empty() { | ||
| ctx.runtime_options.eval.script = ctx.passthrough.remove(0); | ||
| ctx.runtime_options.eval.eval_and_print = true; | ||
| } | ||
|
Comment on lines
+3009
to
+3019
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Distinguish an empty eval string from a missing eval argument.
Track eval-option presence separately from script bytes. Return an explicit option-value error only when the value is absent. As per coding guidelines, distinguish empty input from unset input. 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| } else if first == b"--version" { | ||
| crate::cli::print_version_and_exit(); | ||
| } else if first == b"--revision" { | ||
| crate::cli::print_revision_and_exit(); | ||
| } else if first == b"--help" || first == b"-h" { | ||
| crate::cli::command::tag_print_help(CommandTag::RunAsNodeCommand, true); | ||
| Output::flush(); | ||
| bun_core::Global::exit(0); | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| if ctx.positionals.is_empty() && !ctx.passthrough.is_empty() { | ||
| // The real target file (or remaining arg) parked in | ||
| // passthrough; promote it back. | ||
| ctx.positionals.push(ctx.passthrough.remove(0)); | ||
|
Comment on lines
+3003
to
+3035
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift Do not promote an unparsed Node option as the script. For Use Node option parsing that preserves options and their operands in 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| } | ||
| } | ||
| } | ||
|
|
||
| // `node --interactive [-e code]`: same gate as AutoCommand — a script | ||
| // positional wins, and `-p` currently bypasses the REPL (see mod.rs). | ||
| if ctx.runtime_options.interactive | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Parse the first positional before enabling Node emulation.
The leading-flag loop does not consume option operands. Therefore,
bun --cwd node app.jstreats the--cwdvalue as thenodecommand and selectsRunAsNodeCommand.Make the prescan consume value-taking options, or defer this decision until argument parsing identifies the actual first positional. As per coding guidelines, deliberately distinguish input forms at the CLI boundary.
🤖 Prompt for AI Agents
Source: Coding guidelines