1use futures::channel::mpsc;
2use kdl::{KdlDocument, KdlNode};
3use miette::Diagnostic;
4use thiserror::Error;
5
6use crate::{NpmPackageLock, NpmPackageLockEntry};
7
8#[allow(clippy::large_enum_variant)]
9#[derive(Debug, Error, Diagnostic)]
10pub enum NodeMaintainerError {
11 #[error("Unsupported resolved URL scheme")]
13 #[diagnostic(code(node_maintainer::kdl::unsupported_url_scheme), url(docsrs))]
14 UnsupportedScheme(String),
15
16 #[error("Failed to parse a resolved URL while parsing lockfile: {0}")]
18 #[diagnostic(code(node_maintainer::kdl::url_parse_error), url(docsrs))]
19 UrlParseError(String, #[source] url::ParseError),
20
21 #[error("Failed to parse a Semver string.")]
23 #[diagnostic(code(node_maintainer::kdl::semver_parse_error), url(docsrs))]
24 SemverParseError(#[from] node_semver::SemverError),
25
26 #[error("Missing version for NPM package entry in lockfile.")]
28 #[diagnostic(code(node_maintainer::kdl::missing_version), url(docsrs))]
29 MissingVersion,
30
31 #[error("Missing version for NPM package entry in lockfile.")]
33 #[diagnostic(code(node_maintainer::kdl::missing_version), url(docsrs))]
34 MissingResolution,
35
36 #[error(transparent)]
38 #[diagnostic(code(node_maintainer::kdl::integrity_parse_error), url(docsrs))]
39 IntegrityParseError(#[from] ssri::Error),
40
41 #[error("Failed to parse an integrity value while loading lockfile node:\n{0}")]
43 #[diagnostic(code(node_maintainer::kdl::integrity_parse_error), url(docsrs))]
44 KdlLockfileIntegrityParseError(KdlNode, #[source] ssri::Error),
45
46 #[error("Missing package node name:\n{0}")]
48 #[diagnostic(code(node_maintainer::kdl::missing_node_name), url(docsrs))]
49 KdlLockMissingName(KdlNode),
50
51 #[error("Missing package name:\n{0:#?}")]
53 #[diagnostic(code(node_maintainer::npm::missing_name), url(docsrs))]
54 NpmLockMissingName(Box<NpmPackageLockEntry>),
55
56 #[error("Failed to parse an integrity value while loading lockfile node:\n{0:#?}")]
58 #[diagnostic(code(node_maintainer::npm::integrity_parse_error), url(docsrs))]
59 NpmLockfileIntegrityParseError(Box<NpmPackageLockEntry>, #[source] ssri::Error),
60
61 #[error("Unsupported NPM Package Lock version: {0}")]
63 #[diagnostic(
64 code(node_maintainer::npm::unsupported_package_lock_Version),
65 url(docsrs)
66 )]
67 NpmUnsupportedPackageLockVersion(u64),
68
69 #[error("No root node in KDL lockfile.")]
71 #[diagnostic(code(node_maintainer::kdl::missing_root), url(docsrs))]
72 KdlLockMissingRoot(KdlDocument),
73
74 #[error("No root package in NPM lockfile.")]
76 #[diagnostic(code(node_maintainer::npm::missing_root), url(docsrs))]
77 NpmLockMissingRoot(NpmPackageLock),
78
79 #[error(transparent)]
81 #[diagnostic(code(node_maintainer::kdl::parse_error), url(docsrs))]
82 KdlParseError(#[from] kdl::KdlError),
83
84 #[error("Invalid lockfile version format.")]
85 #[diagnostic(code(node_maintainer::kdl::invalid_lockfile_version), url(docsrs))]
86 InvalidLockfileVersion,
87
88 #[cfg(target_arch = "wasm32")]
90 #[error(transparent)]
91 #[diagnostic(code(node_maintainer::serde_wasm_bindgen::error), url(docsrs))]
92 SerdeWasmBindgenError(#[from] serde_wasm_bindgen::Error),
93
94 #[error(transparent)]
96 #[diagnostic(transparent)]
97 PackageSpecError(#[from] oro_package_spec::PackageSpecError),
98
99 #[error("{0}")]
101 #[diagnostic(code(node_maintainer::io_error), url(docsrs))]
102 IoError(String, #[source] std::io::Error),
103
104 #[cfg(not(target_arch = "wasm32"))]
105 #[error(transparent)]
107 #[diagnostic(transparent)]
108 NassunError(#[from] nassun::NassunError),
109
110 #[cfg(windows)]
124 #[error("Failed to create either a symlink or junction from {} to {}.", .0.display(), .1.display())]
125 #[diagnostic(
126 code(node_maintainer::junctions_not_supported),
127 url(docsrs),
128 help("The isolated linker requires your Windows user to either be able to create symlinks, which requires Administrator privileges, or create junctions, which require an NTFS filesystem, among other things. If you see this message, you might consider switching to the 'hoisted' linker instead.")
129 )]
130 JunctionsNotSupported(
131 std::path::PathBuf,
132 std::path::PathBuf,
133 #[source] std::io::Error,
134 ),
135
136 #[cfg(target_arch = "wasm32")]
137 #[error(transparent)]
139 #[diagnostic(transparent)]
140 NassunError(#[from] nassun::error::NassunError),
141
142 #[error(transparent)]
144 #[diagnostic(code(node_maintainer::serde_json_error), url(docsrs))]
145 SerdeJsonError(#[from] serde_json::Error),
146
147 #[error("{0}")]
149 #[diagnostic(code(node_maintainer::miscellaneous_error), url(docsrs))]
150 MiscError(String),
151
152 #[error("Failed to send data through mpsc channel.")]
155 #[diagnostic(code(node_maintainer::mpsc_error), url(docsrs))]
156 TrySendError,
157
158 #[error("{0}")]
160 #[diagnostic(code(node_maintainer::graph_error), url(docsrs))]
161 GraphValidationError(String),
162
163 #[cfg(not(target_arch = "wasm32"))]
166 #[error(transparent)]
167 #[diagnostic(code(node_maintainer::walkdir_error), url(docsrs))]
168 WalkDirError(#[from] walkdir::Error),
169
170 #[cfg(not(target_arch = "wasm32"))]
173 #[error("Failed to read manifest during build step, at {}", .0.display())]
174 #[diagnostic(code(node_maintainer::build_manifest_read_error), url(docsrs))]
175 BuildManifestReadError(std::path::PathBuf, #[source] std::io::Error),
176
177 #[cfg(not(target_arch = "wasm32"))]
180 #[error(transparent)]
181 #[diagnostic(transparent)]
182 OroScriptError(#[from] oro_script::OroScriptError),
183
184 #[error("Locked file was requested, but a new dependency tree was resolved that would cause changes to the lockfile. The contents of `package.json` may have changed since the last time the lockfile was updated.")]
194 #[diagnostic(
195 code(node_maintainer::lockfile_mismatch),
196 url(docsrs),
197 help("Did you modify package.json by hand?")
198 )]
199 LockfileMismatch,
200}
201
202impl<T> From<mpsc::TrySendError<T>> for NodeMaintainerError {
203 fn from(_: mpsc::TrySendError<T>) -> Self {
204 NodeMaintainerError::TrySendError
205 }
206}
207
208pub trait IoContext {
209 type T;
210
211 fn io_context(self, context: impl FnOnce() -> String) -> Result<Self::T, NodeMaintainerError>;
212}
213
214impl<T> IoContext for Result<T, std::io::Error> {
215 type T = T;
216
217 fn io_context(self, context: impl FnOnce() -> String) -> Result<Self::T, NodeMaintainerError> {
218 self.map_err(|e| NodeMaintainerError::IoError(context(), e))
219 }
220}