use std::path::{Path, PathBuf};
use serde_json::Value as JSONValue;
use crate::{
ImportsExportsKind, ImportsExportsMap, PackageJson, ResolveError,
package_json::{ImportsExportsArray, ImportsExportsEntry, PackageType},
path::PathUtil,
};
pub type JSONMap = serde_json::Map<String, JSONValue>;
#[cfg(feature = "fs_cache")]
#[derive(Debug, Default)]
pub struct PackageJsonSerde {
pub path: PathBuf,
pub realpath: PathBuf,
pub name: Option<String>,
pub r#type: Option<PackageType>,
pub side_effects: Option<JSONValue>,
raw_json: std::sync::Arc<JSONValue>,
}
#[allow(refining_impl_trait)]
impl PackageJson for PackageJsonSerde {
fn path(&self) -> &Path {
&self.path
}
fn realpath(&self) -> &Path {
&self.realpath
}
fn directory(&self) -> &Path {
debug_assert!(self.realpath.file_name().is_some_and(|x| x == "package.json"));
self.realpath.parent().unwrap()
}
fn name(&self) -> Option<&str> {
self.name.as_deref()
}
fn r#type(&self) -> Option<PackageType> {
self.r#type
}
fn main_fields<'a>(&'a self, main_fields: &'a [String]) -> impl Iterator<Item = &'a str> + 'a {
main_fields
.iter()
.filter_map(|main_field| self.raw_json.get(main_field))
.filter_map(JSONValue::as_str)
}
fn exports_fields<'a>(
&'a self,
exports_fields: &'a [Vec<String>],
) -> impl Iterator<Item = ImportsExportsSerdeEntry<'a>> + 'a {
exports_fields
.iter()
.filter_map(|object_path| {
self.raw_json
.as_object()
.and_then(|json_object| Self::get_value_by_path(json_object, object_path))
})
.map(ImportsExportsSerdeEntry)
}
fn imports_fields<'a>(
&'a self,
imports_fields: &'a [Vec<String>],
) -> impl Iterator<Item = ImportsExportsSerdeMap<'a>> + 'a {
imports_fields
.iter()
.filter_map(|object_path| {
self.raw_json
.as_object()
.and_then(|json_object| Self::get_value_by_path(json_object, object_path))
.and_then(JSONValue::as_object)
})
.map(ImportsExportsSerdeMap)
}
fn resolve_browser_field<'a>(
&'a self,
path: &Path,
request: Option<&str>,
alias_fields: &'a [Vec<String>],
) -> Result<Option<&'a str>, ResolveError> {
for object in self.browser_fields(alias_fields) {
if let Some(request) = request {
if let Some(value) = object.get(request) {
return Self::alias_value(path, value);
}
} else {
let dir = self.path.parent().unwrap();
for (key, value) in object {
let joined = dir.normalize_with(key);
if joined == path {
return Self::alias_value(path, value);
}
}
}
}
Ok(None)
}
}
impl PackageJsonSerde {
pub(crate) fn parse(
path: PathBuf,
realpath: PathBuf,
json: &str,
) -> Result<Self, serde_json::Error> {
let mut raw_json: JSONValue = serde_json::from_str(json)?;
let mut package_json = Self::default();
if let Some(json_object) = raw_json.as_object_mut() {
#[cfg(feature = "package_json_raw_json_api")]
{
json_object.remove("description");
json_object.remove("keywords");
json_object.remove("scripts");
json_object.remove("dependencies");
json_object.remove("devDependencies");
json_object.remove("peerDependencies");
json_object.remove("optionalDependencies");
}
package_json.name =
json_object.get("name").and_then(|field| field.as_str()).map(ToString::to_string);
package_json.r#type =
json_object.get("type").and_then(|ty| serde_json::from_value(ty.clone()).ok());
package_json.side_effects = json_object.get("sideEffects").cloned();
}
package_json.path = path;
package_json.realpath = realpath;
package_json.raw_json = std::sync::Arc::new(raw_json);
Ok(package_json)
}
fn get_value_by_path<'a>(
fields: &'a serde_json::Map<String, JSONValue>,
path: &[String],
) -> Option<&'a JSONValue> {
if path.is_empty() {
return None;
}
let mut value = fields.get(&path[0])?;
for key in path.iter().skip(1) {
if let Some(inner_value) = value.as_object().and_then(|o| o.get(key)) {
value = inner_value;
} else {
return None;
}
}
Some(value)
}
#[cfg(feature = "package_json_raw_json_api")]
#[must_use]
pub const fn raw_json(&self) -> &std::sync::Arc<JSONValue> {
&self.raw_json
}
fn browser_fields<'a>(
&'a self,
alias_fields: &'a [Vec<String>],
) -> impl Iterator<Item = &'a JSONMap> + 'a {
alias_fields.iter().filter_map(|object_path| {
self.raw_json
.as_object()
.and_then(|json_object| Self::get_value_by_path(json_object, object_path))
.and_then(|value| value.as_object())
})
}
fn alias_value<'a>(key: &Path, value: &'a JSONValue) -> Result<Option<&'a str>, ResolveError> {
match value {
JSONValue::String(value) => Ok(Some(value.as_str())),
JSONValue::Bool(b) if !b => Err(ResolveError::Ignored(key.to_path_buf())),
_ => Ok(None),
}
}
}
#[derive(Clone)]
pub struct ImportsExportsSerdeEntry<'a>(pub(crate) &'a JSONValue);
impl<'a> ImportsExportsEntry<'a> for ImportsExportsSerdeEntry<'a> {
type Array = ImportsExportsSerdeArray<'a>;
type Map = ImportsExportsSerdeMap<'a>;
fn kind(&self) -> ImportsExportsKind {
match &self.0 {
JSONValue::String(_) => ImportsExportsKind::String,
JSONValue::Array(_) => ImportsExportsKind::Array,
JSONValue::Object(_) => ImportsExportsKind::Map,
_ => ImportsExportsKind::Invalid,
}
}
fn as_string(&self) -> Option<&'a str> {
match &self.0 {
JSONValue::String(string) => Some(string),
_ => None,
}
}
fn as_array(&self) -> Option<ImportsExportsSerdeArray<'a>> {
match &self.0 {
JSONValue::Array(vec) => Some(ImportsExportsSerdeArray(vec)),
_ => None,
}
}
fn as_map(&self) -> Option<ImportsExportsSerdeMap<'a>> {
match &self.0 {
JSONValue::Object(map) => Some(ImportsExportsSerdeMap(map)),
_ => None,
}
}
}
#[derive(Clone)]
pub struct ImportsExportsSerdeArray<'a>(&'a Vec<JSONValue>);
impl<'a> ImportsExportsArray<'a> for ImportsExportsSerdeArray<'a> {
type Entry = ImportsExportsSerdeEntry<'a>;
fn len(&self) -> usize {
self.0.len()
}
fn iter(&self) -> impl Iterator<Item = ImportsExportsSerdeEntry<'a>> {
ImportsExportsSerdeArrayIter { vec: self.0, index: 0 }
}
}
struct ImportsExportsSerdeArrayIter<'a> {
vec: &'a Vec<JSONValue>,
index: usize,
}
impl<'a> Iterator for ImportsExportsSerdeArrayIter<'a> {
type Item = ImportsExportsSerdeEntry<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.vec.get(self.index).map(|value| {
self.index += 1;
ImportsExportsSerdeEntry(value)
})
}
}
#[derive(Clone)]
pub struct ImportsExportsSerdeMap<'a>(pub(crate) &'a JSONMap);
impl<'a> ImportsExportsMap<'a> for ImportsExportsSerdeMap<'a> {
type Entry = ImportsExportsSerdeEntry<'a>;
fn get(&self, key: &str) -> Option<Self::Entry> {
self.0.get(key).map(ImportsExportsSerdeEntry)
}
fn keys(&self) -> impl Iterator<Item = &'a str> {
ImportsExportsSerdeMapKeysIter { inner: self.0.keys() }
}
fn iter(&self) -> impl Iterator<Item = (&'a str, ImportsExportsSerdeEntry<'a>)> {
ImportsExportsSerdeMapIter { inner: self.0.iter() }
}
}
struct ImportsExportsSerdeMapIter<'a> {
inner: serde_json::map::Iter<'a>,
}
impl<'a> Iterator for ImportsExportsSerdeMapIter<'a> {
type Item = (&'a str, ImportsExportsSerdeEntry<'a>);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(key, value)| (key.as_str(), ImportsExportsSerdeEntry(value)))
}
}
struct ImportsExportsSerdeMapKeysIter<'a> {
inner: serde_json::map::Keys<'a>,
}
impl<'a> Iterator for ImportsExportsSerdeMapKeysIter<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(String::as_str)
}
}