mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
fix(bundler): some sourcemap generation bugs (#11344)
Co-authored-by: paperdave <paperdave@users.noreply.github.com> Co-authored-by: Meghan Denny <meghan@bun.sh> Co-authored-by: nektro <nektro@users.noreply.github.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com> Co-authored-by: Le Michel <95184938+Ptitet@users.noreply.github.com> Co-authored-by: Дмитрий Заводской <zawodskoj2@gmail.com> Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Co-authored-by: HUMORCE <humorce@outlook.com> Co-authored-by: huseeiin <122984423+huseeiin@users.noreply.github.com>
This commit is contained in:
@@ -484,11 +484,6 @@ pub const Mapping = struct {
|
||||
}
|
||||
remain = remain[source_index_delta.start..];
|
||||
|
||||
// // "AAAA" is extremely common
|
||||
// if (strings.hasPrefixComptime(remain, "AAAA;")) {
|
||||
|
||||
// }
|
||||
|
||||
// Read the original line
|
||||
const original_line_delta = decodeVLQ(remain, 0);
|
||||
if (original_line_delta.start == 0) {
|
||||
@@ -713,7 +708,15 @@ pub const SourceProviderMap = opaque {
|
||||
arena.allocator(),
|
||||
found_url.slice(),
|
||||
result,
|
||||
) catch return null,
|
||||
) catch |err| {
|
||||
bun.Output.warn("Could not decode sourcemap in '{s}': {s}", .{
|
||||
source_filename,
|
||||
@errorName(err),
|
||||
});
|
||||
// Disable the "try using --sourcemap=external" hint
|
||||
bun.JSC.SavedSourceMap.MissingSourceMapNoteInfo.seen_invalid = true;
|
||||
return null;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -725,11 +728,8 @@ pub const SourceProviderMap = opaque {
|
||||
@memcpy(load_path_buf[0..source_filename.len], source_filename);
|
||||
@memcpy(load_path_buf[source_filename.len..][0..4], ".map");
|
||||
|
||||
const data = switch (bun.sys.File.readFrom(
|
||||
std.fs.cwd(),
|
||||
load_path_buf[0 .. source_filename.len + 4],
|
||||
arena.allocator(),
|
||||
)) {
|
||||
const load_path = load_path_buf[0 .. source_filename.len + 4];
|
||||
const data = switch (bun.sys.File.readFrom(std.fs.cwd(), load_path, arena.allocator())) {
|
||||
.err => break :try_external,
|
||||
.result => |data| data,
|
||||
};
|
||||
@@ -741,7 +741,15 @@ pub const SourceProviderMap = opaque {
|
||||
arena.allocator(),
|
||||
data,
|
||||
result,
|
||||
) catch return null,
|
||||
) catch |err| {
|
||||
bun.Output.warn("Could not decode sourcemap '{s}': {s}", .{
|
||||
source_filename,
|
||||
@errorName(err),
|
||||
});
|
||||
// Disable the "try using --sourcemap=external" hint
|
||||
bun.JSC.SavedSourceMap.MissingSourceMapNoteInfo.seen_invalid = true;
|
||||
return null;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -766,14 +774,14 @@ pub const LineColumnOffset = struct {
|
||||
pub fn advance(this: *Optional, input: []const u8) void {
|
||||
switch (this.*) {
|
||||
.null => {},
|
||||
.value => this.value.advance(input),
|
||||
.value => |*v| v.advance(input),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(this: *Optional) void {
|
||||
switch (this.*) {
|
||||
.null => {},
|
||||
.value => this.value = .{},
|
||||
.value => this.* = .{ .value = .{} },
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -787,9 +795,13 @@ pub const LineColumnOffset = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn advance(this: *LineColumnOffset, input: []const u8) void {
|
||||
var columns = this.columns;
|
||||
defer this.columns = columns;
|
||||
pub fn advance(this_ptr: *LineColumnOffset, input: []const u8) void {
|
||||
// Instead of mutating `this_ptr` directly, copy the state to the stack and do
|
||||
// all the work here, then move it back to the input pointer. When sourcemaps
|
||||
// are enabled, this function is extremely hot.
|
||||
var this = this_ptr.*;
|
||||
defer this_ptr.* = this;
|
||||
|
||||
var offset: u32 = 0;
|
||||
while (strings.indexOfNewlineOrNonASCII(input, offset)) |i| {
|
||||
assert(i >= offset);
|
||||
@@ -803,7 +815,7 @@ pub const LineColumnOffset = struct {
|
||||
// This can lead to integer overflow, crashes, or hangs.
|
||||
// https://github.com/oven-sh/bun/issues/10624
|
||||
if (cursor.width == 0) {
|
||||
columns += 1;
|
||||
this.columns += 1;
|
||||
offset = i + 1;
|
||||
continue;
|
||||
}
|
||||
@@ -814,22 +826,32 @@ pub const LineColumnOffset = struct {
|
||||
'\r', '\n', 0x2028, 0x2029 => {
|
||||
// Handle Windows-specific "\r\n" newlines
|
||||
if (cursor.c == '\r' and input.len > i + 1 and input[i + 1] == '\n') {
|
||||
columns += 1;
|
||||
this.columns += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
this.lines += 1;
|
||||
columns = 0;
|
||||
this.columns = 0;
|
||||
},
|
||||
else => |c| {
|
||||
// Mozilla's "source-map" library counts columns using UTF-16 code units
|
||||
columns += switch (c) {
|
||||
this.columns += switch (c) {
|
||||
0...0xFFFF => 1,
|
||||
else => 2,
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const remain = input[offset..];
|
||||
|
||||
if (bun.Environment.allow_assert) {
|
||||
assert(bun.strings.isAllASCII(remain));
|
||||
assert(!bun.strings.containsChar(remain, '\n'));
|
||||
assert(!bun.strings.containsChar(remain, '\r'));
|
||||
}
|
||||
|
||||
this.columns += @intCast(remain.len);
|
||||
}
|
||||
|
||||
pub fn comesBefore(a: LineColumnOffset, b: LineColumnOffset) bool {
|
||||
@@ -977,43 +999,44 @@ pub fn appendSourceMapChunk(j: *StringJoiner, allocator: std.mem.Allocator, prev
|
||||
var prev_end_state = prev_end_state_;
|
||||
var start_state = start_state_;
|
||||
// Handle line breaks in between this mapping and the previous one
|
||||
if (start_state.generated_line > 0) {
|
||||
if (start_state.generated_line != 0) {
|
||||
j.push(try strings.repeatingAlloc(allocator, @intCast(start_state.generated_line), ';'), allocator);
|
||||
prev_end_state.generated_column = 0;
|
||||
}
|
||||
|
||||
// Skip past any leading semicolons, which indicate line breaks
|
||||
var source_map = source_map_;
|
||||
if (strings.indexOfNotChar(source_map, ';')) |semicolons| {
|
||||
j.pushStatic(source_map[0..semicolons]);
|
||||
source_map = source_map[semicolons..];
|
||||
prev_end_state.generated_column = 0;
|
||||
start_state.generated_column = 0;
|
||||
if (semicolons > 0) {
|
||||
j.pushStatic(source_map[0..semicolons]);
|
||||
source_map = source_map[semicolons..];
|
||||
prev_end_state.generated_column = 0;
|
||||
start_state.generated_column = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Strip off the first mapping from the buffer. The first mapping should be
|
||||
// for the start of the original file (the printer always generates one for
|
||||
// the start of the file).
|
||||
//
|
||||
// Bun has a 24-byte header for source map meta-data
|
||||
var i: usize = 0;
|
||||
const generated_column_ = decodeVLQAssumeValid(source_map, i);
|
||||
i = generated_column_.start;
|
||||
const source_index_ = decodeVLQAssumeValid(source_map, i);
|
||||
i = source_index_.start;
|
||||
const original_line_ = decodeVLQAssumeValid(source_map, i);
|
||||
i = original_line_.start;
|
||||
const original_column_ = decodeVLQAssumeValid(source_map, i);
|
||||
i = original_column_.start;
|
||||
const generated_column = decodeVLQAssumeValid(source_map, i);
|
||||
i = generated_column.start;
|
||||
const source_index = decodeVLQAssumeValid(source_map, i);
|
||||
i = source_index.start;
|
||||
const original_line = decodeVLQAssumeValid(source_map, i);
|
||||
i = original_line.start;
|
||||
const original_column = decodeVLQAssumeValid(source_map, i);
|
||||
i = original_column.start;
|
||||
|
||||
source_map = source_map[i..];
|
||||
|
||||
// Rewrite the first mapping to be relative to the end state of the previous
|
||||
// chunk. We now know what the end state is because we're in the second pass
|
||||
// where all chunks have already been generated.
|
||||
start_state.source_index += source_index_.value;
|
||||
start_state.generated_column += generated_column_.value;
|
||||
start_state.original_line += original_line_.value;
|
||||
start_state.original_column += original_column_.value;
|
||||
start_state.source_index += source_index.value;
|
||||
start_state.generated_column += generated_column.value;
|
||||
start_state.original_line += original_line.value;
|
||||
start_state.original_column += original_column.value;
|
||||
|
||||
j.push(
|
||||
appendMappingToBuffer(
|
||||
|
||||
Reference in New Issue
Block a user