Skip to content

Commit defe1aa

Browse files
branchseerclaude
andauthored
refactor: create separate error enums for vite_task and vite_workspace (#273)
Move error variants to their respective crates to improve modularity and reduce coupling. Each crate now has its own error type for errors it constructs, with vite_error wrapping them via TaskError and WorkspaceError variants. Changes: - Create vite_workspace::Error with workspace-specific variants (DuplicatedPackageName, PackageJsonNotFound, PackageOutsideWorkspace) - Create vite_task::Error with task-specific variants (DuplicatedTask, CycleDependencies, TaskNotFound, etc.) - Create vite_glob::Error to break circular dependency - Remove vite_error dependency from vite_workspace and vite_task - Add TaskError and WorkspaceError wrapper variants to vite_error::Error - Update CLI binding commands to convert between error types - Update test assertions to match new error structure - Remove unnecessary StripPrefixError implementation from vite_error - Replace manual From implementation with #[from] attribute for vite_glob::Error All leaf error types (vite_workspace::Error, vite_task::Error) are now independent and do not depend on vite_error, following proper dependency separation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 08a11f1 commit defe1aa

22 files changed

Lines changed: 265 additions & 100 deletions

File tree

Cargo.lock

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/vite_error/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ anyhow = { workspace = true }
1212
bincode = { workspace = true }
1313
bstr = { workspace = true }
1414
nix = { workspace = true }
15-
petgraph = { workspace = true }
1615
rusqlite = { workspace = true }
1716
semver = { workspace = true }
1817
serde_json = { workspace = true }
@@ -21,6 +20,8 @@ thiserror = { workspace = true }
2120
tokio = { workspace = true }
2221
vite_path = { workspace = true }
2322
vite_str = { workspace = true }
23+
vite_task = { workspace = true }
24+
vite_workspace = { workspace = true }
2425
wax = { workspace = true }
2526

2627
[target.'cfg(target_os = "windows")'.dependencies]

crates/vite_error/src/lib.rs

Lines changed: 6 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
use std::{ffi::OsString, path::Path, sync::Arc};
22

3-
use petgraph::graph::NodeIndex;
43
use thiserror::Error;
5-
use vite_path::{
6-
AbsolutePath, AbsolutePathBuf, RelativePathBuf,
7-
absolute::StripPrefixError,
8-
relative::{FromPathError, InvalidPathDataError},
9-
};
4+
use vite_path::{AbsolutePath, AbsolutePathBuf, relative::FromPathError};
105
use vite_str::Str;
116

127
#[derive(Error, Debug)]
@@ -59,41 +54,14 @@ pub enum Error {
5954
#[error(transparent)]
6055
WaxWalk(#[from] wax::WalkError),
6156

62-
#[error("Duplicated task name: {0}")]
63-
DuplicatedTask(Str),
64-
65-
#[error("Duplicated package name: {name} at {path1} and {path2}")]
66-
DuplicatedPackageName { name: Str, path1: RelativePathBuf, path2: RelativePathBuf },
67-
68-
#[error("Circular dependency found : {0:?}")]
69-
CycleDependencies(petgraph::algo::Cycle<NodeIndex>),
70-
71-
#[error("The package.json name is empty at {0:?}/package.json")]
72-
EmptyPackageName(AbsolutePathBuf),
73-
74-
#[error("Package {0} not found in workspace")]
75-
PackageNotFound(Str),
76-
77-
#[error("The package.json file is not found at {0:?}")]
78-
PackageJsonNotFound(AbsolutePathBuf),
79-
80-
#[error("Task '{task_request}' not found in workspace")]
81-
TaskNotFound { task_request: Str },
82-
83-
#[error("Dependency Task '{name}' not found in package located at {package_path}")]
84-
TaskDependencyNotFound { name: Str, package_path: RelativePathBuf },
85-
86-
#[error("{task_request} should not contain multiple '#'")]
87-
AmbiguousTaskRequest { task_request: Str },
88-
89-
#[error("Only one task request is allowed when running in implicit mode: {0}")]
90-
OnlyOneTaskRequest(Str),
57+
#[error(transparent)]
58+
SerdeYml(#[from] serde_yml::Error),
9159

92-
#[error("Recursive run is not allowed when task name contains '#': {0}")]
93-
RecursiveRunWithScope(Str),
60+
#[error(transparent)]
61+
TaskError(#[from] vite_task::Error),
9462

9563
#[error(transparent)]
96-
SerdeYml(#[from] serde_yml::Error),
64+
WorkspaceError(#[from] vite_workspace::Error),
9765

9866
#[error("Lint failed, reason: {reason}")]
9967
LintFailed { status: Str, reason: Str },
@@ -116,17 +84,9 @@ pub enum Error {
11684
#[error("Resolve universal vite config failed")]
11785
ResolveUniversalViteConfigFailed { status: Str, reason: Str },
11886

119-
#[error(
120-
"The stripped path ({stripped_path:?}) is not a valid relative path because: {invalid_path_data_error}"
121-
)]
122-
StripPath { stripped_path: Box<Path>, invalid_path_data_error: InvalidPathDataError },
123-
12487
#[error("The path ({path:?}) is not a valid relative path because: {reason}")]
12588
InvalidRelativePath { path: Box<Path>, reason: FromPathError },
12689

127-
#[error("The package at {package_path:?} is outside the workspace at {workspace_root:?}")]
128-
PackageOutsideWorkspace { package_path: AbsolutePathBuf, workspace_root: AbsolutePathBuf },
129-
13090
#[error("Unsupported package manager: {0}")]
13191
UnsupportedPackageManager(Str),
13292

@@ -168,12 +128,3 @@ pub enum Error {
168128
#[error(transparent)]
169129
Anyhow(#[from] anyhow::Error),
170130
}
171-
172-
impl From<StripPrefixError<'_>> for Error {
173-
fn from(value: StripPrefixError<'_>) -> Self {
174-
Self::StripPath {
175-
stripped_path: Box::from(value.stripped_path),
176-
invalid_path_data_error: value.invalid_path_data_error,
177-
}
178-
}
179-
}

crates/vite_glob/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ publish = false
88
rust-version.workspace = true
99

1010
[dependencies]
11-
vite_error = { workspace = true }
11+
thiserror = { workspace = true }
1212
wax = { workspace = true }
1313

1414
[dev-dependencies]

crates/vite_glob/src/error.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use wax;
2+
3+
#[derive(Debug, thiserror::Error)]
4+
pub enum Error {
5+
#[error(transparent)]
6+
WaxBuild(#[from] wax::BuildError),
7+
}

crates/vite_glob/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
mod error;
2+
13
use std::path::Path;
24

3-
use vite_error::Error;
5+
pub use error::Error;
46
use wax::{Glob, Pattern};
57

68
/// If there are no negated patterns, it will follow the first match wins semantics.

crates/vite_install/src/package_manager.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ mod tests {
616616
fs::create_dir_all(&root_dir).unwrap();
617617
let found = find_package_root(&root_dir);
618618
let err = found.unwrap_err();
619-
assert!(matches!(err, Error::PackageJsonNotFound(_)));
619+
assert!(matches!(err, vite_workspace::Error::PackageJsonNotFound(_)));
620620
}
621621

622622
#[test]
@@ -683,7 +683,7 @@ mod tests {
683683
// Should return PackageJsonNotFound error if no package.json found
684684
let found = find_workspace_root(&nested_dir);
685685
let err = found.unwrap_err();
686-
assert!(matches!(err, Error::PackageJsonNotFound(_)));
686+
assert!(matches!(err, vite_workspace::Error::PackageJsonNotFound(_)));
687687
}
688688

689689
#[test]

crates/vite_task/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ sha2 = { workspace = true }
3333
shell-escape = { workspace = true }
3434
supports-color = { workspace = true }
3535
tempfile = { workspace = true }
36+
thiserror = { workspace = true }
3637
tokio = { workspace = true, features = ["rt-multi-thread", "io-std", "macros"] }
3738
tracing = { workspace = true }
3839
twox-hash = { workspace = true }
3940
uuid = { workspace = true, features = ["v4"] }
40-
vite_error = { workspace = true }
4141
vite_glob = { workspace = true }
4242
vite_path = { workspace = true }
4343
vite_str = { workspace = true }

crates/vite_task/src/config/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ use diff::Diff;
1616
use serde::{Deserialize, Serialize};
1717
pub use task_command::*;
1818
pub use task_graph_builder::*;
19-
use vite_error::Error;
2019
use vite_path::{self, RelativePath, RelativePathBuf};
2120
use vite_str::Str;
2221
pub use workspace::*;
2322

2423
use crate::{
24+
Error,
2525
cmd::TaskParsedCommand,
2626
collections::{HashMap, HashSet},
2727
config::name::TaskName,

crates/vite_task/src/error.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
use std::{ffi::OsString, io, path::Path, sync::Arc};
2+
3+
use petgraph::algo::Cycle;
4+
use vite_path::{
5+
AbsolutePath, RelativePathBuf,
6+
absolute::StripPrefixError,
7+
relative::{FromPathError, InvalidPathDataError},
8+
};
9+
use vite_str::Str;
10+
11+
#[derive(Debug, thiserror::Error)]
12+
pub enum Error {
13+
// Task-specific errors (constructed in vite_task only)
14+
#[error("Duplicate package name `{name}` found at `{path1}` and `{path2}`")]
15+
DuplicatedPackageName { name: Str, path1: RelativePathBuf, path2: RelativePathBuf },
16+
17+
#[error("Package not found in workspace: `{0}`")]
18+
PackageNotFound(Str),
19+
20+
#[error("Duplicate task: `{0}`")]
21+
DuplicatedTask(Str),
22+
23+
#[error("Cycle dependencies detected: {0:?}")]
24+
CycleDependencies(Cycle<petgraph::graph::NodeIndex>),
25+
26+
#[error("Task not found: `{task_request}`")]
27+
TaskNotFound { task_request: Str },
28+
29+
#[error("Task dependency `{name}` not found in package at `{package_path}`")]
30+
TaskDependencyNotFound { name: Str, package_path: RelativePathBuf },
31+
32+
#[error("Ambiguous task request: `{task_request}` (contains multiple '#')")]
33+
AmbiguousTaskRequest { task_request: Str },
34+
35+
#[error("Only one task is allowed in implicit mode (got: `{0}`)")]
36+
OnlyOneTaskRequest(Str),
37+
38+
#[error("Recursive run with scoped task name is not supported: `{0}`")]
39+
RecursiveRunWithScope(Str),
40+
41+
// Errors used by vite_task but not task-specific
42+
#[error("Unrecognized db version: {0}")]
43+
UnrecognizedDbVersion(u32),
44+
45+
#[error("Env value is not valid unicode: {key} = {value:?}")]
46+
EnvValueIsNotValidUnicode { key: Str, value: OsString },
47+
48+
#[error(
49+
"The stripped path ({stripped_path:?}) is not a valid relative path because: {invalid_path_data_error}"
50+
)]
51+
StripPath { stripped_path: Box<Path>, invalid_path_data_error: InvalidPathDataError },
52+
53+
#[error("The path ({path:?}) is not a valid relative path because: {reason}")]
54+
InvalidRelativePath { path: Box<Path>, reason: FromPathError },
55+
56+
#[error("IO error: {err} at {path:?}")]
57+
IoWithPath { err: io::Error, path: Arc<AbsolutePath> },
58+
59+
#[cfg(unix)]
60+
#[error("Unsupported file type: {0:?}")]
61+
UnsupportedFileType(nix::dir::Type),
62+
63+
#[cfg(windows)]
64+
#[error("Unsupported file type: {0:?}")]
65+
UnsupportedFileType(std::fs::FileType),
66+
67+
// External library errors
68+
#[error(transparent)]
69+
Io(#[from] io::Error),
70+
71+
#[error(transparent)]
72+
JoinPathsError(#[from] std::env::JoinPathsError),
73+
74+
#[error(transparent)]
75+
WaxBuild(#[from] wax::BuildError),
76+
77+
#[error(transparent)]
78+
WaxWalk(#[from] wax::WalkError),
79+
80+
#[error(transparent)]
81+
Utf8Error(#[from] bstr::Utf8Error),
82+
83+
#[error(transparent)]
84+
Serde(#[from] serde_json::Error),
85+
86+
#[error(transparent)]
87+
Sqlite(#[from] rusqlite::Error),
88+
89+
#[error(transparent)]
90+
BincodeEncode(#[from] bincode::error::EncodeError),
91+
92+
#[error(transparent)]
93+
BincodeDecode(#[from] bincode::error::DecodeError),
94+
95+
#[error(transparent)]
96+
Anyhow(#[from] anyhow::Error),
97+
98+
#[error(transparent)]
99+
Glob(#[from] vite_glob::Error),
100+
101+
#[error(transparent)]
102+
Workspace(#[from] vite_workspace::Error),
103+
104+
#[cfg(unix)]
105+
#[error(transparent)]
106+
Nix(#[from] nix::Error),
107+
}
108+
109+
impl From<StripPrefixError<'_>> for Error {
110+
fn from(value: StripPrefixError<'_>) -> Self {
111+
Self::StripPath {
112+
stripped_path: Box::from(value.stripped_path),
113+
invalid_path_data_error: value.invalid_path_data_error,
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)