use bun_collections::StringHashMap;
use bun_core::Error;
use crate::bun_json::Expr;
use bun_ast::Indentation;
use bun_ast::{Log, Source};
#[cfg(windows)]
use bun_paths::PathBuffer;
use bun_paths::is_absolute;
use crate::bun_json as json;
use crate::initialize_store;
pub struct MapEntry {
pub root: Expr,
pub source: Source,
pub indentation: Indentation,
_path_storage: bun_core::ZBox,
pub json_arena: bun_alloc::Arena,
pub stale_contents: Vec<std::borrow::Cow<'static, [u8]>>,
}
impl Default for MapEntry {
fn default() -> Self {
Self {
root: Expr::default(),
source: Source::default(),
indentation: Indentation::default(),
_path_storage: bun_core::ZBox::default(),
json_arena: bun_alloc::Arena::new(),
stale_contents: Vec::new(),
}
}
}
impl MapEntry {
pub fn reparse_root(&mut self, log: &mut Log) -> Result<(), Error> {
let json_bump = bun_alloc::Arena::new();
let parsed = parse_package_json(&self.source, log, &json_bump, false)?;
self.root = bun_core::handle_oom(parsed.root.deep_clone(&json_bump));
self.json_arena = json_bump;
Ok(())
}
}
pub type Map = StringHashMap<MapEntry>;
fn parse_package_json(
source: &Source,
log: &mut Log,
bump: &bun_alloc::Arena,
guess_indentation: bool,
) -> Result<json::JsonResult, bun_core::Error> {
if guess_indentation {
json::parse_package_json_utf8_with_opts::<
true, true, true, false, false, false, false, true, >(source, log, bump)
} else {
json::parse_package_json_utf8_with_opts::<
true, true, true, false, false, false, false, false, >(source, log, bump)
}
}
#[derive(Clone, Copy)]
pub struct GetJSONOptions {
pub init_reset_store: bool,
pub guess_indentation: bool,
}
impl Default for GetJSONOptions {
fn default() -> Self {
Self {
init_reset_store: true,
guess_indentation: false,
}
}
}
pub enum GetResult<'a> {
Entry(&'a mut MapEntry),
ReadErr(Error),
ParseErr(Error),
}
impl<'a> GetResult<'a> {
pub fn unwrap(self) -> Result<&'a mut MapEntry, Error> {
match self {
GetResult::Entry(entry) => Ok(entry),
GetResult::ReadErr(err) => Err(err),
GetResult::ParseErr(err) => Err(err),
}
}
}
#[derive(Default)]
pub struct WorkspacePackageJSONCache {
pub map: Map,
}
impl WorkspacePackageJSONCache {
pub fn get_with_path(
&mut self,
log: &mut Log,
abs_package_json_path: &[u8],
opts: GetJSONOptions,
) -> GetResult<'_> {
debug_assert!(is_absolute(abs_package_json_path));
#[cfg(windows)]
let mut buf = PathBuffer::uninit();
#[cfg(not(windows))]
let path: &[u8] = abs_package_json_path;
#[cfg(windows)]
let path: &[u8] = {
buf[..abs_package_json_path.len()].copy_from_slice(abs_package_json_path);
bun_paths::dangerously_convert_path_to_posix_in_place::<u8>(
&mut buf[..abs_package_json_path.len()],
);
&buf[..abs_package_json_path.len()]
};
if self.map.contains_key(path) {
return GetResult::Entry(self.map.get_mut(path).unwrap());
}
let key = bun_core::ZBox::from_bytes(path);
let source = match bun_ast::to_source(&key, Default::default()) {
Ok(s) => s,
Err(err) => {
return GetResult::ReadErr(err.into());
}
};
if opts.init_reset_store {
initialize_store();
}
let json_bump = bun_alloc::Arena::new();
let parsed = match parse_package_json(&source, log, &json_bump, opts.guess_indentation) {
Ok(p) => p,
Err(err) => {
return GetResult::ParseErr(err);
}
};
let value = MapEntry {
root: bun_core::handle_oom(parsed.root.deep_clone(&json_bump)),
source,
indentation: parsed.indentation,
_path_storage: key,
json_arena: json_bump,
stale_contents: Vec::new(),
};
let entry = bun_core::handle_oom(self.map.get_or_put(path));
debug_assert!(!entry.found_existing);
*entry.value_ptr = value;
GetResult::Entry(entry.value_ptr)
}
pub fn get_with_source(
&mut self,
log: &mut Log,
source: &Source,
opts: GetJSONOptions,
) -> GetResult<'_> {
debug_assert!(is_absolute(source.path.text()));
#[cfg(windows)]
let mut buf = PathBuffer::uninit();
#[cfg(not(windows))]
let path: &[u8] = source.path.text();
#[cfg(windows)]
let path: &[u8] = {
let text = source.path.text();
buf[..text.len()].copy_from_slice(text);
bun_paths::dangerously_convert_path_to_posix_in_place::<u8>(&mut buf[..text.len()]);
&buf[..text.len()]
};
if self.map.contains_key(path) {
return GetResult::Entry(self.map.get_mut(path).unwrap());
}
if opts.init_reset_store {
initialize_store();
}
let json_bump = bun_alloc::Arena::new();
let parsed = match parse_package_json(source, log, &json_bump, opts.guess_indentation) {
Ok(p) => p,
Err(err) => {
return GetResult::ParseErr(err);
}
};
let value = MapEntry {
root: bun_core::handle_oom(parsed.root.deep_clone(&json_bump)),
source: source.clone(),
indentation: parsed.indentation,
_path_storage: bun_core::ZBox::default(),
json_arena: json_bump,
stale_contents: Vec::new(),
};
let entry = bun_core::handle_oom(self.map.get_or_put(path));
debug_assert!(!entry.found_existing);
*entry.value_ptr = value;
GetResult::Entry(entry.value_ptr)
}
}