nodejs_resolver/
description.rs

1use crate::info::NormalizedPath;
2use crate::{AliasMap, Error, RResult};
3use once_cell::sync::OnceCell;
4use std::path::Path;
5use std::sync::Arc;
6
7#[derive(Debug)]
8pub struct PkgJSON {
9    name: Option<Box<str>>,
10    alias_fields: OnceCell<Vec<(String, AliasMap)>>,
11    raw: Arc<serde_json::Value>,
12}
13
14impl PkgJSON {
15    pub(crate) fn parse(content: &str, file_path: &Path) -> RResult<Self> {
16        let json: serde_json::Value =
17            tracing::debug_span!("serde_json_from_str").in_scope(|| {
18                serde_json::from_str(content)
19                    .map_err(|error| Error::UnexpectedJson((file_path.into(), error)))
20            })?;
21
22        let name = json.get("name").and_then(|v| v.as_str()).map(|s| s.into());
23
24        Ok(Self {
25            name,
26            alias_fields: OnceCell::new(),
27            raw: Arc::from(json),
28        })
29    }
30
31    pub fn alias_fields(&self) -> &Vec<(String, AliasMap)> {
32        self.alias_fields.get_or_init(|| {
33            let mut alias_fields = Vec::new();
34
35            if let Some(value) = self.raw.get("browser") {
36                // https://github.com/defunctzombie/package-browser-field-spec
37                if let Some(map) = value.as_object() {
38                    for (key, value) in map {
39                        if let Some(false) = value.as_bool() {
40                            alias_fields.push((key.to_string(), AliasMap::Ignored));
41                        } else if let Some(s) = value.as_str() {
42                            alias_fields.push((key.to_string(), AliasMap::Target(s.to_string())));
43                        }
44                    }
45                } else if let Some(false) = value.as_bool() {
46                    alias_fields.push((String::from("."), AliasMap::Ignored));
47                } else if let Some(s) = value.as_str() {
48                    alias_fields.push((String::from("."), AliasMap::Target(s.to_string())));
49                }
50            }
51            alias_fields
52        })
53    }
54
55    pub(crate) fn get_filed(&self, field: &Vec<String>) -> Option<&serde_json::Value> {
56        let mut current_value = self.raw().as_ref();
57        for current_field in field {
58            if !current_value.is_object() {
59                return None;
60            }
61            match current_value.get(current_field) {
62                Some(next) => current_value = next,
63                None => return None,
64            };
65        }
66        Some(current_value)
67    }
68
69    pub fn name(&self) -> Option<&str> {
70        self.name.as_deref()
71    }
72
73    pub fn raw(&self) -> &Arc<serde_json::Value> {
74        &self.raw
75    }
76}
77
78#[derive(Debug)]
79pub struct DescriptionData {
80    json: PkgJSON,
81    /// The path to the directory where the description file located.
82    /// It not a property in package.json.
83    dir_path: NormalizedPath,
84}
85
86impl DescriptionData {
87    pub fn new<P: AsRef<Path>>(json: PkgJSON, dir_path: P) -> Self {
88        Self {
89            json,
90            dir_path: NormalizedPath::new(dir_path),
91        }
92    }
93
94    pub fn dir(&self) -> &NormalizedPath {
95        &self.dir_path
96    }
97
98    pub fn data(&self) -> &PkgJSON {
99        &self.json
100    }
101}