mirror of
https://github.com/oven-sh/bun
synced 2026-02-17 22:32:06 +00:00
fix(cli): support node --run when bun pretends to be node
When `bun run --bun` is used, child processes invoking `node` actually run bun via a symlink. Node.js v22+ supports `node --run <script>` to run package.json scripts, but bun's fake node mode silently ignored the `--run` flag and tried to execute the script name as a file path instead. Detect `--run` in the raw argv and delegate to `RunCommand.exec()` which already handles package.json script resolution with pre/post scripts. Closes #27074 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1637,6 +1637,21 @@ pub const RunCommand = struct {
|
||||
return;
|
||||
}
|
||||
|
||||
// Support `node --run <script>` (Node.js v22+ feature).
|
||||
// The --run flag is silently discarded by the arg parser since it's
|
||||
// unrecognized, but the script name ends up as ctx.positionals[0].
|
||||
// Scan the raw argv to detect if --run was present.
|
||||
if (ctx.positionals.len > 0) {
|
||||
for (bun.argv) |arg| {
|
||||
if (strings.eqlComptime(arg, "--run")) {
|
||||
if (exec(ctx, .{ .bin_dirs_only = false, .log_errors = true, .allow_fast_run_for_extensions = false })) |ok| {
|
||||
if (ok) return;
|
||||
} else |_| {}
|
||||
Global.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.positionals.len == 0) {
|
||||
Output.errGeneric("Missing script to execute. Bun's provided 'node' cli wrapper does not support a repl.", .{});
|
||||
Global.exit(1);
|
||||
|
||||
@@ -101,4 +101,39 @@ describe("fake node cli", () => {
|
||||
const temp = tempDirWithFiles("fake-node", {});
|
||||
expect(() => fakeNodeRun(temp, [])).toThrow();
|
||||
});
|
||||
|
||||
describe("node --run", () => {
|
||||
test("runs a package.json script", () => {
|
||||
const temp = tempDirWithFiles("fake-node", {
|
||||
"package.json": JSON.stringify({
|
||||
scripts: {
|
||||
echo_test: "echo pass",
|
||||
},
|
||||
}),
|
||||
});
|
||||
expect(fakeNodeRun(temp, ["--run", "echo_test"]).stdout).toBe("pass");
|
||||
});
|
||||
|
||||
test("runs pre/post scripts", () => {
|
||||
const temp = tempDirWithFiles("fake-node", {
|
||||
"package.json": JSON.stringify({
|
||||
scripts: {
|
||||
premyscript: "echo pre",
|
||||
myscript: "echo main",
|
||||
postmyscript: "echo post",
|
||||
},
|
||||
}),
|
||||
});
|
||||
expect(fakeNodeRun(temp, ["--run", "myscript"]).stdout).toBe("pre\nmain\npost");
|
||||
});
|
||||
|
||||
test("errors on missing script", () => {
|
||||
const temp = tempDirWithFiles("fake-node", {
|
||||
"package.json": JSON.stringify({
|
||||
scripts: {},
|
||||
}),
|
||||
});
|
||||
expect(() => fakeNodeRun(temp, ["--run", "nonexistent"])).toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
29
test/regression/issue/27074.test.ts
Normal file
29
test/regression/issue/27074.test.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, tempDirWithFiles } from "../../harness";
|
||||
|
||||
// https://github.com/oven-sh/bun/issues/27074
|
||||
// `bun run --bun build` fails when a pre-script uses `node --run`
|
||||
test("bun run --bun works with node --run in lifecycle scripts", () => {
|
||||
const temp = tempDirWithFiles("issue-27074", {
|
||||
"package.json": JSON.stringify({
|
||||
scripts: {
|
||||
echo_test: "echo echo_test_ran",
|
||||
prebuild: "node --run echo_test",
|
||||
build: "echo build_ran",
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const result = Bun.spawnSync({
|
||||
cmd: [bunExe(), "run", "--bun", "build"],
|
||||
cwd: temp,
|
||||
env: bunEnv,
|
||||
});
|
||||
|
||||
const stdout = result.stdout.toString("utf8").trim();
|
||||
const stderr = result.stderr.toString("utf8").trim();
|
||||
|
||||
expect(stdout).toContain("echo_test_ran");
|
||||
expect(stdout).toContain("build_ran");
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
Reference in New Issue
Block a user