1use std::{
5 fmt,
6 path::{Path, PathBuf},
7};
8
9use simd_json::{BorrowedValue, prelude::*};
10
11use crate::{ResolveError, path::PathUtil};
12
13type BorrowedObject<'a> = simd_json::value::borrowed::Object<'a>;
15
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub enum PackageType {
18 CommonJs,
19 Module,
20}
21
22impl PackageType {
23 fn from_str(s: &str) -> Option<Self> {
24 match s {
25 "commonjs" => Some(Self::CommonJs),
26 "module" => Some(Self::Module),
27 _ => None,
28 }
29 }
30}
31
32impl fmt::Display for PackageType {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 match self {
35 Self::CommonJs => f.write_str("commonjs"),
36 Self::Module => f.write_str("module"),
37 }
38 }
39}
40
41#[derive(Clone, Copy, Debug, Eq, PartialEq)]
42pub enum ImportsExportsKind {
43 String,
44 Array,
45 Map,
46 Invalid,
47}
48
49#[derive(Clone, Debug, Eq, PartialEq)]
50pub enum SideEffects<'a> {
51 Bool(bool),
52 String(&'a str),
53 Array(Vec<&'a str>),
54}
55
56self_cell::self_cell! {
57 struct PackageJsonCell {
58 owner: Vec<u8>,
59
60 #[covariant]
61 dependent: BorrowedValue,
62 }
63}
64
65pub struct PackageJson {
70 pub path: PathBuf,
72
73 pub realpath: PathBuf,
75
76 cell: PackageJsonCell,
77}
78
79impl fmt::Debug for PackageJson {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f.debug_struct("PackageJson")
82 .field("path", &self.path)
83 .field("realpath", &self.realpath)
84 .field("name", &self.name())
85 .field("type", &self.r#type())
86 .finish_non_exhaustive()
87 }
88}
89
90impl PackageJson {
91 #[must_use]
98 pub fn path(&self) -> &Path {
99 &self.path
100 }
101
102 #[must_use]
109 pub fn realpath(&self) -> &Path {
110 &self.realpath
111 }
112
113 #[must_use]
119 pub fn directory(&self) -> &Path {
120 debug_assert!(self.realpath.file_name().is_some_and(|x| x == "package.json"));
121 self.realpath.parent().unwrap()
122 }
123
124 #[must_use]
131 pub fn name(&self) -> Option<&str> {
132 self.cell
133 .borrow_dependent()
134 .as_object()
135 .and_then(|obj| obj.get("name"))
136 .and_then(|v| v.as_str())
137 }
138
139 #[must_use]
143 pub fn version(&self) -> Option<&str> {
144 self.cell
145 .borrow_dependent()
146 .as_object()
147 .and_then(|obj| obj.get("version"))
148 .and_then(|v| v.as_str())
149 }
150
151 #[must_use]
155 pub fn r#type(&self) -> Option<PackageType> {
156 self.cell
157 .borrow_dependent()
158 .as_object()
159 .and_then(|obj| obj.get("type"))
160 .and_then(|v| v.as_str())
161 .and_then(PackageType::from_str)
162 }
163
164 #[must_use]
168 pub fn side_effects(&self) -> Option<SideEffects<'_>> {
169 self.cell.borrow_dependent().as_object().and_then(|obj| obj.get("sideEffects")).and_then(
170 |value| match value {
171 BorrowedValue::Static(simd_json::StaticNode::Bool(b)) => {
172 Some(SideEffects::Bool(*b))
173 }
174 BorrowedValue::String(s) => Some(SideEffects::String(s.as_ref())),
175 BorrowedValue::Array(arr) => {
176 let strings: Vec<&str> = arr.iter().filter_map(|v| v.as_str()).collect();
177 Some(SideEffects::Array(strings))
178 }
179 _ => None,
180 },
181 )
182 }
183
184 #[must_use]
188 pub fn exports(&self) -> Option<ImportsExportsEntry<'_>> {
189 self.cell
190 .borrow_dependent()
191 .as_object()
192 .and_then(|obj| obj.get("exports"))
193 .map(ImportsExportsEntry)
194 }
195
196 pub(crate) fn main_fields<'a>(
206 &'a self,
207 main_fields: &'a [String],
208 ) -> impl Iterator<Item = &'a str> + 'a {
209 let json_value = self.cell.borrow_dependent();
210 let json_object = json_value.as_object();
211
212 main_fields
213 .iter()
214 .filter_map(move |main_field| json_object.and_then(|obj| obj.get(main_field.as_str())))
215 .filter_map(|v| v.as_str())
216 }
217
218 pub(crate) fn exports_fields<'a>(
224 &'a self,
225 exports_fields: &'a [Vec<String>],
226 ) -> impl Iterator<Item = ImportsExportsEntry<'a>> + 'a {
227 let json_value = self.cell.borrow_dependent();
228
229 exports_fields
230 .iter()
231 .filter_map(move |object_path| {
232 json_value
233 .as_object()
234 .and_then(|json_object| Self::get_value_by_path(json_object, object_path))
235 })
236 .map(ImportsExportsEntry)
237 }
238
239 pub(crate) fn imports_fields<'a>(
245 &'a self,
246 imports_fields: &'a [Vec<String>],
247 ) -> impl Iterator<Item = ImportsExportsMap<'a>> + 'a {
248 let json_value = self.cell.borrow_dependent();
249
250 imports_fields
251 .iter()
252 .filter_map(move |object_path| {
253 json_value
254 .as_object()
255 .and_then(|json_object| Self::get_value_by_path(json_object, object_path))
256 .and_then(|v| v.as_object())
257 })
258 .map(ImportsExportsMap)
259 }
260
261 pub(crate) fn resolve_browser_field<'a>(
266 &'a self,
267 path: &Path,
268 request: Option<&str>,
269 alias_fields: &'a [Vec<String>],
270 ) -> Result<Option<&'a str>, ResolveError> {
271 for object in self.browser_fields(alias_fields) {
272 if let Some(request) = request {
273 if let Some(value) = object.get(request) {
275 return Self::alias_value(path, value);
276 }
277 } else {
278 let dir = self.path.parent().unwrap();
279 for (key, value) in object {
280 let joined = dir.normalize_with(key.as_ref());
281 if joined == path {
282 return Self::alias_value(path, value);
283 }
284 }
285 }
286 }
287 Ok(None)
288 }
289
290 pub fn parse(path: PathBuf, realpath: PathBuf, json: String) -> Result<Self, simd_json::Error> {
295 let mut json_bytes = json.into_bytes();
297 if json_bytes.starts_with(b"\xEF\xBB\xBF") {
298 json_bytes[0] = b' ';
299 json_bytes[1] = b' ';
300 json_bytes[2] = b' ';
301 }
302
303 let cell = PackageJsonCell::try_new(json_bytes.clone(), |bytes| {
305 let slice =
309 unsafe { std::slice::from_raw_parts_mut(bytes.as_ptr().cast_mut(), bytes.len()) };
310 simd_json::to_borrowed_value(slice)
311 })?;
312
313 Ok(Self { path, realpath, cell })
314 }
315
316 fn get_value_by_path<'a>(
317 fields: &'a BorrowedObject<'a>,
318 path: &[String],
319 ) -> Option<&'a BorrowedValue<'a>> {
320 if path.is_empty() {
321 return None;
322 }
323 let mut value = fields.get(path[0].as_str())?;
324
325 for key in path.iter().skip(1) {
326 if let Some(obj) = value.as_object() {
327 value = obj.get(key.as_str())?;
328 } else {
329 return None;
330 }
331 }
332 Some(value)
333 }
334
335 pub(crate) fn browser_fields<'a>(
340 &'a self,
341 alias_fields: &'a [Vec<String>],
342 ) -> impl Iterator<Item = &'a BorrowedObject<'a>> + 'a {
343 let json_value = self.cell.borrow_dependent();
344
345 alias_fields.iter().filter_map(move |object_path| {
346 json_value
347 .as_object()
348 .and_then(|json_object| Self::get_value_by_path(json_object, object_path))
349 .and_then(|value| value.as_object())
352 })
353 }
354
355 pub(crate) fn alias_value<'a>(
356 key: &Path,
357 value: &'a BorrowedValue<'a>,
358 ) -> Result<Option<&'a str>, ResolveError> {
359 match value {
360 BorrowedValue::String(s) => Ok(Some(s.as_ref())),
361 BorrowedValue::Static(simd_json::StaticNode::Bool(false)) => {
362 Err(ResolveError::Ignored(key.to_path_buf()))
363 }
364 _ => Ok(None),
365 }
366 }
367}
368
369#[derive(Clone)]
370pub struct ImportsExportsEntry<'a>(pub(crate) &'a BorrowedValue<'a>);
371
372impl<'a> ImportsExportsEntry<'a> {
373 #[must_use]
374 pub fn kind(&self) -> ImportsExportsKind {
375 match self.0 {
376 BorrowedValue::String(_) => ImportsExportsKind::String,
377 BorrowedValue::Array(_) => ImportsExportsKind::Array,
378 BorrowedValue::Object(_) => ImportsExportsKind::Map,
379 BorrowedValue::Static(_) => ImportsExportsKind::Invalid,
380 }
381 }
382
383 #[must_use]
384 pub fn as_string(&self) -> Option<&'a str> {
385 match self.0 {
386 BorrowedValue::String(s) => Some(s.as_ref()),
387 _ => None,
388 }
389 }
390
391 #[must_use]
392 pub fn as_array(&self) -> Option<ImportsExportsArray<'a>> {
393 match self.0 {
394 BorrowedValue::Array(arr) => Some(ImportsExportsArray(arr)),
395 _ => None,
396 }
397 }
398
399 #[must_use]
400 pub fn as_map(&self) -> Option<ImportsExportsMap<'a>> {
401 match self.0 {
402 BorrowedValue::Object(obj) => Some(ImportsExportsMap(obj)),
403 _ => None,
404 }
405 }
406}
407
408#[derive(Clone)]
409pub struct ImportsExportsArray<'a>(&'a [BorrowedValue<'a>]);
410
411impl<'a> ImportsExportsArray<'a> {
412 #[must_use]
413 pub fn is_empty(&self) -> bool {
414 self.len() == 0
415 }
416
417 #[must_use]
418 pub fn len(&self) -> usize {
419 self.0.len()
420 }
421
422 pub fn iter(&self) -> impl Iterator<Item = ImportsExportsEntry<'a>> {
423 ImportsExportsArrayIter { slice: self.0, index: 0 }
424 }
425}
426
427struct ImportsExportsArrayIter<'a> {
428 slice: &'a [BorrowedValue<'a>],
429 index: usize,
430}
431
432impl<'a> Iterator for ImportsExportsArrayIter<'a> {
433 type Item = ImportsExportsEntry<'a>;
434
435 fn next(&mut self) -> Option<Self::Item> {
436 self.slice.get(self.index).map(|value| {
437 self.index += 1;
438 ImportsExportsEntry(value)
439 })
440 }
441}
442
443#[derive(Clone)]
444pub struct ImportsExportsMap<'a>(pub(crate) &'a BorrowedObject<'a>);
445
446impl<'a> ImportsExportsMap<'a> {
447 pub fn get(&self, key: &str) -> Option<ImportsExportsEntry<'a>> {
448 self.0.get(key).map(ImportsExportsEntry)
449 }
450
451 pub fn keys(&self) -> impl Iterator<Item = &'a str> {
452 self.0.keys().map(std::convert::AsRef::as_ref)
453 }
454
455 pub fn iter(&self) -> impl Iterator<Item = (&'a str, ImportsExportsEntry<'a>)> {
456 self.0.iter().map(|(k, v)| (k.as_ref(), ImportsExportsEntry(v)))
457 }
458}