mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
Add bunfig.toml [runtime] sourceCodePreview option
This adds a configuration option to disable source code previews in error stack traces via bunfig.toml: [runtime] sourceCodePreview = false When disabled, error stack traces will still show file paths and line numbers, but will not include the source code snippets with line numbers and caret indicators that are normally displayed. Changes: - Add source_code_preview field to RuntimeOptions in cli.zig - Add parsing for [runtime].sourceCodePreview in bunfig.zig - Add source_code_preview field to VirtualMachine struct and Options - Wire up the config to disable collectSourceLines() in remapZigException - Add test verifying source code preview can be disabled Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,7 @@ pub const Run = struct {
|
||||
.args = ctx.args,
|
||||
.graph = graph_ptr,
|
||||
.is_main_thread = true,
|
||||
.source_code_preview = ctx.runtime_options.source_code_preview,
|
||||
}),
|
||||
.arena = arena,
|
||||
.ctx = ctx,
|
||||
@@ -174,6 +175,7 @@ pub const Run = struct {
|
||||
.debugger = ctx.runtime_options.debugger,
|
||||
.dns_result_order = DNSResolver.Order.fromStringOrDie(ctx.runtime_options.dns_result_order),
|
||||
.is_main_thread = true,
|
||||
.source_code_preview = ctx.runtime_options.source_code_preview,
|
||||
},
|
||||
),
|
||||
.arena = arena,
|
||||
|
||||
@@ -48,6 +48,7 @@ unhandled_pending_rejection_to_capture: ?*JSValue = null,
|
||||
standalone_module_graph: ?*bun.StandaloneModuleGraph = null,
|
||||
smol: bool = false,
|
||||
dns_result_order: DNSResolver.Order = .verbatim,
|
||||
source_code_preview: bool = true,
|
||||
counters: Counters = .{},
|
||||
|
||||
hot_reload: bun.cli.Command.HotReload = .none,
|
||||
@@ -1086,6 +1087,7 @@ pub const Options = struct {
|
||||
/// Worker VMs are always destroyed on exit, regardless of this setting. Setting this to
|
||||
/// true may expose bugs that would otherwise only occur using Workers.
|
||||
destruct_main_thread_on_exit: bool = false,
|
||||
source_code_preview: bool = true,
|
||||
};
|
||||
|
||||
pub var is_smol_mode = false;
|
||||
@@ -1180,6 +1182,7 @@ pub fn init(opts: Options) !*VirtualMachine {
|
||||
uws.Loop.get().internal_loop_data.jsc_vm = vm.jsc_vm;
|
||||
vm.smol = opts.smol;
|
||||
vm.dns_result_order = opts.dns_result_order;
|
||||
vm.source_code_preview = opts.source_code_preview;
|
||||
|
||||
if (opts.smol)
|
||||
is_smol_mode = opts.smol;
|
||||
@@ -1330,6 +1333,7 @@ pub fn initWorker(
|
||||
}
|
||||
|
||||
vm.smol = opts.smol;
|
||||
vm.source_code_preview = opts.source_code_preview;
|
||||
vm.transpiler.macro_context = js_ast.Macro.MacroContext.init(&vm.transpiler);
|
||||
|
||||
vm.global = JSGlobalObject.create(
|
||||
@@ -1430,6 +1434,7 @@ pub fn initBake(opts: Options) anyerror!*VirtualMachine {
|
||||
vm.transpiler.macro_context = js_ast.Macro.MacroContext.init(&vm.transpiler);
|
||||
|
||||
vm.smol = opts.smol;
|
||||
vm.source_code_preview = opts.source_code_preview;
|
||||
|
||||
if (opts.smol)
|
||||
is_smol_mode = opts.smol;
|
||||
@@ -2923,7 +2928,7 @@ fn printErrorInstance(
|
||||
exception_list,
|
||||
&exception_holder.need_to_clear_parser_arena_on_deinit,
|
||||
&source_code_slice,
|
||||
formatter.error_display_level != .warn,
|
||||
formatter.error_display_level != .warn and this.source_code_preview,
|
||||
);
|
||||
}
|
||||
const prev_had_errors = this.had_errors;
|
||||
|
||||
@@ -779,6 +779,16 @@ pub const Bunfig = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json.get("runtime")) |runtime_expr| {
|
||||
if (runtime_expr.get("sourceCodePreview")) |source_code_preview| {
|
||||
if (source_code_preview.asBool()) |value| {
|
||||
this.ctx.runtime_options.source_code_preview = value;
|
||||
} else {
|
||||
try this.addError(source_code_preview.loc, "Expected boolean");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json.getObject("serve")) |serve_obj2| {
|
||||
|
||||
@@ -385,6 +385,7 @@ pub const Command = struct {
|
||||
expose_gc: bool = false,
|
||||
preserve_symlinks_main: bool = false,
|
||||
console_depth: ?u16 = null,
|
||||
source_code_preview: bool = true,
|
||||
};
|
||||
|
||||
var global_cli_ctx: Context = undefined;
|
||||
|
||||
@@ -1380,6 +1380,7 @@ pub const TestCommand = struct {
|
||||
.smol = ctx.runtime_options.smol,
|
||||
.debugger = ctx.runtime_options.debugger,
|
||||
.is_main_thread = true,
|
||||
.source_code_preview = ctx.runtime_options.source_code_preview,
|
||||
},
|
||||
);
|
||||
vm.argv = ctx.passthrough;
|
||||
|
||||
76
test/js/bun/runtime/source-code-preview.test.ts
Normal file
76
test/js/bun/runtime/source-code-preview.test.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, tempDir } from "harness";
|
||||
|
||||
describe("sourceCodePreview config option", () => {
|
||||
test("default behavior shows source code in error stack traces", async () => {
|
||||
using dir = tempDir("source-code-preview-default", {
|
||||
"test.js": `
|
||||
function foo() {
|
||||
console.log(new Error().stack);
|
||||
}
|
||||
foo();
|
||||
`,
|
||||
});
|
||||
|
||||
const proc = Bun.spawn({
|
||||
cmd: [bunExe(), "test.js"],
|
||||
cwd: String(dir),
|
||||
env: bunEnv,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
const stdout = await proc.stdout.text();
|
||||
const exitCode = await proc.exited;
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
// Should contain line numbers and source code
|
||||
expect(stdout).toContain("test.js:");
|
||||
// Should contain the function call location with source code or line number
|
||||
expect(stdout.length).toBeGreaterThan(10);
|
||||
});
|
||||
|
||||
test("sourceCodePreview=false disables source code in error stack traces", async () => {
|
||||
using dir = tempDir("source-code-preview-disabled", {
|
||||
"bunfig.toml": `
|
||||
[runtime]
|
||||
sourceCodePreview = false
|
||||
`,
|
||||
"test.fixture.ts": `
|
||||
function foo() {
|
||||
console.log(new Error().stack);
|
||||
}
|
||||
foo();
|
||||
`,
|
||||
});
|
||||
|
||||
const proc2 = Bun.spawn({
|
||||
cmd: [bunExe(), "test.fixture.ts"],
|
||||
cwd: String(dir),
|
||||
env: bunEnv,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
const stdout = await proc2.stdout.text();
|
||||
const stderr = await proc2.stderr.text();
|
||||
const exitCode = await proc2.exited;
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const output = stdout + stderr;
|
||||
// Should still contain file path and line numbers
|
||||
expect(output).toContain("test.fixture.ts:");
|
||||
|
||||
// Should NOT contain source code snippets (no pipe characters from source display)
|
||||
// The source code preview typically shows lines like:
|
||||
// 3 | console.log(new Error().stack);
|
||||
// ^
|
||||
// We check that these formatted source lines are not present
|
||||
const lines = output.split("\n");
|
||||
const hasSourceCodeDisplay = lines.some(
|
||||
line =>
|
||||
/^\s*\d+\s+\|/.test(line) || // Lines with line numbers and pipe
|
||||
/^\s*\^/.test(line), // Caret indicators
|
||||
);
|
||||
expect(hasSourceCodeDisplay).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user