unrspack_resolver/
package_json.rs

1use std::{fmt::Display, path::Path};
2
3use crate::ResolveError;
4
5/// Abstract representation for the contents of a `package.json` file, as well
6/// as the location where it was found.
7///
8/// This representation makes no assumptions regarding how the file was
9/// deserialized.
10#[allow(clippy::missing_errors_doc)] // trait impls should be free to return any typesafe error
11pub trait PackageJson: Sized {
12    /// Returns the path where the `package.json` was found.
13    ///
14    /// Contains the `package.json` filename.
15    ///
16    /// This does not need to be the path where the file is stored on disk.
17    /// See [Self::realpath()].
18    #[must_use]
19    fn path(&self) -> &Path;
20
21    /// Returns the path where the `package.json` file was stored on disk.
22    ///
23    /// Contains the `package.json` filename.
24    ///
25    /// This is the canonicalized version of [Self::path()], where all symbolic
26    /// links are resolved.
27    #[must_use]
28    fn realpath(&self) -> &Path;
29
30    /// Directory to `package.json`.
31    ///
32    /// # Panics
33    ///
34    /// * When the `package.json` path is misconfigured.
35    #[must_use]
36    fn directory(&self) -> &Path;
37
38    /// Name of the package.
39    ///
40    /// The "name" field can be used together with the "exports" field to
41    /// self-reference a package using its name.
42    ///
43    /// <https://nodejs.org/api/packages.html#name>
44    fn name(&self) -> Option<&str>;
45
46    /// Returns the package type, if one is configured in the `package.json`.
47    ///
48    /// <https://nodejs.org/api/packages.html#type>
49    fn r#type(&self) -> Option<PackageType>;
50
51    /// The "main" field defines the entry point of a package when imported by
52    /// name via a node_modules lookup. Its value should be a path.
53    ///
54    /// When a package has an "exports" field, this will take precedence over
55    /// the "main" field when importing the package by name.
56    ///
57    /// Values are dynamically retrieved from [crate::ResolveOptions::main_fields].
58    ///
59    /// <https://nodejs.org/api/packages.html#main>
60    #[must_use]
61    fn main_fields<'a>(&'a self, main_fields: &'a [String]) -> impl Iterator<Item = &'a str> + 'a;
62
63    /// The "exports" field allows defining the entry points of a package when
64    /// imported by name loaded either via a node_modules lookup or a
65    /// self-reference to its own name.
66    ///
67    /// <https://nodejs.org/api/packages.html#exports>
68    #[must_use]
69    fn exports_fields<'a>(
70        &'a self,
71        exports_fields: &'a [Vec<String>],
72    ) -> impl Iterator<Item = impl ImportsExportsEntry<'a>> + 'a;
73
74    /// In addition to the "exports" field, there is a package "imports" field
75    /// to create private mappings that only apply to import specifiers from
76    /// within the package itself.
77    ///
78    /// <https://nodejs.org/api/packages.html#subpath-imports>
79    #[must_use]
80    fn imports_fields<'a>(
81        &'a self,
82        imports_fields: &'a [Vec<String>],
83    ) -> impl Iterator<Item = impl ImportsExportsMap<'a>> + 'a;
84
85    /// Resolves the request string for this `package.json` by looking at the
86    /// "browser" field.
87    ///
88    /// <https://github.com/defunctzombie/package-browser-field-spec>
89    fn resolve_browser_field<'a>(
90        &'a self,
91        path: &Path,
92        request: Option<&str>,
93        alias_fields: &'a [Vec<String>],
94    ) -> Result<Option<&'a str>, ResolveError>;
95}
96
97#[derive(Clone, Copy, Debug, Eq, PartialEq)]
98#[cfg_attr(feature = "fs_cache", derive(serde::Deserialize, serde::Serialize))]
99#[cfg_attr(feature = "fs_cache", serde(rename_all = "lowercase"))]
100pub enum PackageType {
101    CommonJs,
102    Module,
103}
104
105impl Display for PackageType {
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        match self {
108            Self::CommonJs => f.write_str("commonjs"),
109            Self::Module => f.write_str("module"),
110        }
111    }
112}
113
114/// Trait used for representing entries in the `imports` and `exports` fields
115/// without allocation.
116pub trait ImportsExportsEntry<'a>: Clone + Sized {
117    type Array: ImportsExportsArray<'a, Entry = Self>;
118    type Map: ImportsExportsMap<'a, Entry = Self>;
119
120    fn kind(&self) -> ImportsExportsKind;
121
122    fn as_string(&self) -> Option<&'a str>;
123    fn as_array(&self) -> Option<Self::Array>;
124    fn as_map(&self) -> Option<Self::Map>;
125}
126
127/// Trait used for representing array values in the `imports` and `exports`
128/// fields without allocation.
129pub trait ImportsExportsArray<'a>: Clone + Sized {
130    type Entry: ImportsExportsEntry<'a, Array = Self>;
131
132    fn is_empty(&self) -> bool {
133        self.len() == 0
134    }
135
136    fn len(&self) -> usize;
137    fn iter(&self) -> impl Iterator<Item = Self::Entry>;
138}
139
140/// Trait used for representing map (object) values in the `imports` and
141/// `exports` fields without allocation.
142pub trait ImportsExportsMap<'a>: Clone + Sized {
143    type Entry: ImportsExportsEntry<'a, Map = Self>;
144
145    fn get(&self, key: &str) -> Option<Self::Entry>;
146    fn keys(&self) -> impl Iterator<Item = &'a str>;
147    fn iter(&self) -> impl Iterator<Item = (&'a str, Self::Entry)>;
148}
149
150#[derive(Clone, Copy, Debug, Eq, PartialEq)]
151pub enum ImportsExportsKind {
152    String,
153    Array,
154    Map,
155    Invalid,
156}