Compare commits

...

3 Commits

Author SHA1 Message Date
Claude Bot
66ecf9802a test: verify console.log is not in stderr (source code preview)
The test now properly verifies that when sourceCodePreview is disabled:
- console.log() output still appears in stdout (program runs normally)
- The source code line containing 'console.log' does NOT appear in stderr
  (source code preview is truly disabled)

This confirms that the error formatting doesn't show the source code,
while the actual program execution and console.log output still work.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 03:58:25 +00:00
Claude Bot
a665db4549 test: improve source code preview test to verify console.log not in output
Update test to:
- Throw actual errors instead of console.log(stack) to trigger source preview
- Check that source code lines with 'console.log' don't appear in output
- Verify source code preview shows line numbers and pipes in default mode
- Verify caret indicators (^) are present in default mode
- Ensure source code lines and carets are NOT present when disabled

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 03:55:41 +00:00
Claude Bot
ab1d20e596 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>
2025-10-16 03:50:56 +00:00
6 changed files with 110 additions and 1 deletions

View File

@@ -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,

View File

@@ -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;

View File

@@ -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| {

View File

@@ -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;

View File

@@ -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;

View File

@@ -0,0 +1,90 @@
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() {
throw new Error("Test error");
}
foo();
`,
});
const proc = Bun.spawn({
cmd: [bunExe(), "test.js"],
cwd: String(dir),
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
const stderr = await proc.stderr.text();
const exitCode = await proc.exited;
expect(exitCode).toBe(1);
// Should contain file path and line numbers
expect(stderr).toContain("test.js:");
// Should contain source code preview with line numbers and pipes
expect(stderr).toMatch(/\d+\s+\|/);
// Should contain the source line with "throw new Error"
expect(stderr).toContain('throw new Error("Test error")');
// Should contain caret indicator
expect(stderr).toContain("^");
});
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("before error");
throw new Error("Test error");
}
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(1);
// stdout should contain the console.log output from the program
expect(stdout).toContain("before error");
// Should still contain file path and line numbers in stack trace
expect(stderr).toContain("test.fixture.ts:");
expect(stderr).toContain("Test error");
// Should NOT contain the console.log source code line in the error output
expect(stderr).not.toContain("console.log");
// Should NOT contain source code snippets (no pipe characters from source display)
// The source code preview shows lines like:
// 3 | throw new Error("Test error");
// ^
expect(stderr).not.toMatch(/\d+\s+\|/);
// Should NOT contain caret indicators
expect(stderr).not.toContain(" ^");
// Should NOT show the actual source line "throw new Error"
expect(stderr).not.toContain('throw new Error("Test error")');
});
});