Files
bun.sh/src/install/PackageManager/WorkspacePackageJSONCache.zig
taylor.fish 437e15bae5 Replace catch bun.outOfMemory() with safer alternatives (#22141)
Replace `catch bun.outOfMemory()`, which can accidentally catch
non-OOM-related errors, with either `bun.handleOom` or a manual `catch
|err| switch (err)`.

(For internal tracking: fixes STAB-1070)

---------

Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-08-26 12:50:25 -07:00

164 lines
4.7 KiB
Zig

// maybe rename to `PackageJSONCache` if we cache more than workspaces
pub const MapEntry = struct {
root: Expr,
source: logger.Source,
indentation: JSPrinter.Options.Indentation = .{},
};
pub const Map = bun.StringHashMapUnmanaged(MapEntry);
pub const GetJSONOptions = struct {
init_reset_store: bool = true,
guess_indentation: bool = false,
};
pub const GetResult = union(enum) {
entry: *MapEntry,
read_err: anyerror,
parse_err: anyerror,
pub fn unwrap(this: GetResult) !*MapEntry {
return switch (this) {
.entry => |entry| entry,
inline else => |err| err,
};
}
};
map: Map = .{},
/// Given an absolute path to a workspace package.json, return the AST
/// and contents of the file. If the package.json is not present in the
/// cache, it will be read from disk and parsed, and stored in the cache.
pub fn getWithPath(
this: *@This(),
allocator: std.mem.Allocator,
log: *logger.Log,
abs_package_json_path: anytype,
comptime opts: GetJSONOptions,
) GetResult {
bun.assertWithLocation(std.fs.path.isAbsolute(abs_package_json_path), @src());
var buf: if (Environment.isWindows) bun.PathBuffer else void = undefined;
const path = if (comptime !Environment.isWindows)
abs_package_json_path
else brk: {
@memcpy(buf[0..abs_package_json_path.len], abs_package_json_path);
bun.path.dangerouslyConvertPathToPosixInPlace(u8, buf[0..abs_package_json_path.len]);
break :brk buf[0..abs_package_json_path.len];
};
const entry = bun.handleOom(this.map.getOrPut(allocator, path));
if (entry.found_existing) {
return .{ .entry = entry.value_ptr };
}
const key = bun.handleOom(allocator.dupeZ(u8, path));
entry.key_ptr.* = key;
const source = &(bun.sys.File.toSource(key, allocator, .{}).unwrap() catch |err| {
_ = this.map.remove(key);
allocator.free(key);
return .{ .read_err = err };
});
if (comptime opts.init_reset_store)
initializeStore();
const json = JSON.parsePackageJSONUTF8WithOpts(
source,
log,
allocator,
.{
.is_json = true,
.allow_comments = true,
.allow_trailing_commas = true,
.guess_indentation = opts.guess_indentation,
},
) catch |err| {
_ = this.map.remove(key);
allocator.free(source.contents);
allocator.free(key);
bun.handleErrorReturnTrace(err, @errorReturnTrace());
return .{ .parse_err = err };
};
entry.value_ptr.* = .{
.root = bun.handleOom(json.root.deepClone(bun.default_allocator)),
.source = source.*,
.indentation = json.indentation,
};
return .{ .entry = entry.value_ptr };
}
/// source path is used as the key, needs to be absolute
pub fn getWithSource(
this: *@This(),
allocator: std.mem.Allocator,
log: *logger.Log,
source: *const logger.Source,
comptime opts: GetJSONOptions,
) GetResult {
bun.assertWithLocation(std.fs.path.isAbsolute(source.path.text), @src());
var buf: if (Environment.isWindows) bun.PathBuffer else void = undefined;
const path = if (comptime !Environment.isWindows)
source.path.text
else brk: {
@memcpy(buf[0..source.path.text.len], source.path.text);
bun.path.dangerouslyConvertPathToPosixInPlace(u8, buf[0..source.path.text.len]);
break :brk buf[0..source.path.text.len];
};
const entry = bun.handleOom(this.map.getOrPut(allocator, path));
if (entry.found_existing) {
return .{ .entry = entry.value_ptr };
}
if (comptime opts.init_reset_store)
initializeStore();
const json_result = JSON.parsePackageJSONUTF8WithOpts(
source,
log,
allocator,
.{
.is_json = true,
.allow_comments = true,
.allow_trailing_commas = true,
.guess_indentation = opts.guess_indentation,
},
);
const json = json_result catch |err| {
_ = this.map.remove(path);
return .{ .parse_err = err };
};
entry.value_ptr.* = .{
.root = bun.handleOom(json.root.deepClone(allocator)),
.source = source.*,
.indentation = json.indentation,
};
entry.key_ptr.* = bun.handleOom(allocator.dupe(u8, path));
return .{ .entry = entry.value_ptr };
}
const std = @import("std");
const bun = @import("bun");
const Environment = bun.Environment;
const JSON = bun.json;
const JSPrinter = bun.js_printer;
const default_allocator = bun.default_allocator;
const logger = bun.logger;
const File = bun.sys.File;
const initializeStore = bun.install.initializeStore;
const js_ast = bun.ast;
const Expr = js_ast.Expr;