diff --git a/src/cli/Arguments.zig b/src/cli/Arguments.zig index d29edde371..e6e6659a9f 100644 --- a/src/cli/Arguments.zig +++ b/src/cli/Arguments.zig @@ -82,6 +82,7 @@ pub const runtime_params_ = [_]ParamType{ clap.parseParam("--smol Use less memory, but run garbage collection more often") catch unreachable, clap.parseParam("-r, --preload ... Import a module before other modules are loaded") catch unreachable, clap.parseParam("--require ... Alias of --preload, for Node.js compatibility") catch unreachable, + clap.parseParam("--import ... Alias of --preload, for Node.js compatibility") catch unreachable, clap.parseParam("--inspect ? Activate Bun's debugger") catch unreachable, clap.parseParam("--inspect-wait ? Activate Bun's debugger, wait for a connection before executing") catch unreachable, clap.parseParam("--inspect-brk ? Activate Bun's debugger, set breakpoint on first line of code and wait") catch unreachable, @@ -542,13 +543,23 @@ pub fn parse(allocator: std.mem.Allocator, ctx: Command.Context, comptime cmd: C // runtime commands if (cmd == .AutoCommand or cmd == .RunCommand or cmd == .TestCommand or cmd == .RunAsNodeCommand) { - var preloads = args.options("--preload"); - if (preloads.len == 0) { - if (bun.getenvZ("BUN_INSPECT_PRELOAD")) |preload| { - preloads = bun.default_allocator.dupe([]const u8, &.{preload}) catch unreachable; + { + const preloads = args.options("--preload"); + const preloads2 = args.options("--require"); + const preloads3 = args.options("--import"); + const preload4 = bun.getenvZ("BUN_INSPECT_PRELOAD"); + + const total_preloads = ctx.preloads.len + preloads.len + preloads2.len + preloads3.len + (if (preload4 != null) @as(usize, 1) else @as(usize, 0)); + if (total_preloads > 0) { + var all = std.ArrayList(string).initCapacity(ctx.allocator, total_preloads) catch unreachable; + if (ctx.preloads.len > 0) all.appendSliceAssumeCapacity(ctx.preloads); + if (preloads.len > 0) all.appendSliceAssumeCapacity(preloads); + if (preloads2.len > 0) all.appendSliceAssumeCapacity(preloads2); + if (preloads3.len > 0) all.appendSliceAssumeCapacity(preloads3); + if (preload4) |p| all.appendAssumeCapacity(p); + ctx.preloads = all.items; } } - const preloads2 = args.options("--require"); if (args.flag("--hot")) { ctx.debug.hot_reload = .hot; @@ -645,25 +656,6 @@ pub fn parse(allocator: std.mem.Allocator, ctx: Command.Context, comptime cmd: C } } - if (ctx.preloads.len > 0 and (preloads.len > 0 or preloads2.len > 0)) { - var all = std.ArrayList(string).initCapacity(ctx.allocator, ctx.preloads.len + preloads.len + preloads2.len) catch unreachable; - all.appendSliceAssumeCapacity(ctx.preloads); - all.appendSliceAssumeCapacity(preloads); - all.appendSliceAssumeCapacity(preloads2); - ctx.preloads = all.items; - } else if (preloads.len > 0) { - if (preloads2.len > 0) { - var all = std.ArrayList(string).initCapacity(ctx.allocator, preloads.len + preloads2.len) catch unreachable; - all.appendSliceAssumeCapacity(preloads); - all.appendSliceAssumeCapacity(preloads2); - ctx.preloads = all.items; - } else { - ctx.preloads = preloads; - } - } else if (preloads2.len > 0) { - ctx.preloads = preloads2; - } - if (args.option("--print")) |script| { ctx.runtime_options.eval.script = script; ctx.runtime_options.eval.eval_and_print = true; diff --git a/test/config/bunfig/fixtures/preload/many/index.ts b/test/config/bunfig/fixtures/preload/many/index.ts new file mode 100644 index 0000000000..8f356d1362 --- /dev/null +++ b/test/config/bunfig/fixtures/preload/many/index.ts @@ -0,0 +1 @@ +console.log(globalThis.preload); \ No newline at end of file diff --git a/test/config/bunfig/fixtures/preload/many/preload1.ts b/test/config/bunfig/fixtures/preload/many/preload1.ts new file mode 100644 index 0000000000..63141e2cd2 --- /dev/null +++ b/test/config/bunfig/fixtures/preload/many/preload1.ts @@ -0,0 +1 @@ +(globalThis.preload ??= []).push("multi/preload1.ts"); diff --git a/test/config/bunfig/fixtures/preload/many/preload2.ts b/test/config/bunfig/fixtures/preload/many/preload2.ts new file mode 100644 index 0000000000..59d054a998 --- /dev/null +++ b/test/config/bunfig/fixtures/preload/many/preload2.ts @@ -0,0 +1 @@ +(globalThis.preload ??= []).push("multi/preload2.ts"); diff --git a/test/config/bunfig/fixtures/preload/many/preload3.ts b/test/config/bunfig/fixtures/preload/many/preload3.ts new file mode 100644 index 0000000000..c5da4a3366 --- /dev/null +++ b/test/config/bunfig/fixtures/preload/many/preload3.ts @@ -0,0 +1 @@ +(globalThis.preload ??= []).push("multi/preload3.ts"); diff --git a/test/config/bunfig/preload.test.ts b/test/config/bunfig/preload.test.ts index 895be5ea57..44daf6c91d 100644 --- a/test/config/bunfig/preload.test.ts +++ b/test/config/bunfig/preload.test.ts @@ -7,13 +7,17 @@ const fixturePath = (...segs: string[]) => resolve(import.meta.dirname, "fixture type Opts = { args?: string[]; cwd?: string; + env?: Record; }; type Out = [stdout: string, stderr: string, exitCode: number]; -const run = (file: string, { args = [], cwd }: Opts = {}): Promise => { +const run = (file: string, { args = [], cwd, env = {} }: Opts = {}): Promise => { const res = Bun.spawn([bunExe(), ...args, file], { cwd, stdio: ["ignore", "pipe", "pipe"], - env: bunEnv, + env: { + ...env, + ...bunEnv, + }, } satisfies SpawnOptions.OptionsObject<"ignore", "pipe", "pipe">); return Promise.all([ @@ -134,3 +138,65 @@ describe("Given a `bunfig.toml` file with a relative path without a leading './' expect(code).toBe(0); }); }); // + +describe("Test that all the aliases for --preload work", () => { + const dir = fixturePath("many"); + + it.each(["--preload=./preload1.ts", "--require=./preload1.ts", "--import=./preload1.ts"])( + "When `bun run` is run with %s, the preload is executed", + async flag => { + const [out, err, code] = await run("index.ts", { args: [flag], cwd: dir }); + expect(err).toBeEmpty(); + expect(out).toBe('[ "multi/preload1.ts" ]'); + expect(code).toBe(0); + }, + ); + + it.each(["1", "2", "3", "4"])( + "When multiple preload flags are used, they execute in order: --preload, --require, --import (#%s)", + async i => { + let args: string[] = []; + if (i === "1") args = ["--preload", "./preload1.ts", "--require", "./preload2.ts", "--import", "./preload3.ts"]; + if (i === "2") args = ["--import", "./preload3.ts", "--preload=./preload1.ts", "--require", "./preload2.ts"]; + if (i === "3") args = ["--require", "./preload2.ts", "--import", "./preload3.ts", "--preload", "./preload1.ts"]; + if (i === "4") args = ["--require", "./preload1.ts", "--import", "./preload3.ts", "--require", "./preload2.ts"]; + const [out, err, code] = await run("index.ts", { args, cwd: dir }); + expect(err).toBeEmpty(); + expect(out).toBe('[ "multi/preload1.ts", "multi/preload2.ts", "multi/preload3.ts" ]'); + expect(code).toBe(0); + }, + ); + + it("Duplicate preload flags are only executed once", async () => { + const args = ["--preload", "./preload1.ts", "--require", "./preload1.ts", "--import", "./preload1.ts"]; + const [out, err, code] = await run("index.ts", { args, cwd: dir }); + expect(err).toBeEmpty(); + expect(out).toBe('[ "multi/preload1.ts" ]'); + expect(code).toBe(0); + }); + + it("Test double preload flags", async () => { + const dir = fixturePath("many"); + const args = [ + "--preload", + "./preload1.ts", + "--preload=./preload2.ts", + "--preload", + "./preload3.ts", + "-r", + "./preload3.ts", + ]; + const [out, err, code] = await run("index.ts", { args, cwd: dir }); + expect(err).toBeEmpty(); + expect(out).toMatchInlineSnapshot(`"[ "multi/preload1.ts", "multi/preload2.ts", "multi/preload3.ts" ]"`); + expect(code).toBe(0); + }); +}); // + +test("Test BUN_INSPECT_PRELOAD is used to set preloads", async () => { + const dir = fixturePath("many"); + const [out, err, code] = await run("index.ts", { args: [], cwd: dir, env: { BUN_INSPECT_PRELOAD: "./preload1.ts" } }); + expect(err).toBeEmpty(); + expect(out).toMatchInlineSnapshot(`"[ "multi/preload1.ts" ]"`); + expect(code).toBe(0); +}); // diff --git a/test/internal/ban-words.test.ts b/test/internal/ban-words.test.ts index ac05275e59..3ac65c6498 100644 --- a/test/internal/ban-words.test.ts +++ b/test/internal/ban-words.test.ts @@ -34,7 +34,7 @@ const words: Record [String.raw`: [a-zA-Z0-9_\.\*\?\[\]\(\)]+ = undefined,`]: { reason: "Do not default a struct field to undefined", limit: 242, regex: true }, "usingnamespace": { reason: "Zig 0.15 will remove `usingnamespace`" }, - "catch unreachable": { reason: "For out-of-memory, prefer 'catch bun.outOfMemory()'", limit: 1860 }, + "catch unreachable": { reason: "For out-of-memory, prefer 'catch bun.outOfMemory()'", limit: 1859 }, "std.fs.Dir": { reason: "Prefer bun.sys + bun.FD instead of std.fs", limit: 179 }, "std.fs.cwd": { reason: "Prefer bun.FD.cwd()", limit: 102 },