oxc_resolver/
resolution.rs

1use std::{
2    fmt,
3    path::{Path, PathBuf},
4    sync::Arc,
5};
6
7use crate::PackageJson;
8
9#[derive(Debug, Clone, Copy, Eq, PartialEq)]
10pub enum ModuleType {
11    Module,
12    CommonJs,
13    Json,
14    Wasm,
15    Addon,
16}
17
18/// The final path resolution with optional `?query` and `#fragment`
19pub struct Resolution {
20    pub(crate) path: PathBuf,
21
22    /// Path query `?query`, contains `?`.
23    pub(crate) query: Option<String>,
24
25    /// Path fragment `#query`, contains `#`.
26    pub(crate) fragment: Option<String>,
27
28    /// `package.json` for the given module.
29    pub(crate) package_json: Option<Arc<PackageJson>>,
30
31    /// Module type for this path.
32    ///
33    /// Enable with [crate::ResolveOptions::module_type].
34    ///
35    /// The module type is computed `ESM_FILE_FORMAT` from the [ESM resolution algorithm specification](https://nodejs.org/docs/latest/api/esm.html#resolution-algorithm-specification).
36    ///
37    ///  The algorithm uses the file extension or finds the closest `package.json` with the `type` field.
38    pub(crate) module_type: Option<ModuleType>,
39}
40
41impl Clone for Resolution {
42    fn clone(&self) -> Self {
43        Self {
44            path: self.path.clone(),
45            query: self.query.clone(),
46            fragment: self.fragment.clone(),
47            package_json: self.package_json.clone(),
48            module_type: self.module_type,
49        }
50    }
51}
52
53impl fmt::Debug for Resolution {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        f.debug_struct("Resolution")
56            .field("path", &self.path)
57            .field("query", &self.query)
58            .field("fragment", &self.fragment)
59            .field("module_type", &self.module_type)
60            .field("package_json", &self.package_json.as_ref().map(|p| p.path()))
61            .finish()
62    }
63}
64
65impl PartialEq for Resolution {
66    fn eq(&self, other: &Self) -> bool {
67        self.path == other.path && self.query == other.query && self.fragment == other.fragment
68    }
69}
70impl Eq for Resolution {}
71
72impl Resolution {
73    /// Returns the path without query and fragment
74    #[must_use]
75    pub fn path(&self) -> &Path {
76        &self.path
77    }
78
79    /// Returns the path without query and fragment
80    #[must_use]
81    pub fn into_path_buf(self) -> PathBuf {
82        self.path
83    }
84
85    /// Returns the path query `?query`, contains the leading `?`
86    #[must_use]
87    pub fn query(&self) -> Option<&str> {
88        self.query.as_deref()
89    }
90
91    /// Returns the path fragment `#fragment`, contains the leading `#`
92    #[must_use]
93    pub fn fragment(&self) -> Option<&str> {
94        self.fragment.as_deref()
95    }
96
97    /// Returns serialized package_json
98    #[must_use]
99    pub fn package_json(&self) -> Option<&Arc<PackageJson>> {
100        self.package_json.as_ref()
101    }
102
103    /// Returns the full path with query and fragment
104    #[must_use]
105    pub fn full_path(&self) -> PathBuf {
106        let mut path = self.path.clone().into_os_string();
107        if let Some(query) = &self.query {
108            path.push(query);
109        }
110        if let Some(fragment) = &self.fragment {
111            path.push(fragment);
112        }
113        PathBuf::from(path)
114    }
115
116    /// Returns the module type of this path.
117    #[must_use]
118    pub fn module_type(&self) -> Option<ModuleType> {
119        self.module_type
120    }
121}