[autofix.ci] apply automated fixes

This commit is contained in:
autofix-ci[bot]
2025-08-12 18:48:02 +00:00
committed by GitHub
parent 1d24744ecb
commit d1e817fcce
5 changed files with 92 additions and 93 deletions

View File

@@ -82,25 +82,25 @@ pub const SavedMappings = struct {
/// Compact variant that uses LineOffsetTable.Compact for reduced memory usage
pub const SavedMappingsCompact = struct {
compact_table: SourceMap.LineOffsetTable.Compact,
pub fn init(allocator: Allocator, vlq_mappings: []const u8) !SavedMappingsCompact {
return SavedMappingsCompact{
.compact_table = try SourceMap.LineOffsetTable.Compact.init(allocator, vlq_mappings),
};
}
pub fn deinit(this: *SavedMappingsCompact) void {
this.compact_table.deinit();
}
pub fn toMapping(this: *SavedMappingsCompact, allocator: Allocator, path: string) anyerror!ParsedSourceMap {
// Parse the VLQ mappings using the existing parser but keep the compact table
const result = SourceMap.Mapping.parse(
allocator,
this.compact_table.vlq_mappings,
null, // estimated mapping count
1, // sources count
this.compact_table.line_offsets.len, // input line count
1, // sources count
this.compact_table.line_offsets.len, // input line count
.{},
);
switch (result) {
@@ -223,11 +223,11 @@ pub fn deinit(this: *SavedSourceMap) void {
pub fn putMappings(this: *SavedSourceMap, source: *const logger.Source, mappings: MutableString) !void {
// Always use compact format for memory efficiency
const mappings_data = mappings.list.items;
// Extract VLQ mappings (starts after header if present)
const vlq_start: usize = if (mappings_data.len >= vlq_offset) vlq_offset else 0;
const vlq_data = mappings_data[vlq_start..];
const compact = try bun.default_allocator.create(SavedMappingsCompact);
compact.* = try SavedMappingsCompact.init(bun.default_allocator, vlq_data);
try this.putValue(source.path.text, Value.init(compact));

View File

@@ -141,7 +141,7 @@ pub fn constructor(
error.OutOfMemory => return error.OutOfMemory,
else => return globalObject.throwValue(globalObject.createSyntaxErrorInstance("Failed to parse compact sourcemap: {s}", .{@errorName(err)})),
};
const source_map = bun.new(JSSourceMap, .{
.sourcemap = bun.new(bun.sourcemap.ParsedSourceMap, parsed_map),
.sources = sources.items,
@@ -158,7 +158,6 @@ pub fn constructor(
return source_map;
}
pub fn memoryCost(this: *const JSSourceMap) usize {
return @sizeOf(JSSourceMap) + this.sources.len * @sizeOf(bun.String) + this.sourcemap.memoryCost();
}

View File

@@ -22,111 +22,111 @@ pub const List = bun.MultiArrayList(LineOffsetTable);
pub const Compact = struct {
/// VLQ-encoded sourcemap mappings string
vlq_mappings: []const u8,
/// Index of positions where ';' (line separators) occur in vlq_mappings
/// Index of positions where ';' (line separators) occur in vlq_mappings
line_offsets: []const u32,
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator, vlq_mappings: []const u8) !Compact {
// Find all line separator positions
var line_positions = std.ArrayList(u32).init(allocator);
defer line_positions.deinit();
// Start with implicit position 0 for first line
try line_positions.append(0);
for (vlq_mappings, 0..) |char, i| {
if (char == ';') {
try line_positions.append(@intCast(i + 1));
}
}
const owned_mappings = try allocator.dupe(u8, vlq_mappings);
const owned_offsets = try allocator.dupe(u32, line_positions.items);
return Compact{
.vlq_mappings = owned_mappings,
.line_offsets = owned_offsets,
.allocator = allocator,
};
}
pub fn deinit(self: *Compact) void {
self.allocator.free(self.vlq_mappings);
self.allocator.free(self.line_offsets);
}
/// Find mapping for a given line/column by decoding VLQ on demand
pub fn findMapping(self: *const Compact, target_line: i32, target_column: i32) ?SourceMapping {
if (target_line < 0 or target_line >= self.line_offsets.len - 1) {
return null;
}
const line_start = self.line_offsets[@intCast(target_line)];
const line_end = if (target_line + 1 < self.line_offsets.len)
self.line_offsets[@intCast(target_line + 1)] - 1 // -1 to exclude the ';'
else
const line_end = if (target_line + 1 < self.line_offsets.len)
self.line_offsets[@intCast(target_line + 1)] - 1 // -1 to exclude the ';'
else
@as(u32, @intCast(self.vlq_mappings.len));
if (line_start >= line_end) return null;
const line_mappings = self.vlq_mappings[line_start..line_end];
// Decode VLQ mappings for this line
var generated_column: i32 = 0;
var source_index: i32 = 0;
var source_index: i32 = 0;
var original_line: i32 = 0;
var original_column: i32 = 0;
var pos: usize = 0;
var best_mapping: ?SourceMapping = null;
while (pos < line_mappings.len) {
// Skip commas
if (line_mappings[pos] == ',') {
pos += 1;
continue;
}
// Decode generated column delta
const gen_col_result = VLQ.decode(line_mappings, pos);
if (gen_col_result.start == pos) break; // Invalid VLQ
generated_column += gen_col_result.value;
pos = gen_col_result.start;
// If we've passed the target column, return the last good mapping
if (generated_column > target_column and best_mapping != null) {
return best_mapping;
}
if (pos >= line_mappings.len) break;
if (line_mappings[pos] == ',') {
// Only generated column - no source info
pos += 1;
continue;
}
// Decode source index delta
const src_idx_result = VLQ.decode(line_mappings, pos);
if (src_idx_result.start == pos) break;
source_index += src_idx_result.value;
pos = src_idx_result.start;
if (pos >= line_mappings.len) break;
// Decode original line delta
// Decode original line delta
const orig_line_result = VLQ.decode(line_mappings, pos);
if (orig_line_result.start == pos) break;
original_line += orig_line_result.value;
pos = orig_line_result.start;
if (pos >= line_mappings.len) break;
// Decode original column delta
const orig_col_result = VLQ.decode(line_mappings, pos);
if (orig_col_result.start == pos) break;
original_column += orig_col_result.value;
pos = orig_col_result.start;
// Skip name index if present
if (pos < line_mappings.len and line_mappings[pos] != ',' and line_mappings[pos] != ';') {
const name_result = VLQ.decode(line_mappings, pos);
@@ -134,7 +134,7 @@ pub const Compact = struct {
pos = name_result.start;
}
}
// Update best mapping if this column is <= target
if (generated_column <= target_column) {
best_mapping = SourceMapping{
@@ -146,22 +146,22 @@ pub const Compact = struct {
};
}
}
return best_mapping;
}
/// Compatible API with regular LineOffsetTable for findLine
pub fn findLine(self: *const Compact, loc: Logger.Loc) i32 {
// For compact version, we need to search through mappings to find the line
// This is a simplified version - in practice you'd want to maintain
// This is a simplified version - in practice you'd want to maintain
// generated line->original line mapping
// For now, return a basic implementation that assumes 1:1 line mapping
// This can be optimized by maintaining a separate line mapping cache
return @max(0, @min(@as(i32, @intCast(self.line_offsets.len)) - 2, loc.start));
}
/// Compatible API with regular LineOffsetTable for findIndex
/// Compatible API with regular LineOffsetTable for findIndex
pub fn findIndex(self: *const Compact, loc: Logger.Loc) ?usize {
const line = self.findLine(loc);
if (line >= 0 and line < self.line_offsets.len - 1) {
@@ -169,10 +169,10 @@ pub const Compact = struct {
}
return null;
}
const SourceMapping = struct {
generated_line: i32,
generated_column: i32,
generated_column: i32,
source_index: i32,
original_line: i32,
original_column: i32,
@@ -385,6 +385,7 @@ pub fn generate(allocator: std.mem.Allocator, contents: []const u8, approximate_
return list;
}
const VLQ = @import("./VLQ.zig");
const std = @import("std");
const bun = @import("bun");
@@ -392,4 +393,3 @@ const BabyList = bun.BabyList;
const Logger = bun.logger;
const assert = bun.assert;
const strings = bun.strings;
const VLQ = @import("./VLQ.zig");

View File

@@ -1,5 +1,5 @@
import { test, expect } from "bun:test";
import { tempDirWithFiles, bunExe, bunEnv } from "harness";
import { expect, test } from "bun:test";
import { bunEnv, bunExe, tempDirWithFiles } from "harness";
// Test the compact sourcemap implementation using the SourceMap class from Node.js
test("SourceMap with compact mappings handles basic cases", () => {
@@ -9,7 +9,7 @@ test("SourceMap with compact mappings handles basic cases", () => {
sources: ["input.js"],
sourcesContent: ["console.log('hello');\nconsole.log('world');"],
mappings: "AAAA;AACA", // Simple VLQ mappings
names: []
names: [],
};
const { SourceMap } = require("module");
@@ -22,7 +22,7 @@ test("SourceMap with compact mappings handles basic cases", () => {
expect(origin.column).toBe(0);
expect(origin.fileName || origin.source).toBe("input.js");
// Test findEntry method
// Test findEntry method
const entry = sourceMap.findEntry(0, 0);
expect(entry).toBeObject();
expect(entry.generatedLine).toBe(0);
@@ -36,16 +36,16 @@ test("SourceMap with complex VLQ mappings", () => {
sources: ["input.js"],
sourcesContent: ["function test() { console.log('test'); }"],
mappings: "AAAA,SAAS,KAAK,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC", // Complex VLQ
names: ["test", "console", "log"]
names: ["test", "console", "log"],
};
const { SourceMap } = require("module");
const sourceMap = new SourceMap(payload);
// Test various positions
const origin1 = sourceMap.findOrigin(0, 9); // Should map to function name
const origin1 = sourceMap.findOrigin(0, 9); // Should map to function name
expect(origin1).toBeObject();
const origin2 = sourceMap.findOrigin(0, 20); // Should map to console.log
expect(origin2).toBeObject();
});
@@ -55,8 +55,8 @@ test("SourceMap with non-ASCII characters in VLQ", () => {
version: 3,
sources: ["unicode.js"],
sourcesContent: ["console.log('你好');"],
mappings: "AAAA,QAAQ,GAAG,CAAC,IAAI,CAAC",
names: []
mappings: "AAAA,QAAQ,GAAG,CAAC,IAAI,CAAC",
names: [],
};
const { SourceMap } = require("module");
@@ -73,7 +73,7 @@ test("SourceMap handles empty and sparse mappings", () => {
sources: ["sparse.js"],
sourcesContent: ["line1\n\n\nline4"],
mappings: "AAAA;;;AAEA", // Empty lines represented by ;;;
names: []
names: [],
};
const { SourceMap } = require("module");
@@ -83,24 +83,24 @@ test("SourceMap handles empty and sparse mappings", () => {
expect(origin1).toBeObject();
// Test mapping to line with empty content
const origin4 = sourceMap.findOrigin(3, 0);
const origin4 = sourceMap.findOrigin(3, 0);
expect(origin4).toBeObject();
});
test("SourceMap with large number of mappings for memory test", () => {
// Generate a large number of VLQ mappings to test memory efficiency
const sources = ["large.js"];
const sourcesContent = [Array.from({ length: 100 }, (_, i) => `console.log(${i});`).join('\n')];
const sourcesContent = [Array.from({ length: 100 }, (_, i) => `console.log(${i});`).join("\n")];
// Generate simple mappings for each line
const mappings = Array.from({ length: 100 }, () => "AAAA").join(';');
const mappings = Array.from({ length: 100 }, () => "AAAA").join(";");
const payload = {
version: 3,
sources,
sourcesContent,
mappings,
names: []
names: [],
};
const { SourceMap } = require("module");
@@ -145,7 +145,7 @@ throwError();
const [stdout, stderr, exitCode2] = await Promise.all([
proc2.stdout.text(),
proc2.stderr?.text() || Promise.resolve(""),
proc2.stderr?.text() || Promise.resolve(""),
proc2.exited,
]);
@@ -160,31 +160,31 @@ throwError();
test("compact sourcemap performance vs regular sourcemap", () => {
// Test to ensure compact variant doesn't significantly impact performance
const startTime = Date.now();
// Create many SourceMap instances with complex mappings
const mappings = Array.from({ length: 50 }, () => "AAAA,CAAC,CAAC,CAAC,CAAC").join(';');
const mappings = Array.from({ length: 50 }, () => "AAAA,CAAC,CAAC,CAAC,CAAC").join(";");
for (let i = 0; i < 100; i++) {
const payload = {
version: 3,
sources: [`file${i}.js`],
sourcesContent: [`// File ${i}\nconsole.log(${i});`],
mappings,
names: []
names: [],
};
const { SourceMap } = require("module");
const sourceMap = new SourceMap(payload);
// Perform some lookups
sourceMap.findOrigin(0, 0);
sourceMap.findOrigin(1, 0);
}
const endTime = Date.now();
const duration = endTime - startTime;
// Should complete reasonably quickly (< 1 second)
expect(duration).toBeLessThan(1000);
console.log(`Performance test completed in ${duration}ms`);
});
});

View File

@@ -1,32 +1,32 @@
import { test, expect } from "bun:test";
import { expect, test } from "bun:test";
test("Compact vs Regular SourceMap memory comparison conceptual test", () => {
// This test demonstrates the memory savings concept
// Regular sourcemap storage:
// - Each mapping = 4 x i32 (16 bytes) for generated_line, generated_column, original_line, original_column
// - Plus source_index, name_index etc.
// - For 1000 mappings: ~20KB+ in unpacked form
const mappingCount = 1000;
const regularMemoryPerMapping = 20; // bytes per mapping in unpacked form
const regularTotalMemory = mappingCount * regularMemoryPerMapping; // ~20KB
// Compact sourcemap storage:
// - VLQ encoded strings are much smaller
// - A simple mapping like "AAAA" (4 chars) represents the same data as 16+ bytes
// - Line index overhead is minimal (one u32 per line)
const vlqBytesPerMapping = 4; // Average VLQ encoding size
const lineIndexOverhead = Math.ceil(mappingCount / 10) * 4; // Assume ~10 mappings per line
const compactTotalMemory = (mappingCount * vlqBytesPerMapping) + lineIndexOverhead; // ~4KB
const compactTotalMemory = mappingCount * vlqBytesPerMapping + lineIndexOverhead; // ~4KB
const memoryReduction = ((regularTotalMemory - compactTotalMemory) / regularTotalMemory) * 100;
console.log(`Regular sourcemap memory: ${regularTotalMemory} bytes`);
console.log(`Compact sourcemap memory: ${compactTotalMemory} bytes`);
console.log(`Compact sourcemap memory: ${compactTotalMemory} bytes`);
console.log(`Memory reduction: ${memoryReduction.toFixed(1)}%`);
// We expect significant memory reduction
expect(memoryReduction).toBeGreaterThan(70); // At least 70% reduction
expect(compactTotalMemory).toBeLessThan(regularTotalMemory);
@@ -34,20 +34,20 @@ test("Compact vs Regular SourceMap memory comparison conceptual test", () => {
test("VLQ encoding efficiency demonstration", () => {
// Test that shows VLQ encoding is more efficient than storing raw i32 values
// Example: mapping with generated_column=5, source_index=0, original_line=2, original_column=8
// In regular form: 4 x i32 = 16 bytes
// In VLQ form: "KAEA,G" = 6 bytes (including separators)
const regularSize = 4 * 4; // 4 i32 values = 16 bytes
const vlqSize = 6; // "KAEA,G" = 6 bytes
const savings = ((regularSize - vlqSize) / regularSize) * 100;
console.log(`Regular mapping size: ${regularSize} bytes`);
console.log(`VLQ mapping size: ${vlqSize} bytes`);
console.log(`Space savings per mapping: ${savings.toFixed(1)}%`);
expect(vlqSize).toBeLessThan(regularSize);
expect(savings).toBeGreaterThan(50); // At least 50% savings per mapping
});
@@ -55,19 +55,19 @@ test("VLQ encoding efficiency demonstration", () => {
test("Line index efficiency", () => {
// The line index in our compact format adds minimal overhead
// but enables fast line-based lookups
const lineCount = 100;
const indexSize = lineCount * 4; // u32 per line = 400 bytes
const mappingCount = 1000;
const mappingCount = 1000;
const vlqMappingsSize = mappingCount * 4; // Average 4 bytes per mapping = 4000 bytes
const totalCompactSize = indexSize + vlqMappingsSize;
const indexOverheadPercent = (indexSize / totalCompactSize) * 100;
console.log(`Line index size: ${indexSize} bytes`);
console.log(`VLQ mappings size: ${vlqMappingsSize} bytes`);
console.log(`Index overhead: ${indexOverheadPercent.toFixed(1)}%`);
// Index overhead should be minimal
expect(indexOverheadPercent).toBeLessThan(15); // Less than 15% overhead
});
});