-
Notifications
You must be signed in to change notification settings - Fork 4.7k
sourcemap: bit-packed InternalSourceMap (~2.4 B/mapping, no decode) #29358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b18fac2
631a655
0d6bbb1
bd62e3f
dc4ad33
371cbc2
5ab24dd
3af7239
960ba47
baf016d
00ecf84
db32176
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| big-module.generated.ts |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| // Microbench for the InternalSourceMap stack-trace remapping path. Compare | ||
| // against a baseline build by running: | ||
| // | ||
| // bun run build:release bench/sourcemap/internal-sourcemap-bench.ts | ||
| // | ||
| // On first run this generates a ~150k-line .ts module next to this file so the | ||
| // stack frames being remapped live inside a large SavedSourceMap entry. | ||
|
|
||
| import fs from "node:fs"; | ||
| import path from "node:path"; | ||
|
|
||
| const ITER = 10_000; | ||
| const BIG_LINES = 150_000; | ||
|
|
||
| const flag = process.argv[2] ?? "bench"; | ||
| const mb = (n: number) => (n / 1048576).toFixed(2) + " MB"; | ||
|
|
||
| const bigPath = path.join(import.meta.dir, "big-module.generated.ts"); | ||
| if (!fs.existsSync(bigPath)) { | ||
| let src = "let v: number = 0;\n"; | ||
| for (let i = 0; i < BIG_LINES; i++) src += `v = (v + ${i % 97}) | 0;\n`; | ||
| src += "export function go(): string { return new Error('e').stack!; }\n"; | ||
| fs.writeFileSync(bigPath, src); | ||
| } | ||
|
|
||
| const rssBefore = process.memoryUsage().rss; | ||
| const tLoad0 = performance.now(); | ||
| const { go } = require(bigPath) as { go: () => string }; | ||
| const tLoad1 = performance.now(); | ||
| const rssAfterLoad = process.memoryUsage().rss; | ||
|
|
||
| // First .stack: triggers full VLQ decode in the old path. | ||
| const tFirst0 = performance.now(); | ||
| let s = go(); | ||
| const tFirst1 = performance.now(); | ||
| const rssAfterFirst = process.memoryUsage().rss; | ||
|
|
||
| const t0 = performance.now(); | ||
| for (let i = 0; i < ITER; i++) s = go(); | ||
| const t1 = performance.now(); | ||
| const rssAfterLoop = process.memoryUsage().rss; | ||
|
|
||
| console.log(`[${flag}] load big module: ${(tLoad1 - tLoad0).toFixed(2)} ms`); | ||
| console.log(`[${flag}] first new Error().stack: ${(tFirst1 - tFirst0).toFixed(3)} ms`); | ||
| console.log( | ||
| `[${flag}] ${ITER}x new Error().stack: ${(t1 - t0).toFixed(2)} ms (${(((t1 - t0) * 1000) / ITER).toFixed(2)} µs/op)`, | ||
| ); | ||
| console.log( | ||
| `[${flag}] rss before/afterLoad/afterFirst/afterLoop: ${mb(rssBefore)} / ${mb(rssAfterLoad)} / ${mb(rssAfterFirst)} / ${mb(rssAfterLoop)}`, | ||
| ); | ||
| console.log(`[${flag}] rss delta load→firstStack: ${mb(rssAfterFirst - rssAfterLoad)}`); | ||
| void s; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -264,25 +264,25 @@ | |
| defer init_lock.unlock(); | ||
|
|
||
| return switch (this.*) { | ||
| .none => null, | ||
| .parsed => |map| map, | ||
| .serialized => |serialized| { | ||
| var stored = switch (SourceMap.Mapping.parse( | ||
| bun.default_allocator, | ||
| serialized.mappingVLQ(), | ||
| null, | ||
| std.math.maxInt(i32), | ||
| std.math.maxInt(i32), | ||
| .{}, | ||
| )) { | ||
| .success => |x| x, | ||
| .fail => { | ||
| this.* = .none; | ||
| return null; | ||
| }, | ||
| const blob = serialized.mappingBlob() orelse { | ||
| this.* = .none; | ||
| return null; | ||
| }; | ||
| if (!SourceMap.InternalSourceMap.isValidBlob(blob)) { | ||
| this.* = .none; | ||
| return null; | ||
| } | ||
| const ism = SourceMap.InternalSourceMap{ .data = blob.ptr }; | ||
| var stored: SourceMap.ParsedSourceMap = .{ | ||
| .ref_count = .init(), | ||
| .internal = ism, | ||
| .input_line_count = ism.inputLineCount(), | ||
| }; | ||
|
|
||
| const source_files = serialized.sourceFileNames(); | ||
|
Check failure on line 285 in src/StandaloneModuleGraph.zig
|
||
|
claude[bot] marked this conversation as resolved.
Comment on lines
267
to
285
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 In Extended reasoning...What the bug is and how it manifests In const slices = bun.default_allocator.alloc(?[]u8, source_files.len * 2);The first half becomes stored.external_source_names = file_names; // N borrowed pointers
stored.is_standalone_module_graph = true;
parsed.ref(); // never freeThe specific code path that triggers it
if (this.external_source_names.len > 0) {
for (this.external_source_names) |name|
allocator.free(name); // (1) frees borrowed blob pointers
allocator.free(this.external_source_names); // (2) size-N free of a 2N allocation
}This has no if (this.internal) |ism| {
if (\!this.is_standalone_module_graph) ism.deinit(); // ← guarded
}The inconsistency — adding the guard for ISM but not for Why existing code doesn't prevent it The protection is entirely behavioral: What the impact would be If
Step-by-step proof
How to fix it Add the same guard to the if (this.external_source_names.len > 0 and \!this.is_standalone_module_graph) {
for (this.external_source_names) |name|
allocator.free(name);
allocator.free(this.external_source_names);
}This mirrors exactly the pattern already used for |
||
| const slices = bun.handleOom(bun.default_allocator.alloc(?[]u8, source_files.len * 2)); | ||
|
|
||
| const file_names: [][]const u8 = @ptrCast(slices[0..source_files.len]); | ||
|
|
@@ -1358,14 +1358,15 @@ | |
|
|
||
| /// Source map serialization in the bundler is specially designed to be | ||
| /// loaded in memory as is. Source contents are compressed with ZSTD to | ||
| /// reduce the file size, and mappings are stored as uncompressed VLQ. | ||
| /// reduce the file size, and mappings are stored as an InternalSourceMap | ||
| /// blob (varint deltas + sync points) so lookups need no decode pass. | ||
| pub const SerializedSourceMap = struct { | ||
| bytes: []const u8, | ||
|
|
||
| /// Following the header bytes: | ||
| /// - source_files_count number of StringPointer, file names | ||
| /// - source_files_count number of StringPointer, zstd compressed contents | ||
| /// - the mapping data, `map_vlq_length` bytes | ||
| /// - the InternalSourceMap blob, `map_bytes_length` bytes | ||
| /// - all the StringPointer contents | ||
| pub const Header = extern struct { | ||
| source_files_count: u32, | ||
|
|
@@ -1376,9 +1377,11 @@ | |
| return @ptrCast(map.bytes.ptr); | ||
| } | ||
|
|
||
| pub fn mappingVLQ(map: SerializedSourceMap) []const u8 { | ||
| pub fn mappingBlob(map: SerializedSourceMap) ?[]const u8 { | ||
| if (map.bytes.len < @sizeOf(Header)) return null; | ||
| const head = map.header(); | ||
| const start = @sizeOf(Header) + head.source_files_count * @sizeOf(StringPointer) * 2; | ||
| if (start > map.bytes.len or head.map_bytes_length > map.bytes.len - start) return null; | ||
| return map.bytes[start..][0..head.map_bytes_length]; | ||
| } | ||
|
|
||
|
|
@@ -1466,14 +1469,16 @@ | |
| } | ||
|
|
||
| const map_vlq: []const u8 = mappings_str.data.e_string.slice(arena); | ||
| const map_blob = SourceMap.InternalSourceMap.fromVLQ(arena, map_vlq, 0) catch | ||
| return error.InvalidSourceMap; | ||
|
claude[bot] marked this conversation as resolved.
|
||
|
|
||
| try out.writeInt(u32, sources_paths.items.len, .little); | ||
| try out.writeInt(u32, @intCast(map_vlq.len), .little); | ||
| try out.writeInt(u32, @intCast(map_blob.len), .little); | ||
|
|
||
| const string_payload_start_location = @sizeOf(u32) + | ||
| @sizeOf(u32) + | ||
| @sizeOf(bun.StringPointer) * sources_content.items.len * 2 + // path + source | ||
| map_vlq.len; | ||
| map_blob.len; | ||
|
|
||
| for (sources_paths.items.slice()) |item| { | ||
| if (item.data != .e_string) | ||
|
|
@@ -1519,7 +1524,7 @@ | |
| try out.writeInt(u32, slice.length, .little); | ||
| } | ||
|
|
||
| try out.writeAll(map_vlq); | ||
| try out.writeAll(map_blob); | ||
|
|
||
| bun.assert(header_list.items.len == string_payload_start_location); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,7 +4,12 @@ const SavedSourceMap = @This(); | |||||||||||||||||||||
| map: *HashTable, | ||||||||||||||||||||||
| mutex: bun.Mutex = .{}, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub const vlq_offset = 24; | ||||||||||||||||||||||
| /// Warm cache for `remapStackFramePositions`: the last decoded sync window and | ||||||||||||||||||||||
| /// the last (path_hash -> ISM) resolution. Guarded by `mutex`. Invalidated on | ||||||||||||||||||||||
| /// any `putValue` since that may free the cached blob. | ||||||||||||||||||||||
| find_cache: InternalSourceMap.FindCache = .{}, | ||||||||||||||||||||||
| last_path_hash: u64 = 0, | ||||||||||||||||||||||
| last_ism: ?InternalSourceMap = null, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub fn init(this: *SavedSourceMap, map: *HashTable) void { | ||||||||||||||||||||||
| this.* = .{ | ||||||||||||||||||||||
|
|
@@ -25,70 +30,16 @@ pub inline fn unlock(map: *SavedSourceMap) void { | |||||||||||||||||||||
| map.mutex.unlock(); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // For the runtime, we store the number of mappings and how many bytes the final list is at the beginning of the array | ||||||||||||||||||||||
| // The first 8 bytes are the length of the array | ||||||||||||||||||||||
| // The second 8 bytes are the number of mappings | ||||||||||||||||||||||
| pub const SavedMappings = struct { | ||||||||||||||||||||||
| data: [*]u8, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub fn vlq(this: SavedMappings) []u8 { | ||||||||||||||||||||||
| return this.data[vlq_offset..this.len()]; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub inline fn len(this: SavedMappings) usize { | ||||||||||||||||||||||
| return @as(u64, @bitCast(this.data[0..8].*)); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub fn deinit(this: SavedMappings) void { | ||||||||||||||||||||||
| bun.default_allocator.free(this.data[0..this.len()]); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub fn toMapping(this: SavedMappings, allocator: Allocator, path: string) anyerror!ParsedSourceMap { | ||||||||||||||||||||||
| const result = SourceMap.Mapping.parse( | ||||||||||||||||||||||
| allocator, | ||||||||||||||||||||||
| this.data[vlq_offset..this.len()], | ||||||||||||||||||||||
| @as(usize, @bitCast(this.data[8..16].*)), | ||||||||||||||||||||||
| 1, | ||||||||||||||||||||||
| @as(usize, @bitCast(this.data[16..24].*)), | ||||||||||||||||||||||
| .{}, | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| switch (result) { | ||||||||||||||||||||||
| .fail => |fail| { | ||||||||||||||||||||||
| if (Output.enable_ansi_colors_stderr) { | ||||||||||||||||||||||
| try fail.toData(path).writeFormat( | ||||||||||||||||||||||
| Output.errorWriter(), | ||||||||||||||||||||||
| logger.Kind.warn, | ||||||||||||||||||||||
| false, | ||||||||||||||||||||||
| true, | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| } else { | ||||||||||||||||||||||
| try fail.toData(path).writeFormat( | ||||||||||||||||||||||
| Output.errorWriter(), | ||||||||||||||||||||||
| logger.Kind.warn, | ||||||||||||||||||||||
| false, | ||||||||||||||||||||||
| false, | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return fail.err; | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| .success => |success| { | ||||||||||||||||||||||
| return success; | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /// ParsedSourceMap is the canonical form for sourcemaps, | ||||||||||||||||||||||
| /// | ||||||||||||||||||||||
| /// but `SavedMappings` and `SourceProviderMap` are much cheaper to construct. | ||||||||||||||||||||||
| /// In `fn get`, this value gets converted to ParsedSourceMap always | ||||||||||||||||||||||
| /// `InternalSourceMap` is the storage for runtime-transpiled modules. | ||||||||||||||||||||||
| /// `ParsedSourceMap` is materialized lazily from a `SourceProviderMap` / | ||||||||||||||||||||||
| /// `BakeSourceProvider` / `DevServerSourceProvider` for sources that ship | ||||||||||||||||||||||
| /// their own external `.map`. | ||||||||||||||||||||||
| pub const Value = bun.TaggedPointerUnion(.{ | ||||||||||||||||||||||
| ParsedSourceMap, | ||||||||||||||||||||||
| SavedMappings, | ||||||||||||||||||||||
| SourceProviderMap, | ||||||||||||||||||||||
| BakeSourceProvider, | ||||||||||||||||||||||
| DevServerSourceProvider, | ||||||||||||||||||||||
| InternalSourceMap, | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub const MissingSourceMapNoteInfo = struct { | ||||||||||||||||||||||
|
|
@@ -178,11 +129,10 @@ pub fn deinit(this: *SavedSourceMap) void { | |||||||||||||||||||||
| var value = Value.from(val.*); | ||||||||||||||||||||||
| if (value.get(ParsedSourceMap)) |source_map| { | ||||||||||||||||||||||
| source_map.deref(); | ||||||||||||||||||||||
| } else if (value.get(SavedMappings)) |saved_mappings| { | ||||||||||||||||||||||
| var saved = SavedMappings{ .data = @as([*]u8, @ptrCast(saved_mappings)) }; | ||||||||||||||||||||||
| saved.deinit(); | ||||||||||||||||||||||
| } else if (value.get(SourceProviderMap)) |provider| { | ||||||||||||||||||||||
| _ = provider; // do nothing, we did not hold a ref to ZigSourceProvider | ||||||||||||||||||||||
| } else if (value.get(InternalSourceMap)) |ism| { | ||||||||||||||||||||||
| (InternalSourceMap{ .data = @as([*]u8, @ptrCast(ism)) }).deinit(); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
@@ -192,24 +142,27 @@ pub fn deinit(this: *SavedSourceMap) void { | |||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub fn putMappings(this: *SavedSourceMap, source: *const logger.Source, mappings: MutableString) !void { | ||||||||||||||||||||||
| try this.putValue(source.path.text, Value.init(bun.cast(*SavedMappings, try bun.default_allocator.dupe(u8, mappings.list.items)))); | ||||||||||||||||||||||
| const blob = try bun.default_allocator.dupe(u8, mappings.list.items); | ||||||||||||||||||||||
| errdefer bun.default_allocator.free(blob); | ||||||||||||||||||||||
| try this.putValue(source.path.text, Value.init(bun.cast(*InternalSourceMap, blob.ptr))); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
Comment on lines
144
to
148
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Free the duplicated blob if The allocation succeeds before the hash-table insert, so an error from Suggested fix pub fn putMappings(this: *SavedSourceMap, source: *const logger.Source, mappings: MutableString) !void {
const blob = try bun.default_allocator.dupe(u8, mappings.list.items);
+ errdefer bun.default_allocator.free(blob);
try this.putValue(source.path.text, Value.init(bun.cast(*InternalSourceMap, blob.ptr)));
}As per coding guidelines, "In Zig code, be careful with allocators and use defer for cleanup". 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
claude[bot] marked this conversation as resolved.
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub fn putValue(this: *SavedSourceMap, path: []const u8, value: Value) !void { | ||||||||||||||||||||||
| this.lock(); | ||||||||||||||||||||||
| defer this.unlock(); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| this.find_cache.invalidateAll(); | ||||||||||||||||||||||
| this.last_ism = null; | ||||||||||||||||||||||
| const entry = try this.map.getOrPut(bun.hash(path)); | ||||||||||||||||||||||
| if (entry.found_existing) { | ||||||||||||||||||||||
| var old_value = Value.from(entry.value_ptr.*); | ||||||||||||||||||||||
| if (old_value.get(ParsedSourceMap)) |parsed_source_map| { | ||||||||||||||||||||||
| var source_map: *ParsedSourceMap = parsed_source_map; | ||||||||||||||||||||||
| source_map.deref(); | ||||||||||||||||||||||
| } else if (old_value.get(SavedMappings)) |saved_mappings| { | ||||||||||||||||||||||
| var saved = SavedMappings{ .data = @as([*]u8, @ptrCast(saved_mappings)) }; | ||||||||||||||||||||||
| saved.deinit(); | ||||||||||||||||||||||
| } else if (old_value.get(SourceProviderMap)) |provider| { | ||||||||||||||||||||||
| _ = provider; // do nothing, we did not hold a ref to ZigSourceProvider | ||||||||||||||||||||||
| } else if (old_value.get(InternalSourceMap)) |ism| { | ||||||||||||||||||||||
| (InternalSourceMap{ .data = @as([*]u8, @ptrCast(ism)) }).deinit(); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| entry.value_ptr.* = value.ptr(); | ||||||||||||||||||||||
|
|
@@ -233,25 +186,30 @@ fn getWithContent( | |||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| switch (Value.from(mapping.value_ptr.*).tag()) { | ||||||||||||||||||||||
| @field(Value.Tag, @typeName(ParsedSourceMap)) => { | ||||||||||||||||||||||
| @field(Value.Tag, @typeName(InternalSourceMap)) => { | ||||||||||||||||||||||
| // Runtime-transpiled module. Wrap the blob in a refcounted | ||||||||||||||||||||||
| // ParsedSourceMap shell (no VLQ decode, no Mapping.List) so callers | ||||||||||||||||||||||
| // can hold a ref while the table mutates. The shell takes ownership | ||||||||||||||||||||||
| // of the blob. | ||||||||||||||||||||||
| defer this.unlock(); | ||||||||||||||||||||||
| const map = Value.from(mapping.value_ptr.*).as(ParsedSourceMap); | ||||||||||||||||||||||
| map.ref(); | ||||||||||||||||||||||
| return .{ .map = map }; | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| @field(Value.Tag, @typeName(SavedMappings)) => { | ||||||||||||||||||||||
| defer this.unlock(); | ||||||||||||||||||||||
| var saved = SavedMappings{ .data = @as([*]u8, @ptrCast(Value.from(mapping.value_ptr.*).as(ParsedSourceMap))) }; | ||||||||||||||||||||||
| defer saved.deinit(); | ||||||||||||||||||||||
| const result = bun.new(ParsedSourceMap, saved.toMapping(bun.default_allocator, path) catch { | ||||||||||||||||||||||
| _ = this.map.remove(mapping.key_ptr.*); | ||||||||||||||||||||||
| return .{}; | ||||||||||||||||||||||
| const ism: InternalSourceMap = .{ | ||||||||||||||||||||||
| .data = @as([*]u8, @ptrCast(Value.from(mapping.value_ptr.*).as(InternalSourceMap))), | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
| const result = bun.new(ParsedSourceMap, .{ | ||||||||||||||||||||||
| .ref_count = .init(), | ||||||||||||||||||||||
| .input_line_count = ism.inputLineCount(), | ||||||||||||||||||||||
| .internal = ism, | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| mapping.value_ptr.* = Value.init(result).ptr(); | ||||||||||||||||||||||
| result.ref(); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return .{ .map = result }; | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| @field(Value.Tag, @typeName(ParsedSourceMap)) => { | ||||||||||||||||||||||
| defer this.unlock(); | ||||||||||||||||||||||
| const map = Value.from(mapping.value_ptr.*).as(ParsedSourceMap); | ||||||||||||||||||||||
| map.ref(); | ||||||||||||||||||||||
| return .{ .map = map }; | ||||||||||||||||||||||
| }, | ||||||||||||||||||||||
| @field(Value.Tag, @typeName(SourceProviderMap)) => { | ||||||||||||||||||||||
| const ptr: *SourceProviderMap = Value.from(mapping.value_ptr.*).as(SourceProviderMap); | ||||||||||||||||||||||
| this.unlock(); | ||||||||||||||||||||||
|
|
@@ -348,6 +306,12 @@ pub fn get(this: *SavedSourceMap, path: string) ?*ParsedSourceMap { | |||||||||||||||||||||
| return this.getWithContent(path, .mappings_only).map; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /// Mutex must already be held. Returns the raw table value for `hash` if any. | ||||||||||||||||||||||
| pub fn getValueLocked(this: *SavedSourceMap, hash: u64) ?Value { | ||||||||||||||||||||||
| const raw = this.map.get(hash) orelse return null; | ||||||||||||||||||||||
| return Value.from(raw); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub fn resolveMapping( | ||||||||||||||||||||||
| this: *SavedSourceMap, | ||||||||||||||||||||||
| path: []const u8, | ||||||||||||||||||||||
|
|
@@ -362,7 +326,7 @@ pub fn resolveMapping( | |||||||||||||||||||||
| const map = parse.map orelse return null; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const mapping = parse.mapping orelse | ||||||||||||||||||||||
| map.mappings.find(line, column) orelse | ||||||||||||||||||||||
| map.findMapping(line, column) orelse | ||||||||||||||||||||||
| return null; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return .{ | ||||||||||||||||||||||
|
|
@@ -375,7 +339,6 @@ pub fn resolveMapping( | |||||||||||||||||||||
| const string = []const u8; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const std = @import("std"); | ||||||||||||||||||||||
| const Allocator = std.mem.Allocator; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const bun = @import("bun"); | ||||||||||||||||||||||
| const Environment = bun.Environment; | ||||||||||||||||||||||
|
|
@@ -387,5 +350,6 @@ const logger = bun.logger; | |||||||||||||||||||||
| const SourceMap = bun.SourceMap; | ||||||||||||||||||||||
| const BakeSourceProvider = bun.SourceMap.BakeSourceProvider; | ||||||||||||||||||||||
| const DevServerSourceProvider = bun.SourceMap.DevServerSourceProvider; | ||||||||||||||||||||||
| const InternalSourceMap = SourceMap.InternalSourceMap; | ||||||||||||||||||||||
| const ParsedSourceMap = SourceMap.ParsedSourceMap; | ||||||||||||||||||||||
| const SourceProviderMap = SourceMap.SourceProviderMap; | ||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.