unrspack_resolver/
error.rs1use std::{io, path::PathBuf, sync::Arc};
2
3use thiserror::Error;
4
5#[derive(Debug, Clone, PartialEq, Error)]
9#[non_exhaustive]
10pub enum ResolveError {
11 #[error("Path is ignored {0}")]
23 Ignored(PathBuf),
24
25 #[error("Cannot find module '{0}'")]
27 NotFound(String),
28
29 #[error("Cannot find module '{0}' for matched aliased key '{1}'")]
31 MatchedAliasNotFound(String, String),
32
33 #[error("Tsconfig not found {0}")]
35 TsconfigNotFound(PathBuf),
36
37 #[error("Tsconfig's project reference path points to this tsconfig {0}")]
39 TsconfigSelfReference(PathBuf),
40
41 #[error("{0}")]
42 IOError(IOError),
43
44 #[error("Builtin module {resolved}")]
51 Builtin { resolved: String, is_runtime_module: bool },
52
53 #[error("Cannot resolve '{0}' for extension aliases '{1}' in '{2}'")]
57 ExtensionAlias(
58 String,
59 String,
60 PathBuf,
61 ),
62
63 #[error("{0}")]
65 Specifier(SpecifierError),
66
67 #[error("{0:?}")]
69 JSON(JSONError),
70
71 #[error(r#"Path "{0}" restricted by {0}"#)]
73 Restriction(PathBuf, PathBuf),
74
75 #[error(r#"Invalid module "{0}" specifier is not a valid subpath for the "exports" resolution of {1}"#)]
76 InvalidModuleSpecifier(String, PathBuf),
77
78 #[error(r#"Invalid "exports" target "{0}" defined for '{1}' in the package config {2}"#)]
79 InvalidPackageTarget(String, String, PathBuf),
80
81 #[error(r#"Package subpath '{0}' is not defined by "exports" in {1}"#)]
82 PackagePathNotExported(String, PathBuf),
83
84 #[error(r#"Invalid package config "{0}", "exports" cannot contain some keys starting with '.' and some not. The exports object must either be an object of package subpath keys or an object of main entry condition name keys only."#)]
85 InvalidPackageConfig(PathBuf),
86
87 #[error(r#"Default condition should be last one in "{0}""#)]
88 InvalidPackageConfigDefault(PathBuf),
89
90 #[error(r#"Expecting folder to folder mapping. "{0}" should end with "/"#)]
91 InvalidPackageConfigDirectory(PathBuf),
92
93 #[error(r#"Package import specifier "{0}" is not defined in package {1}"#)]
94 PackageImportNotDefined(String, PathBuf),
95
96 #[error("{0} is unimplemented")]
97 Unimplemented(&'static str),
98
99 #[error("Recursion in resolving")]
101 Recursion,
102}
103
104impl ResolveError {
105 #[must_use]
106 pub const fn is_ignore(&self) -> bool {
107 matches!(self, Self::Ignored(_))
108 }
109
110 #[must_use]
111 #[cfg(feature = "fs_cache")]
112 pub fn from_serde_json_error(
113 path: PathBuf,
114 error: &serde_json::Error,
115 content: Option<String>,
116 ) -> Self {
117 Self::JSON(JSONError {
118 path,
119 message: error.to_string(),
120 line: error.line(),
121 column: error.column(),
122 content,
123 })
124 }
125}
126
127#[derive(Debug, Clone, Eq, PartialEq, Error)]
129pub enum SpecifierError {
130 #[error("The specifiers must be a non-empty string. Received \"{0}\"")]
131 Empty(String),
132}
133
134#[derive(Debug, Clone, Eq, PartialEq)]
136pub struct JSONError {
137 pub path: PathBuf,
138 pub message: String,
139 pub line: usize,
140 pub column: usize,
141 pub content: Option<String>,
142}
143
144#[derive(Debug, Clone, Error)]
145#[error("{0}")]
146pub struct IOError(Arc<io::Error>);
147
148impl PartialEq for IOError {
149 fn eq(&self, other: &Self) -> bool {
150 self.0.kind() == other.0.kind()
151 }
152}
153
154impl From<IOError> for io::Error {
155 fn from(error: IOError) -> Self {
156 let io_error = error.0.as_ref();
157 Self::new(io_error.kind(), io_error.to_string())
158 }
159}
160
161impl From<io::Error> for ResolveError {
162 fn from(err: io::Error) -> Self {
163 Self::IOError(IOError(Arc::new(err)))
164 }
165}
166
167#[test]
168fn test_into_io_error() {
169 use std::io::{self, ErrorKind};
170 let error_string = "IOError occurred";
171 let string_error = io::Error::new(ErrorKind::Interrupted, error_string.to_string());
172 let string_error2 = io::Error::new(ErrorKind::Interrupted, error_string.to_string());
173 let resolve_io_error: ResolveError = ResolveError::from(string_error2);
174
175 assert_eq!(resolve_io_error, ResolveError::from(string_error));
176 assert_eq!(resolve_io_error.clone(), resolve_io_error);
177 let ResolveError::IOError(io_error) = resolve_io_error else { unreachable!() };
178 assert_eq!(
179 format!("{io_error:?}"),
180 r#"IOError(Custom { kind: Interrupted, error: "IOError occurred" })"#
181 );
182 let std_io_error: io::Error = io_error.into();
184 assert_eq!(std_io_error.kind(), ErrorKind::Interrupted);
185 assert_eq!(std_io_error.to_string(), error_string);
186 assert_eq!(
187 format!("{std_io_error:?}"),
188 r#"Custom { kind: Interrupted, error: "IOError occurred" }"#
189 );
190}
191
192#[test]
193fn test_coverage() {
194 let error = ResolveError::NotFound("x".into());
195 assert_eq!(format!("{error:?}"), r#"NotFound("x")"#);
196 assert_eq!(error.clone(), error);
197
198 let error = ResolveError::Specifier(SpecifierError::Empty("x".into()));
199 assert_eq!(format!("{error:?}"), r#"Specifier(Empty("x"))"#);
200 assert_eq!(error.clone(), error);
201}