mirror of
https://github.com/oven-sh/bun
synced 2026-02-12 11:59:00 +00:00
Source Maps for client-side errors & columns
This commit is contained in:
@@ -389,7 +389,12 @@ pub const ZigStackTrace = extern struct {
|
||||
frames_ptr: [*c]ZigStackFrame,
|
||||
frames_len: u8,
|
||||
|
||||
pub fn toAPI(this: *const ZigStackTrace, allocator: std.mem.Allocator) !Api.StackTrace {
|
||||
pub fn toAPI(
|
||||
this: *const ZigStackTrace,
|
||||
allocator: std.mem.Allocator,
|
||||
root_path: string,
|
||||
origin: ?*const ZigURL,
|
||||
) !Api.StackTrace {
|
||||
var stack_trace: Api.StackTrace = std.mem.zeroes(Api.StackTrace);
|
||||
{
|
||||
var source_lines_iter = this.sourceLineIterator();
|
||||
@@ -424,7 +429,11 @@ pub const ZigStackTrace = extern struct {
|
||||
stack_trace.frames = stack_frames;
|
||||
|
||||
for (_frames) |frame, i| {
|
||||
stack_frames[i] = try frame.toAPI(allocator);
|
||||
stack_frames[i] = try frame.toAPI(
|
||||
root_path,
|
||||
origin,
|
||||
allocator,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,18 +489,24 @@ pub const ZigStackFrame = extern struct {
|
||||
position: ZigStackFramePosition,
|
||||
code_type: ZigStackFrameCode,
|
||||
|
||||
pub fn toAPI(this: *const ZigStackFrame, allocator: std.mem.Allocator) !Api.StackFrame {
|
||||
/// This informs formatters whether to display as a blob URL or not
|
||||
remapped: bool = false,
|
||||
|
||||
pub fn toAPI(this: *const ZigStackFrame, root_path: string, origin: ?*const ZigURL, allocator: std.mem.Allocator) !Api.StackFrame {
|
||||
var frame: Api.StackFrame = std.mem.zeroes(Api.StackFrame);
|
||||
if (this.function_name.len > 0) {
|
||||
frame.function_name = try allocator.dupe(u8, this.function_name.slice());
|
||||
}
|
||||
|
||||
if (this.source_url.len > 0) {
|
||||
frame.file = try allocator.dupe(u8, this.source_url.slice());
|
||||
frame.file = try std.fmt.allocPrint(allocator, "{any}", .{this.sourceURLFormatter(root_path, origin, true, false)});
|
||||
}
|
||||
|
||||
frame.position.source_offset = this.position.source_offset;
|
||||
frame.position.line = this.position.line;
|
||||
|
||||
// For remapped code, we add 1 to the line number
|
||||
frame.position.line = this.position.line + @as(i32, @boolToInt(this.remapped));
|
||||
|
||||
frame.position.line_start = this.position.line_start;
|
||||
frame.position.line_stop = this.position.line_stop;
|
||||
frame.position.column_start = this.position.column_start;
|
||||
@@ -508,7 +523,8 @@ pub const ZigStackFrame = extern struct {
|
||||
position: ZigStackFramePosition,
|
||||
enable_color: bool,
|
||||
origin: ?*const ZigURL,
|
||||
|
||||
exclude_line_column: bool = false,
|
||||
remapped: bool = false,
|
||||
root_path: string = "",
|
||||
pub fn format(this: SourceURLFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
||||
if (this.enable_color) {
|
||||
@@ -516,16 +532,19 @@ pub const ZigStackFrame = extern struct {
|
||||
}
|
||||
|
||||
var source_slice = this.source_url.slice();
|
||||
if (this.origin) |origin| {
|
||||
try writer.writeAll(origin.displayProtocol());
|
||||
try writer.writeAll("://");
|
||||
try writer.writeAll(origin.displayHostname());
|
||||
try writer.writeAll(":");
|
||||
try writer.writeAll(origin.port);
|
||||
try writer.writeAll("/blob:");
|
||||
|
||||
if (strings.startsWith(source_slice, this.root_path)) {
|
||||
source_slice = source_slice[this.root_path.len..];
|
||||
if (!this.remapped) {
|
||||
if (this.origin) |origin| {
|
||||
try writer.writeAll(origin.displayProtocol());
|
||||
try writer.writeAll("://");
|
||||
try writer.writeAll(origin.displayHostname());
|
||||
try writer.writeAll(":");
|
||||
try writer.writeAll(origin.port);
|
||||
try writer.writeAll("/blob:");
|
||||
|
||||
if (strings.startsWith(source_slice, this.root_path)) {
|
||||
source_slice = source_slice[this.root_path.len..];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,30 +558,32 @@ pub const ZigStackFrame = extern struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.position.line > -1 and this.position.column_start > -1) {
|
||||
if (this.enable_color) {
|
||||
try std.fmt.format(
|
||||
writer,
|
||||
// :
|
||||
comptime Output.prettyFmt("<d>:<r><yellow>{d}<r><d>:<yellow>{d}<r>", true),
|
||||
.{ this.position.line + 1, this.position.column_start },
|
||||
);
|
||||
} else {
|
||||
try std.fmt.format(writer, ":{d}:{d}", .{ this.position.line + 1, this.position.column_start });
|
||||
}
|
||||
} else if (this.position.line > -1) {
|
||||
if (this.enable_color) {
|
||||
try std.fmt.format(
|
||||
writer,
|
||||
comptime Output.prettyFmt("<d>:<r><yellow>{d}<r>", true),
|
||||
.{
|
||||
if (!this.exclude_line_column) {
|
||||
if (this.position.line > -1 and this.position.column_start > -1) {
|
||||
if (this.enable_color) {
|
||||
try std.fmt.format(
|
||||
writer,
|
||||
// :
|
||||
comptime Output.prettyFmt("<d>:<r><yellow>{d}<r><d>:<yellow>{d}<r>", true),
|
||||
.{ this.position.line + 1, this.position.column_start },
|
||||
);
|
||||
} else {
|
||||
try std.fmt.format(writer, ":{d}:{d}", .{ this.position.line + 1, this.position.column_start });
|
||||
}
|
||||
} else if (this.position.line > -1) {
|
||||
if (this.enable_color) {
|
||||
try std.fmt.format(
|
||||
writer,
|
||||
comptime Output.prettyFmt("<d>:<r><yellow>{d}<r>", true),
|
||||
.{
|
||||
this.position.line + 1,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
try std.fmt.format(writer, ":{d}", .{
|
||||
this.position.line + 1,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
try std.fmt.format(writer, ":{d}", .{
|
||||
this.position.line + 1,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -621,8 +642,16 @@ pub const ZigStackFrame = extern struct {
|
||||
return NameFormatter{ .function_name = this.function_name, .code_type = this.code_type, .enable_color = enable_color };
|
||||
}
|
||||
|
||||
pub fn sourceURLFormatter(this: *const ZigStackFrame, root_path: string, origin: ?*const ZigURL, comptime enable_color: bool) SourceURLFormatter {
|
||||
return SourceURLFormatter{ .source_url = this.source_url, .origin = origin, .root_path = root_path, .position = this.position, .enable_color = enable_color };
|
||||
pub fn sourceURLFormatter(this: *const ZigStackFrame, root_path: string, origin: ?*const ZigURL, exclude_line_column: bool, comptime enable_color: bool) SourceURLFormatter {
|
||||
return SourceURLFormatter{
|
||||
.source_url = this.source_url,
|
||||
.exclude_line_column = exclude_line_column,
|
||||
.origin = origin,
|
||||
.root_path = root_path,
|
||||
.position = this.position,
|
||||
.enable_color = enable_color,
|
||||
.remapped = this.remapped,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -670,6 +699,8 @@ pub const ZigException = extern struct {
|
||||
|
||||
exception: ?*anyopaque,
|
||||
|
||||
remapped: bool = false,
|
||||
|
||||
pub const shim = Shimmer("Zig", "Exception", @This());
|
||||
pub const name = "ZigException";
|
||||
pub const namespace = shim.namespace;
|
||||
@@ -736,7 +767,12 @@ pub const ZigException = extern struct {
|
||||
return shim.cppFn("fromException", .{exception});
|
||||
}
|
||||
|
||||
pub fn addToErrorList(this: *ZigException, error_list: *std.ArrayList(Api.JsException)) !void {
|
||||
pub fn addToErrorList(
|
||||
this: *ZigException,
|
||||
error_list: *std.ArrayList(Api.JsException),
|
||||
root_path: string,
|
||||
origin: ?*const ZigURL,
|
||||
) !void {
|
||||
const _name: string = @field(this, "name").slice();
|
||||
const message: string = @field(this, "message").slice();
|
||||
|
||||
@@ -757,7 +793,7 @@ pub const ZigException = extern struct {
|
||||
}
|
||||
|
||||
if (this.stack.frames_len > 0) {
|
||||
api_exception.stack = try this.stack.toAPI(error_list.allocator);
|
||||
api_exception.stack = try this.stack.toAPI(error_list.allocator, root_path, origin);
|
||||
is_empty = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef struct ZigStackFrame {
|
||||
ZigString source_url;
|
||||
ZigStackFramePosition position;
|
||||
ZigStackFrameCode code_type;
|
||||
bool remapped;
|
||||
} ZigStackFrame;
|
||||
|
||||
typedef struct ZigStackTrace {
|
||||
@@ -90,6 +91,7 @@ typedef struct ZigException {
|
||||
ZigString message;
|
||||
ZigStackTrace stack;
|
||||
void* exception;
|
||||
bool remapped;
|
||||
} ZigException;
|
||||
|
||||
typedef uint8_t JSErrorCode;
|
||||
|
||||
@@ -2921,7 +2921,7 @@ pub const VirtualMachine = struct {
|
||||
}
|
||||
|
||||
if (exception_list) |list| {
|
||||
zig_exception.addToErrorList(list) catch {};
|
||||
zig_exception.addToErrorList(list, this.bundler.fs.top_level_dir, &this.origin) catch {};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3067,6 +3067,7 @@ pub const VirtualMachine = struct {
|
||||
frame.sourceURLFormatter(
|
||||
dir,
|
||||
origin,
|
||||
false,
|
||||
allow_ansi_colors,
|
||||
),
|
||||
},
|
||||
@@ -3081,6 +3082,7 @@ pub const VirtualMachine = struct {
|
||||
frame.sourceURLFormatter(
|
||||
dir,
|
||||
origin,
|
||||
false,
|
||||
allow_ansi_colors,
|
||||
),
|
||||
},
|
||||
@@ -3095,10 +3097,13 @@ pub const VirtualMachine = struct {
|
||||
exception: *ZigException,
|
||||
error_instance: JSValue,
|
||||
exception_list: ?*ExceptionList,
|
||||
) !void {
|
||||
) void {
|
||||
error_instance.toZigException(this.global, exception);
|
||||
if (exception_list) |list| {
|
||||
try exception.addToErrorList(list);
|
||||
// defer this so that it copies correctly
|
||||
defer {
|
||||
if (exception_list) |list| {
|
||||
exception.addToErrorList(list, this.bundler.fs.top_level_dir, &this.origin) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
var frames: []JSC.ZigStackFrame = exception.stack.frames_ptr[0..exception.stack.frames_len];
|
||||
@@ -3108,14 +3113,22 @@ pub const VirtualMachine = struct {
|
||||
if (this.source_mappings.resolveMapping(
|
||||
top.source_url.slice(),
|
||||
@maximum(top.position.line, 0),
|
||||
@maximum(top.position.column_stop, 0),
|
||||
@maximum(top.position.column_start, 0),
|
||||
)) |mapping| {
|
||||
var log = logger.Log.init(default_allocator);
|
||||
var original_source = _fetch(this.global, top.source_url.slice(), "", &log, true) catch return;
|
||||
const code = original_source.source_code.slice();
|
||||
top.position.line = mapping.original.lines;
|
||||
top.position.line_start = mapping.original.lines;
|
||||
top.position.line_stop = mapping.original.lines + 1;
|
||||
top.position.column_start = mapping.original.columns;
|
||||
top.position.column_stop = mapping.original.columns + 1;
|
||||
exception.remapped = true;
|
||||
top.remapped = true;
|
||||
// This expression range is no longer accurate
|
||||
top.position.expression_start = mapping.original.columns;
|
||||
top.position.expression_stop = mapping.original.columns + 1;
|
||||
|
||||
if (strings.getLinesInText(
|
||||
code,
|
||||
@intCast(u32, top.position.line),
|
||||
@@ -3133,6 +3146,13 @@ pub const VirtualMachine = struct {
|
||||
}
|
||||
|
||||
exception.stack.source_lines_len = @intCast(u8, lines_.len);
|
||||
|
||||
top.position.column_stop = @intCast(i32, source_lines[lines_.len - 1].len);
|
||||
top.position.line_stop = top.position.column_stop;
|
||||
|
||||
// This expression range is no longer accurate
|
||||
top.position.expression_start = mapping.original.columns;
|
||||
top.position.expression_stop = top.position.column_stop;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3145,6 +3165,7 @@ pub const VirtualMachine = struct {
|
||||
@maximum(frame.position.column_start, 0),
|
||||
)) |mapping| {
|
||||
frame.position.line = mapping.original.lines;
|
||||
frame.remapped = true;
|
||||
frame.position.column_start = mapping.original.columns;
|
||||
}
|
||||
}
|
||||
@@ -3154,7 +3175,7 @@ pub const VirtualMachine = struct {
|
||||
pub fn printErrorInstance(this: *VirtualMachine, error_instance: JSValue, exception_list: ?*ExceptionList, comptime Writer: type, writer: Writer, comptime allow_ansi_color: bool) !void {
|
||||
var exception_holder = ZigException.Holder.init();
|
||||
var exception = exception_holder.zigException();
|
||||
try this.remapZigException(exception, error_instance, exception_list);
|
||||
this.remapZigException(exception, error_instance, exception_list);
|
||||
this.had_errors = true;
|
||||
|
||||
var line_numbers = exception.stack.source_lines_numbers[0..exception.stack.source_lines_len];
|
||||
@@ -3217,7 +3238,7 @@ pub const VirtualMachine = struct {
|
||||
writer.writeByteNTimes(' ', pad) catch unreachable;
|
||||
const top = exception.stack.frames()[0];
|
||||
var remainder = std.mem.trim(u8, source.text, "\n");
|
||||
if (@intCast(usize, top.position.column_stop) > remainder.len) {
|
||||
if (@intCast(usize, top.position.column_stop) > remainder.len or (top.position.column_stop - top.position.column_start) <= 0) {
|
||||
writer.print(
|
||||
comptime Output.prettyFmt(
|
||||
"<r><d>{d} |<r> {s}\n",
|
||||
|
||||
@@ -486,8 +486,7 @@ pub const TextDecoder = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str.toValueGC(ctx.ptr()).asObjectRef();
|
||||
return str.toValue(ctx.ptr()).asObjectRef();
|
||||
},
|
||||
|
||||
EncodingLabel.@"UTF-16LE" => {
|
||||
|
||||
Reference in New Issue
Block a user