mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 10:58:56 +00:00
[bun.js] Map the sources when handling the error
This commit is contained in:
@@ -19,6 +19,7 @@ const NetworkThread = @import("http").NetworkThread;
|
||||
pub fn zigCast(comptime Destination: type, value: anytype) *Destination {
|
||||
return @ptrCast(*Destination, @alignCast(@alignOf(*Destination), value));
|
||||
}
|
||||
const Allocator = std.mem.Allocator;
|
||||
const IdentityContext = @import("../../identity_context.zig").IdentityContext;
|
||||
const Fs = @import("../../fs.zig");
|
||||
const Resolver = @import("../../resolver/resolver.zig");
|
||||
@@ -1705,6 +1706,7 @@ pub const Task = TaggedPointerUnion(.{
|
||||
});
|
||||
|
||||
const SourceMap = @import("../../sourcemap/sourcemap.zig");
|
||||
const MappingList = SourceMap.Mapping.List;
|
||||
|
||||
pub const SavedSourceMap = struct {
|
||||
// For bun.js, we store the number of mappings and how many bytes the final list is at the beginning of the array
|
||||
@@ -1718,26 +1720,65 @@ pub const SavedSourceMap = struct {
|
||||
}
|
||||
|
||||
pub inline fn len(this: SavedMappings) usize {
|
||||
return @bitCast(u64, this.data[0..8]);
|
||||
return @bitCast(u64, this.data[0..8].*);
|
||||
}
|
||||
|
||||
pub fn deinit(this: SavedMappings) []u8 {
|
||||
pub fn deinit(this: SavedMappings) void {
|
||||
default_allocator.free(this.data[0..this.len()]);
|
||||
}
|
||||
|
||||
pub fn toMapping(this: SavedMappings, allocator: Allocator, path: string) anyerror!MappingList {
|
||||
const result = SourceMap.Mapping.parse(
|
||||
allocator,
|
||||
this.data[16..this.len()],
|
||||
@bitCast(usize, this.data[8..16].*),
|
||||
1,
|
||||
);
|
||||
switch (result) {
|
||||
.fail => |fail| {
|
||||
if (Output.enable_ansi_colors_stderr) {
|
||||
try fail.toData(path).writeFormat(
|
||||
Output.errorWriter(),
|
||||
logger.Kind.warn,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
try fail.toData(path).writeFormat(
|
||||
Output.errorWriter(),
|
||||
logger.Kind.warn,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
return fail.err;
|
||||
},
|
||||
.success => |success| {
|
||||
return success;
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Value = TaggedPointerUnion(.{ SourceMap, SavedMappings });
|
||||
pub const Value = TaggedPointerUnion(.{ MappingList, SavedMappings });
|
||||
pub const HashTable = std.HashMap(u64, *anyopaque, IdentityContext(u64), 80);
|
||||
|
||||
map: HashTable,
|
||||
|
||||
pub fn onSourceMapChunk(this: *SavedSourceMap, chunk: SourceMap.Chunk, source: logger.Source) anyerror!void {
|
||||
try this.putMappings(source, chunk.buffer);
|
||||
}
|
||||
|
||||
pub const SourceMapHandler = js_printer.SourceMapHandler.For(SavedSourceMap, onSourceMapChunk);
|
||||
|
||||
pub fn putMappings(this: *SavedSourceMap, source: logger.Source, mappings: MutableString) !void {
|
||||
var entry = try this.map.getOrPut(std.hash.Wyhash.hash(0, source.path.text));
|
||||
if (entry.found_existing) {
|
||||
var value = Value.from(entry.value_ptr.*);
|
||||
if (value.get(SourceMap)) |source_map_| {
|
||||
var source_map: *SourceMap = source_map_;
|
||||
source_map.deinit();
|
||||
if (value.get(MappingList)) |source_map_| {
|
||||
var source_map: *MappingList = source_map_;
|
||||
source_map.deinit(default_allocator);
|
||||
} else if (value.get(SavedMappings)) |saved_mappings| {
|
||||
var saved = SavedMappings{ .data = @ptrCast([*]u8, saved_mappings) };
|
||||
|
||||
@@ -1745,22 +1786,39 @@ pub const SavedSourceMap = struct {
|
||||
}
|
||||
}
|
||||
|
||||
entry.value_ptr.* = Value.init(@ptrCast(*SavedMappings, mappings.list.items.ptr)).ptr();
|
||||
entry.value_ptr.* = Value.init(bun.cast(*SavedMappings, mappings.list.items.ptr)).ptr();
|
||||
}
|
||||
|
||||
pub fn get(this: *SavedSourceMap, allocator: std.mem.Allocator, path: string) ?*SourceMap {
|
||||
pub fn get(this: *SavedSourceMap, path: string) ?MappingList {
|
||||
var mapping = this.map.getEntry(std.hash.Wyhash.hash(0, path)) orelse return null;
|
||||
switch (Value.from(mapping.value_ptr.*).tag()) {
|
||||
SourceMap => {
|
||||
return Value.from(mapping).as(SourceMap);
|
||||
(@field(Value.Tag, @typeName(MappingList))) => {
|
||||
return Value.from(mapping.value_ptr.*).as(MappingList).*;
|
||||
},
|
||||
SavedMappings => {
|
||||
_ = allocator;
|
||||
return null;
|
||||
Value.Tag.SavedMappings => {
|
||||
var saved = SavedMappings{ .data = @ptrCast([*]u8, Value.from(mapping.value_ptr.*).as(MappingList)) };
|
||||
defer saved.deinit();
|
||||
var result = default_allocator.create(MappingList) catch unreachable;
|
||||
result.* = saved.toMapping(default_allocator, path) catch {
|
||||
_ = this.map.remove(mapping.key_ptr.*);
|
||||
return null;
|
||||
};
|
||||
mapping.value_ptr.* = Value.init(result).ptr();
|
||||
return result.*;
|
||||
},
|
||||
else => return null,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolveMapping(
|
||||
this: *SavedSourceMap,
|
||||
path: []const u8,
|
||||
line: i32,
|
||||
column: i32,
|
||||
) ?SourceMap.Mapping {
|
||||
var mappings = this.get(path) orelse return null;
|
||||
return SourceMap.Mapping.find(mappings, line, column);
|
||||
}
|
||||
};
|
||||
|
||||
// If you read JavascriptCore/API/JSVirtualMachine.mm - https://github.com/WebKit/WebKit/blob/acff93fb303baa670c055cb24c2bad08691a01a0/Source/JavaScriptCore/API/JSVirtualMachine.mm#L101
|
||||
@@ -2085,6 +2143,7 @@ pub const VirtualMachine = struct {
|
||||
_specifier: string,
|
||||
_: string,
|
||||
log: *logger.Log,
|
||||
comptime disable_transpilying: bool,
|
||||
) !ResolvedSource {
|
||||
std.debug.assert(VirtualMachine.vm_loaded);
|
||||
var jsc_vm = vm;
|
||||
@@ -2117,6 +2176,15 @@ pub const VirtualMachine = struct {
|
||||
// so it consistently handles bundled imports
|
||||
// we can't take the shortcut of just directly importing the file, sadly.
|
||||
} else if (strings.eqlComptime(_specifier, main_file_name)) {
|
||||
if (comptime disable_transpilying) {
|
||||
return ResolvedSource{
|
||||
.allocator = null,
|
||||
.source_code = ZigString.init(jsc_vm.entry_point.source.contents),
|
||||
.specifier = ZigString.init(std.mem.span(main_file_name)),
|
||||
.source_url = ZigString.init(std.mem.span(main_file_name)),
|
||||
.hash = 0,
|
||||
};
|
||||
}
|
||||
defer jsc_vm.transpiled_count += 1;
|
||||
|
||||
var bundler = &jsc_vm.bundler;
|
||||
@@ -2160,11 +2228,12 @@ pub const VirtualMachine = struct {
|
||||
printer.ctx.reset();
|
||||
{
|
||||
defer source_code_printer.?.* = printer;
|
||||
written = try jsc_vm.bundler.print(
|
||||
written = try jsc_vm.bundler.printWithSourceMap(
|
||||
parse_result,
|
||||
@TypeOf(&printer),
|
||||
&printer,
|
||||
.esm_ascii,
|
||||
SavedSourceMap.SourceMapHandler.init(&jsc_vm.source_mappings),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2182,14 +2251,16 @@ pub const VirtualMachine = struct {
|
||||
} else if (_specifier.len > js_ast.Macro.namespaceWithColon.len and
|
||||
strings.eqlComptimeIgnoreLen(_specifier[0..js_ast.Macro.namespaceWithColon.len], js_ast.Macro.namespaceWithColon))
|
||||
{
|
||||
if (jsc_vm.macro_entry_points.get(MacroEntryPoint.generateIDFromSpecifier(_specifier))) |entry| {
|
||||
return ResolvedSource{
|
||||
.allocator = null,
|
||||
.source_code = ZigString.init(entry.source.contents),
|
||||
.specifier = ZigString.init(_specifier),
|
||||
.source_url = ZigString.init(_specifier),
|
||||
.hash = 0,
|
||||
};
|
||||
if (comptime !disable_transpilying) {
|
||||
if (jsc_vm.macro_entry_points.get(MacroEntryPoint.generateIDFromSpecifier(_specifier))) |entry| {
|
||||
return ResolvedSource{
|
||||
.allocator = null,
|
||||
.source_code = ZigString.init(entry.source.contents),
|
||||
.specifier = ZigString.init(_specifier),
|
||||
.source_url = ZigString.init(_specifier),
|
||||
.hash = 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
} else if (strings.eqlComptime(_specifier, "node:fs")) {
|
||||
return ResolvedSource{
|
||||
@@ -2275,13 +2346,24 @@ pub const VirtualMachine = struct {
|
||||
}
|
||||
}
|
||||
|
||||
var parse_result = jsc_vm.bundler.parse(
|
||||
var parse_result = jsc_vm.bundler.parseMaybeReturnFileOnly(
|
||||
parse_options,
|
||||
null,
|
||||
disable_transpilying,
|
||||
) orelse {
|
||||
return error.ParseError;
|
||||
};
|
||||
|
||||
if (comptime disable_transpilying) {
|
||||
return ResolvedSource{
|
||||
.allocator = null,
|
||||
.source_code = ZigString.init(parse_result.source.contents),
|
||||
.specifier = ZigString.init(specifier),
|
||||
.source_url = ZigString.init(path.text),
|
||||
.hash = 0,
|
||||
};
|
||||
}
|
||||
|
||||
const start_count = jsc_vm.bundler.linker.import_counter;
|
||||
// We _must_ link because:
|
||||
// - node_modules bundle won't be properly
|
||||
@@ -2302,11 +2384,12 @@ pub const VirtualMachine = struct {
|
||||
printer.ctx.reset();
|
||||
{
|
||||
defer source_code_printer.?.* = printer;
|
||||
written = try jsc_vm.bundler.print(
|
||||
written = try jsc_vm.bundler.printWithSourceMap(
|
||||
parse_result,
|
||||
@TypeOf(&printer),
|
||||
&printer,
|
||||
.esm_ascii,
|
||||
SavedSourceMap.SourceMapHandler.init(&jsc_vm.source_mappings),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2565,7 +2648,7 @@ pub const VirtualMachine = struct {
|
||||
pub fn fetch(ret: *ErrorableResolvedSource, global: *JSGlobalObject, specifier: ZigString, source: ZigString) callconv(.C) void {
|
||||
var log = logger.Log.init(vm.bundler.allocator);
|
||||
const spec = specifier.slice();
|
||||
const result = _fetch(global, spec, source.slice(), &log) catch |err| {
|
||||
const result = _fetch(global, spec, source.slice(), &log, false) catch |err| {
|
||||
processFetchLog(global, specifier, source, &log, ret, err);
|
||||
return;
|
||||
};
|
||||
@@ -2987,14 +3070,71 @@ 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();
|
||||
error_instance.toZigException(vm.global, exception);
|
||||
fn remapZigException(
|
||||
this: *VirtualMachine,
|
||||
exception: *ZigException,
|
||||
error_instance: JSValue,
|
||||
exception_list: ?*ExceptionList,
|
||||
) !void {
|
||||
error_instance.toZigException(this.global, exception);
|
||||
if (exception_list) |list| {
|
||||
try exception.addToErrorList(list);
|
||||
}
|
||||
|
||||
var frames: []JSC.ZigStackFrame = exception.stack.frames_ptr[0..exception.stack.frames_len];
|
||||
if (frames.len == 0) return;
|
||||
|
||||
var top = &frames[0];
|
||||
if (this.source_mappings.resolveMapping(
|
||||
top.source_url.slice(),
|
||||
@maximum(top.position.line, 0),
|
||||
@maximum(top.position.column_stop, 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.column_start = mapping.original.columns;
|
||||
top.position.expression_start = mapping.original.columns;
|
||||
if (strings.getLinesInText(
|
||||
code,
|
||||
@intCast(u32, top.position.line),
|
||||
JSC.ZigException.Holder.source_lines_count,
|
||||
)) |lines| {
|
||||
var source_lines = exception.stack.source_lines_ptr[0..JSC.ZigException.Holder.source_lines_count];
|
||||
var source_line_numbers = exception.stack.source_lines_numbers[0..JSC.ZigException.Holder.source_lines_count];
|
||||
std.mem.set(ZigString, source_lines, ZigString.Empty);
|
||||
std.mem.set(i32, source_line_numbers, 0);
|
||||
|
||||
var lines_ = lines[0..@minimum(lines.len, source_lines.len)];
|
||||
for (lines_) |line, j| {
|
||||
source_lines[(lines_.len - 1) - j] = ZigString.init(line);
|
||||
source_line_numbers[j] = top.position.line - @intCast(i32, j) + 1;
|
||||
}
|
||||
|
||||
exception.stack.source_lines_len = @intCast(u8, lines_.len);
|
||||
}
|
||||
}
|
||||
|
||||
if (frames.len > 1) {
|
||||
for (frames[1..]) |*frame| {
|
||||
if (frame.position.isInvalid()) continue;
|
||||
if (this.source_mappings.resolveMapping(
|
||||
frame.source_url.slice(),
|
||||
@maximum(frame.position.line, 0),
|
||||
@maximum(frame.position.column_start, 0),
|
||||
)) |mapping| {
|
||||
frame.position.line = mapping.original.lines;
|
||||
frame.position.column_start = mapping.original.columns;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.had_errors = true;
|
||||
|
||||
var line_numbers = exception.stack.source_lines_numbers[0..exception.stack.source_lines_len];
|
||||
|
||||
Reference in New Issue
Block a user