node_resolver/
errors.rs

1// Copyright 2018-2025 the Deno authors. MIT license.
2
3use std::borrow::Cow;
4use std::fmt::Write;
5use std::path::PathBuf;
6
7use boxed_error::Boxed;
8use deno_error::JsError;
9use deno_path_util::UrlToFilePathError;
10use thiserror::Error;
11use url::Url;
12
13use crate::NodeResolutionKind;
14use crate::ResolutionMode;
15use crate::path::UrlOrPath;
16
17#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
18#[allow(non_camel_case_types)]
19pub enum NodeJsErrorCode {
20  ERR_INVALID_MODULE_SPECIFIER,
21  ERR_INVALID_PACKAGE_CONFIG,
22  ERR_INVALID_PACKAGE_TARGET,
23  ERR_MODULE_NOT_FOUND,
24  ERR_PACKAGE_IMPORT_NOT_DEFINED,
25  ERR_PACKAGE_PATH_NOT_EXPORTED,
26  ERR_UNKNOWN_FILE_EXTENSION,
27  ERR_UNSUPPORTED_DIR_IMPORT,
28  ERR_UNSUPPORTED_ESM_URL_SCHEME,
29  ERR_INVALID_FILE_URL_PATH,
30  ERR_UNKNOWN_BUILTIN_MODULE,
31  /// Deno specific since Node doesn't support TypeScript.
32  ERR_TYPES_NOT_FOUND,
33}
34
35impl std::fmt::Display for NodeJsErrorCode {
36  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37    write!(f, "{}", self.as_str())
38  }
39}
40
41impl NodeJsErrorCode {
42  pub fn as_str(&self) -> &'static str {
43    use NodeJsErrorCode::*;
44    match self {
45      ERR_INVALID_MODULE_SPECIFIER => "ERR_INVALID_MODULE_SPECIFIER",
46      ERR_INVALID_PACKAGE_CONFIG => "ERR_INVALID_PACKAGE_CONFIG",
47      ERR_INVALID_PACKAGE_TARGET => "ERR_INVALID_PACKAGE_TARGET",
48      ERR_MODULE_NOT_FOUND => "ERR_MODULE_NOT_FOUND",
49      ERR_PACKAGE_IMPORT_NOT_DEFINED => "ERR_PACKAGE_IMPORT_NOT_DEFINED",
50      ERR_PACKAGE_PATH_NOT_EXPORTED => "ERR_PACKAGE_PATH_NOT_EXPORTED",
51      ERR_UNKNOWN_FILE_EXTENSION => "ERR_UNKNOWN_FILE_EXTENSION",
52      ERR_UNSUPPORTED_DIR_IMPORT => "ERR_UNSUPPORTED_DIR_IMPORT",
53      ERR_UNSUPPORTED_ESM_URL_SCHEME => "ERR_UNSUPPORTED_ESM_URL_SCHEME",
54      ERR_TYPES_NOT_FOUND => "ERR_TYPES_NOT_FOUND",
55      ERR_INVALID_FILE_URL_PATH => "ERR_INVALID_FILE_URL_PATH",
56      ERR_UNKNOWN_BUILTIN_MODULE => "ERR_UNKNOWN_BUILTIN_MODULE",
57    }
58  }
59}
60
61impl From<NodeJsErrorCode> for deno_error::PropertyValue {
62  fn from(value: NodeJsErrorCode) -> Self {
63    deno_error::PropertyValue::String(value.as_str().into())
64  }
65}
66
67pub trait NodeJsErrorCoded {
68  fn code(&self) -> NodeJsErrorCode;
69}
70
71#[derive(Debug, Clone, Error, JsError)]
72#[error(
73  "[{}] Invalid module '{}' {}{}",
74  self.code(),
75  request,
76  reason,
77  maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default()
78)]
79#[class(type)]
80#[property("code" = self.code())]
81pub struct InvalidModuleSpecifierError {
82  pub request: String,
83  pub reason: Cow<'static, str>,
84  pub maybe_referrer: Option<String>,
85}
86
87impl NodeJsErrorCoded for InvalidModuleSpecifierError {
88  fn code(&self) -> NodeJsErrorCode {
89    NodeJsErrorCode::ERR_INVALID_MODULE_SPECIFIER
90  }
91}
92
93#[derive(Debug, Boxed, JsError)]
94pub struct LegacyResolveError(pub Box<LegacyResolveErrorKind>);
95
96impl LegacyResolveError {
97  pub fn specifier(&self) -> &UrlOrPath {
98    match self.as_kind() {
99      LegacyResolveErrorKind::TypesNotFound(err) => &err.0.code_specifier,
100      LegacyResolveErrorKind::ModuleNotFound(err) => &err.specifier,
101    }
102  }
103}
104
105#[derive(Debug, Error, JsError)]
106pub enum LegacyResolveErrorKind {
107  #[class(inherit)]
108  #[error(transparent)]
109  TypesNotFound(#[from] TypesNotFoundError),
110  #[class(inherit)]
111  #[error(transparent)]
112  ModuleNotFound(#[from] ModuleNotFoundError),
113}
114
115impl NodeJsErrorCoded for LegacyResolveError {
116  fn code(&self) -> NodeJsErrorCode {
117    match self.as_kind() {
118      LegacyResolveErrorKind::TypesNotFound(e) => e.code(),
119      LegacyResolveErrorKind::ModuleNotFound(e) => e.code(),
120    }
121  }
122}
123
124#[derive(Debug, Error, JsError)]
125#[error(
126  "Could not find package '{}' from referrer '{}'{}.",
127  package_name,
128  referrer,
129  referrer_extra.as_ref().map(|r| format!(" ({})", r)).unwrap_or_default()
130)]
131#[class(generic)]
132#[property("code" = self.code())]
133pub struct PackageNotFoundError {
134  pub package_name: String,
135  pub referrer: UrlOrPath,
136  /// Extra information about the referrer.
137  pub referrer_extra: Option<String>,
138}
139
140impl NodeJsErrorCoded for PackageNotFoundError {
141  fn code(&self) -> NodeJsErrorCode {
142    NodeJsErrorCode::ERR_MODULE_NOT_FOUND
143  }
144}
145
146#[derive(Debug, Error, JsError)]
147#[error(
148  "Could not find referrer npm package '{}'{}.",
149  referrer,
150  referrer_extra.as_ref().map(|r| format!(" ({})", r)).unwrap_or_default()
151)]
152#[class(generic)]
153#[property("code" = self.code())]
154pub struct ReferrerNotFoundError {
155  pub referrer: UrlOrPath,
156  /// Extra information about the referrer.
157  pub referrer_extra: Option<String>,
158}
159
160impl NodeJsErrorCoded for ReferrerNotFoundError {
161  fn code(&self) -> NodeJsErrorCode {
162    NodeJsErrorCode::ERR_MODULE_NOT_FOUND
163  }
164}
165
166#[derive(Debug, Error, JsError)]
167#[class(inherit)]
168#[error("Failed resolving '{package_name}' from referrer '{referrer}'.")]
169#[property("code" = self.code())]
170pub struct PackageFolderResolveIoError {
171  pub package_name: String,
172  pub referrer: UrlOrPath,
173  #[source]
174  #[inherit]
175  pub source: std::io::Error,
176}
177
178impl NodeJsErrorCoded for PackageFolderResolveIoError {
179  fn code(&self) -> NodeJsErrorCode {
180    NodeJsErrorCode::ERR_MODULE_NOT_FOUND
181  }
182}
183
184impl NodeJsErrorCoded for PackageFolderResolveErrorKind {
185  fn code(&self) -> NodeJsErrorCode {
186    match self {
187      PackageFolderResolveErrorKind::PackageNotFound(e) => e.code(),
188      PackageFolderResolveErrorKind::ReferrerNotFound(e) => e.code(),
189      PackageFolderResolveErrorKind::Io(e) => e.code(),
190      PackageFolderResolveErrorKind::PathToUrl(_) => {
191        NodeJsErrorCode::ERR_INVALID_FILE_URL_PATH
192      }
193    }
194  }
195}
196
197#[derive(Debug, Boxed, JsError)]
198pub struct PackageFolderResolveError(pub Box<PackageFolderResolveErrorKind>);
199
200#[derive(Debug, Error, JsError)]
201pub enum PackageFolderResolveErrorKind {
202  #[class(inherit)]
203  #[error(transparent)]
204  PackageNotFound(#[from] PackageNotFoundError),
205  #[class(inherit)]
206  #[error(transparent)]
207  ReferrerNotFound(#[from] ReferrerNotFoundError),
208  #[class(inherit)]
209  #[error(transparent)]
210  Io(#[from] PackageFolderResolveIoError),
211  #[class(inherit)]
212  #[error(transparent)]
213  #[property("code" = self.code())]
214  PathToUrl(#[from] deno_path_util::PathToUrlError),
215}
216
217#[derive(Debug, Boxed, JsError)]
218pub struct PackageSubpathFromDenoModuleResolveError(
219  pub Box<PackageSubpathFromDenoModuleResolveErrorKind>,
220);
221
222impl NodeJsErrorCoded for PackageSubpathFromDenoModuleResolveError {
223  fn code(&self) -> NodeJsErrorCode {
224    match self.as_kind() {
225      PackageSubpathFromDenoModuleResolveErrorKind::SubPath(e) => e.code(),
226      PackageSubpathFromDenoModuleResolveErrorKind::FinalizeResolution(e) => {
227        e.code()
228      }
229    }
230  }
231}
232
233impl PackageSubpathFromDenoModuleResolveError {
234  pub fn as_types_not_found(&self) -> Option<&TypesNotFoundError> {
235    match self.as_kind() {
236      PackageSubpathFromDenoModuleResolveErrorKind::SubPath(e) => {
237        e.as_types_not_found()
238      }
239      PackageSubpathFromDenoModuleResolveErrorKind::FinalizeResolution(e) => {
240        e.as_types_not_found()
241      }
242    }
243  }
244
245  pub fn maybe_specifier(&self) -> Option<Cow<'_, UrlOrPath>> {
246    match self.as_kind() {
247      PackageSubpathFromDenoModuleResolveErrorKind::SubPath(e) => {
248        e.maybe_specifier()
249      }
250      PackageSubpathFromDenoModuleResolveErrorKind::FinalizeResolution(e) => {
251        e.maybe_specifier()
252      }
253    }
254  }
255
256  pub fn into_node_resolve_error(self) -> NodeResolveError {
257    match self.into_kind() {
258      PackageSubpathFromDenoModuleResolveErrorKind::SubPath(e) => {
259        NodeResolveErrorKind::PackageResolve(
260          PackageResolveErrorKind::SubpathResolve(e).into_box(),
261        )
262      }
263      PackageSubpathFromDenoModuleResolveErrorKind::FinalizeResolution(e) => {
264        NodeResolveErrorKind::FinalizeResolution(e)
265      }
266    }
267    .into_box()
268  }
269}
270
271#[derive(Debug, Error, JsError)]
272pub enum PackageSubpathFromDenoModuleResolveErrorKind {
273  #[class(inherit)]
274  #[error(transparent)]
275  SubPath(#[from] PackageSubpathResolveError),
276  #[class(inherit)]
277  #[error(transparent)]
278  FinalizeResolution(#[from] FinalizeResolutionError),
279}
280
281#[derive(Debug, Boxed, JsError)]
282pub struct PackageSubpathResolveError(pub Box<PackageSubpathResolveErrorKind>);
283
284impl NodeJsErrorCoded for PackageSubpathResolveError {
285  fn code(&self) -> NodeJsErrorCode {
286    match self.as_kind() {
287      PackageSubpathResolveErrorKind::PkgJsonLoad(e) => e.code(),
288      PackageSubpathResolveErrorKind::Exports(e) => e.code(),
289      PackageSubpathResolveErrorKind::LegacyResolve(e) => e.code(),
290    }
291  }
292}
293
294impl PackageSubpathResolveError {
295  pub fn as_types_not_found(&self) -> Option<&TypesNotFoundError> {
296    self.as_kind().as_types_not_found()
297  }
298
299  pub fn maybe_specifier(&self) -> Option<Cow<'_, UrlOrPath>> {
300    match self.as_kind() {
301      PackageSubpathResolveErrorKind::PkgJsonLoad(_) => None,
302      PackageSubpathResolveErrorKind::Exports(err) => err.maybe_specifier(),
303      PackageSubpathResolveErrorKind::LegacyResolve(err) => {
304        Some(Cow::Borrowed(err.specifier()))
305      }
306    }
307  }
308}
309
310#[derive(Debug, Error, JsError)]
311pub enum PackageSubpathResolveErrorKind {
312  #[class(inherit)]
313  #[error(transparent)]
314  PkgJsonLoad(#[from] PackageJsonLoadError),
315  #[class(inherit)]
316  #[error(transparent)]
317  Exports(PackageExportsResolveError),
318  #[class(inherit)]
319  #[error(transparent)]
320  LegacyResolve(LegacyResolveError),
321}
322
323impl PackageSubpathResolveErrorKind {
324  pub fn as_types_not_found(&self) -> Option<&TypesNotFoundError> {
325    match self {
326      PackageSubpathResolveErrorKind::PkgJsonLoad(_) => None,
327      PackageSubpathResolveErrorKind::Exports(err) => match err.as_kind() {
328        PackageExportsResolveErrorKind::PackagePathNotExported(_) => None,
329        PackageExportsResolveErrorKind::PackageTargetResolve(err) => {
330          match err.as_kind() {
331            PackageTargetResolveErrorKind::TypesNotFound(not_found) => {
332              Some(not_found)
333            }
334            PackageTargetResolveErrorKind::NotFound(_)
335            | PackageTargetResolveErrorKind::InvalidPackageTarget(_)
336            | PackageTargetResolveErrorKind::InvalidModuleSpecifier(_)
337            | PackageTargetResolveErrorKind::PackageResolve(_)
338            | PackageTargetResolveErrorKind::UnknownBuiltInNodeModule(_)
339            | PackageTargetResolveErrorKind::UrlToFilePath(_) => None,
340          }
341        }
342      },
343      PackageSubpathResolveErrorKind::LegacyResolve(err) => match err.as_kind()
344      {
345        LegacyResolveErrorKind::TypesNotFound(not_found) => Some(not_found),
346        LegacyResolveErrorKind::ModuleNotFound(_) => None,
347      },
348    }
349  }
350}
351
352#[derive(Debug, Error, JsError)]
353#[class(generic)]
354#[error(
355  "Target '{}' not found from '{}'{}{}.",
356  target,
357  pkg_json_path.display(),
358  maybe_referrer.as_ref().map(|r|
359    format!(
360      " from{} referrer {}",
361      match resolution_mode {
362        ResolutionMode::Import => "",
363        ResolutionMode::Require => " cjs",
364      },
365      r
366    )
367  ).unwrap_or_default(),
368  match resolution_kind {
369    NodeResolutionKind::Execution => "",
370    NodeResolutionKind::Types => " for types",
371  }
372)]
373#[property("code" = self.code())]
374pub struct PackageTargetNotFoundError {
375  pub pkg_json_path: PathBuf,
376  pub target: String,
377  pub maybe_resolved: Option<UrlOrPath>,
378  pub maybe_referrer: Option<UrlOrPath>,
379  pub resolution_mode: ResolutionMode,
380  pub resolution_kind: NodeResolutionKind,
381}
382
383impl NodeJsErrorCoded for PackageTargetNotFoundError {
384  fn code(&self) -> NodeJsErrorCode {
385    NodeJsErrorCode::ERR_MODULE_NOT_FOUND
386  }
387}
388
389impl NodeJsErrorCoded for PackageTargetResolveErrorKind {
390  fn code(&self) -> NodeJsErrorCode {
391    match self {
392      PackageTargetResolveErrorKind::NotFound(e) => e.code(),
393      PackageTargetResolveErrorKind::InvalidPackageTarget(e) => e.code(),
394      PackageTargetResolveErrorKind::InvalidModuleSpecifier(e) => e.code(),
395      PackageTargetResolveErrorKind::PackageResolve(e) => e.code(),
396      PackageTargetResolveErrorKind::TypesNotFound(e) => e.code(),
397      PackageTargetResolveErrorKind::UnknownBuiltInNodeModule(e) => e.code(),
398      PackageTargetResolveErrorKind::UrlToFilePath(_) => {
399        NodeJsErrorCode::ERR_INVALID_FILE_URL_PATH
400      }
401    }
402  }
403}
404
405#[derive(Debug, Boxed, JsError)]
406pub struct PackageTargetResolveError(pub Box<PackageTargetResolveErrorKind>);
407
408impl PackageTargetResolveError {
409  pub fn maybe_specifier(&self) -> Option<Cow<'_, UrlOrPath>> {
410    match self.as_kind() {
411      PackageTargetResolveErrorKind::NotFound(err) => {
412        err.maybe_resolved.as_ref().map(Cow::Borrowed)
413      }
414      PackageTargetResolveErrorKind::PackageResolve(err) => {
415        err.maybe_specifier()
416      }
417      PackageTargetResolveErrorKind::TypesNotFound(err) => {
418        Some(Cow::Borrowed(&err.0.code_specifier))
419      }
420      PackageTargetResolveErrorKind::UnknownBuiltInNodeModule(err) => {
421        err.maybe_specifier().map(|u| Cow::Owned(UrlOrPath::Url(u)))
422      }
423      PackageTargetResolveErrorKind::UrlToFilePath(e) => {
424        Some(Cow::Owned(UrlOrPath::Url(e.0.clone())))
425      }
426      PackageTargetResolveErrorKind::InvalidPackageTarget(_)
427      | PackageTargetResolveErrorKind::InvalidModuleSpecifier(_) => None,
428    }
429  }
430}
431
432#[derive(Debug, Error, JsError)]
433pub enum PackageTargetResolveErrorKind {
434  #[class(inherit)]
435  #[error(transparent)]
436  NotFound(#[from] PackageTargetNotFoundError),
437  #[class(inherit)]
438  #[error(transparent)]
439  InvalidPackageTarget(#[from] InvalidPackageTargetError),
440  #[class(inherit)]
441  #[error(transparent)]
442  InvalidModuleSpecifier(#[from] InvalidModuleSpecifierError),
443  #[class(inherit)]
444  #[error(transparent)]
445  PackageResolve(#[from] PackageResolveError),
446  #[class(inherit)]
447  #[error(transparent)]
448  TypesNotFound(#[from] TypesNotFoundError),
449  #[class(inherit)]
450  #[error(transparent)]
451  UnknownBuiltInNodeModule(#[from] UnknownBuiltInNodeModuleError),
452  #[class(inherit)]
453  #[error(transparent)]
454  #[property("code" = self.code())]
455  UrlToFilePath(#[from] deno_path_util::UrlToFilePathError),
456}
457
458impl PackageTargetResolveErrorKind {
459  pub fn as_types_not_found(&self) -> Option<&TypesNotFoundError> {
460    match self {
461      Self::TypesNotFound(not_found) => Some(not_found),
462      _ => None,
463    }
464  }
465}
466
467impl NodeJsErrorCoded for PackageExportsResolveErrorKind {
468  fn code(&self) -> NodeJsErrorCode {
469    match self {
470      PackageExportsResolveErrorKind::PackagePathNotExported(e) => e.code(),
471      PackageExportsResolveErrorKind::PackageTargetResolve(e) => e.code(),
472    }
473  }
474}
475
476#[derive(Debug, Boxed, JsError)]
477pub struct PackageExportsResolveError(pub Box<PackageExportsResolveErrorKind>);
478
479impl PackageExportsResolveError {
480  pub fn maybe_specifier(&self) -> Option<Cow<'_, UrlOrPath>> {
481    match self.as_kind() {
482      PackageExportsResolveErrorKind::PackagePathNotExported(_) => None,
483      PackageExportsResolveErrorKind::PackageTargetResolve(err) => {
484        err.maybe_specifier()
485      }
486    }
487  }
488}
489
490#[derive(Debug, Error, JsError)]
491pub enum PackageExportsResolveErrorKind {
492  #[class(inherit)]
493  #[error(transparent)]
494  PackagePathNotExported(#[from] PackagePathNotExportedError),
495  #[class(inherit)]
496  #[error(transparent)]
497  PackageTargetResolve(#[from] PackageTargetResolveError),
498}
499
500#[derive(Debug, Error, JsError)]
501#[error(
502    "[{}] Could not find types for '{}'{}",
503    self.code(),
504    self.0.code_specifier,
505    self.0.maybe_referrer.as_ref().map(|r| format!(" imported from '{}'", r)).unwrap_or_default(),
506  )]
507#[class(generic)]
508#[property("code" = self.code())]
509pub struct TypesNotFoundError(pub Box<TypesNotFoundErrorData>);
510
511#[derive(Debug)]
512pub struct TypesNotFoundErrorData {
513  pub code_specifier: UrlOrPath,
514  pub maybe_referrer: Option<UrlOrPath>,
515}
516
517impl NodeJsErrorCoded for TypesNotFoundError {
518  fn code(&self) -> NodeJsErrorCode {
519    NodeJsErrorCode::ERR_TYPES_NOT_FOUND
520  }
521}
522
523#[derive(Debug, Error, JsError)]
524#[class(inherit)]
525#[error("[{}] Invalid package config. {}", self.code(), .0)]
526pub struct PackageJsonLoadError(pub deno_package_json::PackageJsonLoadError);
527
528impl NodeJsErrorCoded for PackageJsonLoadError {
529  fn code(&self) -> NodeJsErrorCode {
530    NodeJsErrorCode::ERR_INVALID_PACKAGE_CONFIG
531  }
532}
533
534#[derive(Debug, Error, JsError)]
535#[class(type)]
536#[error(
537  "[{}] Package import specifier \"{}\" is not defined{}{}",
538  self.code(),
539  name,
540  package_json_path.as_ref().map(|p| format!(" in package {}", p.display())).unwrap_or_default(),
541  maybe_referrer.as_ref().map(|r| format!(" imported from '{}'", r)).unwrap_or_default(),
542)]
543#[property("code" = self.code())]
544pub struct PackageImportNotDefinedError {
545  pub name: String,
546  pub package_json_path: Option<PathBuf>,
547  pub maybe_referrer: Option<UrlOrPath>,
548}
549
550impl NodeJsErrorCoded for PackageImportNotDefinedError {
551  fn code(&self) -> NodeJsErrorCode {
552    NodeJsErrorCode::ERR_PACKAGE_IMPORT_NOT_DEFINED
553  }
554}
555
556#[derive(Debug, Boxed, JsError)]
557pub struct PackageImportsResolveError(pub Box<PackageImportsResolveErrorKind>);
558
559impl PackageImportsResolveError {
560  pub fn maybe_specifier(&self) -> Option<Cow<'_, UrlOrPath>> {
561    match self.as_kind() {
562      PackageImportsResolveErrorKind::Target(err) => err.maybe_specifier(),
563      PackageImportsResolveErrorKind::PkgJsonLoad(_)
564      | PackageImportsResolveErrorKind::InvalidModuleSpecifier(_)
565      | PackageImportsResolveErrorKind::NotDefined(_) => None,
566    }
567  }
568}
569
570#[derive(Debug, Error, JsError)]
571pub enum PackageImportsResolveErrorKind {
572  #[class(inherit)]
573  #[error(transparent)]
574  PkgJsonLoad(PackageJsonLoadError),
575  #[class(inherit)]
576  #[error(transparent)]
577  InvalidModuleSpecifier(#[from] InvalidModuleSpecifierError),
578  #[class(inherit)]
579  #[error(transparent)]
580  NotDefined(#[from] PackageImportNotDefinedError),
581  #[class(inherit)]
582  #[error(transparent)]
583  Target(#[from] PackageTargetResolveError),
584}
585
586impl PackageImportsResolveErrorKind {
587  pub fn as_types_not_found(&self) -> Option<&TypesNotFoundError> {
588    match self {
589      Self::Target(err) => err.as_types_not_found(),
590      _ => None,
591    }
592  }
593}
594
595impl NodeJsErrorCoded for PackageImportsResolveErrorKind {
596  fn code(&self) -> NodeJsErrorCode {
597    match self {
598      Self::PkgJsonLoad(e) => e.code(),
599      Self::InvalidModuleSpecifier(e) => e.code(),
600      Self::NotDefined(e) => e.code(),
601      Self::Target(e) => e.code(),
602    }
603  }
604}
605
606impl NodeJsErrorCoded for PackageResolveErrorKind {
607  fn code(&self) -> NodeJsErrorCode {
608    match self {
609      PackageResolveErrorKind::PkgJsonLoad(e) => e.code(),
610      PackageResolveErrorKind::InvalidModuleSpecifier(e) => e.code(),
611      PackageResolveErrorKind::PackageFolderResolve(e) => e.code(),
612      PackageResolveErrorKind::ExportsResolve(e) => e.code(),
613      PackageResolveErrorKind::SubpathResolve(e) => e.code(),
614      PackageResolveErrorKind::UrlToFilePath(_) => {
615        NodeJsErrorCode::ERR_INVALID_FILE_URL_PATH
616      }
617    }
618  }
619}
620
621#[derive(Debug, Boxed, JsError)]
622pub struct PackageResolveError(pub Box<PackageResolveErrorKind>);
623
624impl PackageResolveError {
625  pub fn maybe_specifier(&self) -> Option<Cow<'_, UrlOrPath>> {
626    match self.as_kind() {
627      PackageResolveErrorKind::ExportsResolve(err) => err.maybe_specifier(),
628      PackageResolveErrorKind::SubpathResolve(err) => err.maybe_specifier(),
629      PackageResolveErrorKind::UrlToFilePath(err) => {
630        Some(Cow::Owned(UrlOrPath::Url(err.0.clone())))
631      }
632      PackageResolveErrorKind::PkgJsonLoad(_)
633      | PackageResolveErrorKind::InvalidModuleSpecifier(_)
634      | PackageResolveErrorKind::PackageFolderResolve(_) => None,
635    }
636  }
637}
638
639#[derive(Debug, Error, JsError)]
640pub enum PackageResolveErrorKind {
641  #[class(inherit)]
642  #[error(transparent)]
643  PkgJsonLoad(#[from] PackageJsonLoadError),
644  #[class(inherit)]
645  #[error(transparent)]
646  InvalidModuleSpecifier(#[from] InvalidModuleSpecifierError),
647  #[class(inherit)]
648  #[error(transparent)]
649  PackageFolderResolve(#[from] PackageFolderResolveError),
650  #[class(inherit)]
651  #[error(transparent)]
652  ExportsResolve(#[from] PackageExportsResolveError),
653  #[class(inherit)]
654  #[error(transparent)]
655  SubpathResolve(#[from] PackageSubpathResolveError),
656  #[class(inherit)]
657  #[error(transparent)]
658  #[property("code" = self.code())]
659  UrlToFilePath(#[from] UrlToFilePathError),
660}
661
662impl PackageResolveErrorKind {
663  pub fn as_types_not_found(&self) -> Option<&TypesNotFoundError> {
664    match self {
665      PackageResolveErrorKind::PkgJsonLoad(_)
666      | PackageResolveErrorKind::InvalidModuleSpecifier(_)
667      | PackageResolveErrorKind::PackageFolderResolve(_)
668      | PackageResolveErrorKind::ExportsResolve(_)
669      | PackageResolveErrorKind::UrlToFilePath(_) => None,
670      PackageResolveErrorKind::SubpathResolve(err) => err.as_types_not_found(),
671    }
672  }
673}
674
675#[derive(Debug, Error, JsError)]
676#[class(generic)]
677#[error("Failed joining '{path}' from '{base}'.")]
678pub struct NodeResolveRelativeJoinError {
679  pub path: String,
680  pub base: Url,
681  #[source]
682  pub source: url::ParseError,
683}
684
685#[derive(Debug, Error, JsError)]
686#[class(generic)]
687#[error("Failed resolving specifier from data url referrer.")]
688pub struct DataUrlReferrerError {
689  #[source]
690  pub source: url::ParseError,
691}
692
693#[derive(Debug, Boxed, JsError)]
694pub struct NodeResolveError(pub Box<NodeResolveErrorKind>);
695
696impl NodeResolveError {
697  pub fn maybe_specifier(&self) -> Option<Cow<'_, UrlOrPath>> {
698    match self.as_kind() {
699      NodeResolveErrorKind::PathToUrl(err) => {
700        Some(Cow::Owned(UrlOrPath::Path(err.0.clone())))
701      }
702      NodeResolveErrorKind::UrlToFilePath(err) => {
703        Some(Cow::Owned(UrlOrPath::Url(err.0.clone())))
704      }
705      NodeResolveErrorKind::PackageImportsResolve(err) => err.maybe_specifier(),
706      NodeResolveErrorKind::PackageResolve(err) => err.maybe_specifier(),
707      NodeResolveErrorKind::TypesNotFound(err) => {
708        Some(Cow::Borrowed(&err.0.code_specifier))
709      }
710      NodeResolveErrorKind::UnknownBuiltInNodeModule(err) => {
711        err.maybe_specifier().map(|u| Cow::Owned(UrlOrPath::Url(u)))
712      }
713      NodeResolveErrorKind::FinalizeResolution(err) => err.maybe_specifier(),
714      NodeResolveErrorKind::UnsupportedEsmUrlScheme(_)
715      | NodeResolveErrorKind::DataUrlReferrer(_)
716      | NodeResolveErrorKind::RelativeJoin(_) => None,
717    }
718  }
719}
720
721#[derive(Debug, Error, JsError)]
722pub enum NodeResolveErrorKind {
723  #[class(inherit)]
724  #[error(transparent)]
725  RelativeJoin(#[from] NodeResolveRelativeJoinError),
726  #[class(inherit)]
727  #[error(transparent)]
728  PathToUrl(#[from] deno_path_util::PathToUrlError),
729  #[class(inherit)]
730  #[error(transparent)]
731  UrlToFilePath(#[from] deno_path_util::UrlToFilePathError),
732  #[class(inherit)]
733  #[error(transparent)]
734  PackageImportsResolve(#[from] PackageImportsResolveError),
735  #[class(inherit)]
736  #[error(transparent)]
737  UnsupportedEsmUrlScheme(#[from] UnsupportedEsmUrlSchemeError),
738  #[class(inherit)]
739  #[error(transparent)]
740  DataUrlReferrer(#[from] DataUrlReferrerError),
741  #[class(inherit)]
742  #[error(transparent)]
743  PackageResolve(#[from] PackageResolveError),
744  #[class(inherit)]
745  #[error(transparent)]
746  TypesNotFound(#[from] TypesNotFoundError),
747  #[class(inherit)]
748  #[error(transparent)]
749  UnknownBuiltInNodeModule(#[from] UnknownBuiltInNodeModuleError),
750  #[class(inherit)]
751  #[error(transparent)]
752  FinalizeResolution(#[from] FinalizeResolutionError),
753}
754
755impl NodeResolveErrorKind {
756  pub fn as_types_not_found(&self) -> Option<&TypesNotFoundError> {
757    match self {
758      NodeResolveErrorKind::TypesNotFound(not_found) => Some(not_found),
759      NodeResolveErrorKind::PackageImportsResolve(err) => {
760        err.as_kind().as_types_not_found()
761      }
762      NodeResolveErrorKind::PackageResolve(package_resolve_error) => {
763        package_resolve_error.as_types_not_found()
764      }
765      NodeResolveErrorKind::UnsupportedEsmUrlScheme(_)
766      | NodeResolveErrorKind::DataUrlReferrer(_)
767      | NodeResolveErrorKind::FinalizeResolution(_)
768      | NodeResolveErrorKind::RelativeJoin(_)
769      | NodeResolveErrorKind::PathToUrl(_)
770      | NodeResolveErrorKind::UnknownBuiltInNodeModule(_)
771      | NodeResolveErrorKind::UrlToFilePath(_) => None,
772    }
773  }
774
775  pub fn maybe_code(&self) -> Option<NodeJsErrorCode> {
776    match self {
777      NodeResolveErrorKind::RelativeJoin(_) => None,
778      NodeResolveErrorKind::PathToUrl(_) => None,
779      NodeResolveErrorKind::UrlToFilePath(_) => None,
780      NodeResolveErrorKind::PackageImportsResolve(e) => Some(e.code()),
781      NodeResolveErrorKind::UnsupportedEsmUrlScheme(e) => Some(e.code()),
782      NodeResolveErrorKind::DataUrlReferrer(_) => None,
783      NodeResolveErrorKind::PackageResolve(e) => Some(e.code()),
784      NodeResolveErrorKind::TypesNotFound(e) => Some(e.code()),
785      NodeResolveErrorKind::UnknownBuiltInNodeModule(e) => Some(e.code()),
786      NodeResolveErrorKind::FinalizeResolution(e) => Some(e.code()),
787    }
788  }
789}
790
791#[derive(Debug, Boxed, JsError)]
792pub struct FinalizeResolutionError(pub Box<FinalizeResolutionErrorKind>);
793
794impl FinalizeResolutionError {
795  pub fn maybe_specifier(&self) -> Option<Cow<'_, UrlOrPath>> {
796    match self.as_kind() {
797      FinalizeResolutionErrorKind::ModuleNotFound(err) => {
798        Some(Cow::Borrowed(&err.specifier))
799      }
800      FinalizeResolutionErrorKind::TypesNotFound(err) => {
801        Some(Cow::Borrowed(&err.0.code_specifier))
802      }
803      FinalizeResolutionErrorKind::UnsupportedDirImport(err) => {
804        Some(Cow::Borrowed(&err.dir_url))
805      }
806      FinalizeResolutionErrorKind::PackageSubpathResolve(err) => {
807        err.maybe_specifier()
808      }
809      FinalizeResolutionErrorKind::InvalidModuleSpecifierError(_)
810      | FinalizeResolutionErrorKind::UrlToFilePath(_) => None,
811    }
812  }
813
814  pub fn as_types_not_found(&self) -> Option<&TypesNotFoundError> {
815    match self.as_kind() {
816      FinalizeResolutionErrorKind::TypesNotFound(err) => Some(err),
817      FinalizeResolutionErrorKind::PackageSubpathResolve(err) => {
818        err.as_types_not_found()
819      }
820      FinalizeResolutionErrorKind::ModuleNotFound(_)
821      | FinalizeResolutionErrorKind::UnsupportedDirImport(_)
822      | FinalizeResolutionErrorKind::InvalidModuleSpecifierError(_)
823      | FinalizeResolutionErrorKind::UrlToFilePath(_) => None,
824    }
825  }
826}
827
828#[derive(Debug, Error, JsError)]
829pub enum FinalizeResolutionErrorKind {
830  #[class(inherit)]
831  #[error(transparent)]
832  InvalidModuleSpecifierError(#[from] InvalidModuleSpecifierError),
833  #[class(inherit)]
834  #[error(transparent)]
835  ModuleNotFound(#[from] ModuleNotFoundError),
836  #[class(inherit)]
837  #[error(transparent)]
838  TypesNotFound(#[from] TypesNotFoundError),
839  #[class(inherit)]
840  #[error(transparent)]
841  PackageSubpathResolve(#[from] PackageSubpathResolveError),
842  #[class(inherit)]
843  #[error(transparent)]
844  UnsupportedDirImport(#[from] UnsupportedDirImportError),
845  #[class(inherit)]
846  #[error(transparent)]
847  #[property("code" = self.code())]
848  UrlToFilePath(#[from] deno_path_util::UrlToFilePathError),
849}
850
851impl NodeJsErrorCoded for FinalizeResolutionErrorKind {
852  fn code(&self) -> NodeJsErrorCode {
853    match self {
854      FinalizeResolutionErrorKind::InvalidModuleSpecifierError(e) => e.code(),
855      FinalizeResolutionErrorKind::ModuleNotFound(e) => e.code(),
856      FinalizeResolutionErrorKind::TypesNotFound(e) => e.code(),
857      FinalizeResolutionErrorKind::PackageSubpathResolve(e) => e.code(),
858      FinalizeResolutionErrorKind::UnsupportedDirImport(e) => e.code(),
859      FinalizeResolutionErrorKind::UrlToFilePath(_) => {
860        NodeJsErrorCode::ERR_INVALID_FILE_URL_PATH
861      }
862    }
863  }
864}
865
866#[derive(Debug, Error, JsError)]
867#[class(generic)]
868#[error(
869  "[{}] Cannot find module '{}'{}{}",
870  self.code(),
871  specifier,
872  maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default(),
873  suggested_ext.as_ref().map(|m| format!("\nDid you mean to import with the \".{}\" extension?", m)).unwrap_or_default()
874)]
875#[property("code" = self.code())]
876pub struct ModuleNotFoundError {
877  pub specifier: UrlOrPath,
878  pub maybe_referrer: Option<UrlOrPath>,
879  pub suggested_ext: Option<&'static str>,
880}
881
882impl NodeJsErrorCoded for ModuleNotFoundError {
883  fn code(&self) -> NodeJsErrorCode {
884    NodeJsErrorCode::ERR_MODULE_NOT_FOUND
885  }
886}
887
888#[derive(Debug, Error, JsError)]
889#[class(generic)]
890#[error(
891  "[{}] Directory import '{}' is not supported resolving ES modules{}{}",
892  self.code(),
893  dir_url,
894  maybe_referrer.as_ref().map(|referrer| format!(" imported from '{}'", referrer)).unwrap_or_default(),
895  suggestion.as_ref().map(|suggestion| format!("\nDid you mean to import '{suggestion}'?")).unwrap_or_default(),
896)]
897#[property("code" = self.code())]
898pub struct UnsupportedDirImportError {
899  pub dir_url: UrlOrPath,
900  pub maybe_referrer: Option<UrlOrPath>,
901  pub suggestion: Option<String>,
902}
903
904impl NodeJsErrorCoded for UnsupportedDirImportError {
905  fn code(&self) -> NodeJsErrorCode {
906    NodeJsErrorCode::ERR_UNSUPPORTED_DIR_IMPORT
907  }
908}
909
910#[derive(Debug, JsError)]
911#[class(generic)]
912#[property("code" = self.code())]
913pub struct InvalidPackageTargetError {
914  pub pkg_json_path: PathBuf,
915  pub sub_path: String,
916  pub target: String,
917  pub is_import: bool,
918  pub maybe_referrer: Option<UrlOrPath>,
919}
920
921impl std::error::Error for InvalidPackageTargetError {}
922
923impl std::fmt::Display for InvalidPackageTargetError {
924  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
925    let rel_error = !self.is_import
926      && !self.target.is_empty()
927      && !self.target.starts_with("./");
928    f.write_char('[')?;
929    f.write_str(self.code().as_str())?;
930    f.write_char(']')?;
931
932    if self.sub_path == "." {
933      assert!(!self.is_import);
934      write!(
935        f,
936        " Invalid \"exports\" main target {} defined in the package config {}",
937        self.target,
938        self.pkg_json_path.display()
939      )?;
940    } else {
941      let ie = if self.is_import { "imports" } else { "exports" };
942      write!(
943        f,
944        " Invalid \"{}\" target {} defined for '{}' in the package config {}",
945        ie,
946        self.target,
947        self.sub_path,
948        self.pkg_json_path.display()
949      )?;
950    };
951
952    if let Some(referrer) = &self.maybe_referrer {
953      write!(f, " imported from '{}'", referrer)?;
954    }
955    if rel_error {
956      write!(f, "; target must start with \"./\"")?;
957    }
958    Ok(())
959  }
960}
961
962impl NodeJsErrorCoded for InvalidPackageTargetError {
963  fn code(&self) -> NodeJsErrorCode {
964    NodeJsErrorCode::ERR_INVALID_PACKAGE_TARGET
965  }
966}
967
968#[derive(Debug, JsError)]
969#[class(generic)]
970#[property("code" = self.code())]
971pub struct PackagePathNotExportedError {
972  pub pkg_json_path: PathBuf,
973  pub subpath: String,
974  pub maybe_referrer: Option<UrlOrPath>,
975  pub resolution_kind: NodeResolutionKind,
976}
977
978impl NodeJsErrorCoded for PackagePathNotExportedError {
979  fn code(&self) -> NodeJsErrorCode {
980    NodeJsErrorCode::ERR_PACKAGE_PATH_NOT_EXPORTED
981  }
982}
983
984impl std::error::Error for PackagePathNotExportedError {}
985
986impl std::fmt::Display for PackagePathNotExportedError {
987  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
988    f.write_char('[')?;
989    f.write_str(self.code().as_str())?;
990    f.write_char(']')?;
991
992    let types_msg = match self.resolution_kind {
993      NodeResolutionKind::Execution => String::new(),
994      NodeResolutionKind::Types => " for types".to_string(),
995    };
996    if self.subpath == "." {
997      write!(
998        f,
999        " No \"exports\" main defined{} in '{}'",
1000        types_msg,
1001        self.pkg_json_path.display()
1002      )?;
1003    } else {
1004      write!(
1005        f,
1006        " Package subpath '{}' is not defined{} by \"exports\" in '{}'",
1007        self.subpath,
1008        types_msg,
1009        self.pkg_json_path.display()
1010      )?;
1011    };
1012
1013    if let Some(referrer) = &self.maybe_referrer {
1014      write!(f, " imported from '{}'", referrer)?;
1015    }
1016    Ok(())
1017  }
1018}
1019
1020#[derive(Debug, Clone, Error, JsError)]
1021#[class(type)]
1022#[error(
1023  "[{}] Only file and data URLs are supported by the default ESM loader.{} Received protocol '{}'",
1024  self.code(),
1025  if cfg!(windows) && url_scheme.len() == 2 { " On Windows, absolute path must be valid file:// URLS."} else { "" },
1026  url_scheme
1027)]
1028#[property("code" = self.code())]
1029pub struct UnsupportedEsmUrlSchemeError {
1030  pub url_scheme: String,
1031}
1032
1033impl NodeJsErrorCoded for UnsupportedEsmUrlSchemeError {
1034  fn code(&self) -> NodeJsErrorCode {
1035    NodeJsErrorCode::ERR_UNSUPPORTED_ESM_URL_SCHEME
1036  }
1037}
1038
1039#[derive(Debug, Error, JsError)]
1040pub enum ResolvePkgJsonBinExportError {
1041  #[class(inherit)]
1042  #[error(transparent)]
1043  PkgJsonLoad(#[from] PackageJsonLoadError),
1044  #[class(generic)]
1045  #[error("Failed resolving binary export. '{}' did not exist", pkg_json_path.display())]
1046  MissingPkgJson { pkg_json_path: PathBuf },
1047  #[class(generic)]
1048  #[error("Failed resolving binary export. {message}")]
1049  InvalidBinProperty { message: String },
1050}
1051
1052#[derive(Debug, Error, JsError)]
1053pub enum ResolveBinaryCommandsError {
1054  #[class(inherit)]
1055  #[error(transparent)]
1056  PkgJsonLoad(#[from] PackageJsonLoadError),
1057  #[class(generic)]
1058  #[error("'{}' did not have a name", pkg_json_path.display())]
1059  MissingPkgJsonName { pkg_json_path: PathBuf },
1060}
1061
1062#[derive(Error, Debug, Clone, deno_error::JsError)]
1063#[class("NotFound")]
1064#[error("No such built-in module: node:{module_name}")]
1065#[property("code" = self.code())]
1066pub struct UnknownBuiltInNodeModuleError {
1067  /// Name of the invalid module.
1068  pub module_name: String,
1069}
1070
1071impl UnknownBuiltInNodeModuleError {
1072  pub fn maybe_specifier(&self) -> Option<Url> {
1073    Url::parse(&format!("node:{}", self.module_name)).ok()
1074  }
1075}
1076
1077impl NodeJsErrorCoded for UnknownBuiltInNodeModuleError {
1078  fn code(&self) -> NodeJsErrorCode {
1079    NodeJsErrorCode::ERR_UNKNOWN_BUILTIN_MODULE
1080  }
1081}
1082
1083#[cfg(test)]
1084mod test {
1085  use super::*;
1086
1087  #[test]
1088  fn types_resolution_package_path_not_exported() {
1089    let separator_char = if cfg!(windows) { '\\' } else { '/' };
1090    assert_eq!(
1091      PackagePathNotExportedError {
1092        pkg_json_path: PathBuf::from("test_path").join("package.json"),
1093        subpath: "./jsx-runtime".to_string(),
1094        maybe_referrer: None,
1095        resolution_kind: NodeResolutionKind::Types
1096      }
1097      .to_string(),
1098      format!(
1099        "[ERR_PACKAGE_PATH_NOT_EXPORTED] Package subpath './jsx-runtime' is not defined for types by \"exports\" in 'test_path{separator_char}package.json'"
1100      )
1101    );
1102    assert_eq!(
1103      PackagePathNotExportedError {
1104        pkg_json_path: PathBuf::from("test_path").join("package.json"),
1105        subpath: ".".to_string(),
1106        maybe_referrer: None,
1107        resolution_kind: NodeResolutionKind::Types
1108      }
1109      .to_string(),
1110      format!(
1111        "[ERR_PACKAGE_PATH_NOT_EXPORTED] No \"exports\" main defined for types in 'test_path{separator_char}package.json'"
1112      )
1113    );
1114  }
1115}