File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -8,7 +8,6 @@ publish = false
88rust-version.workspace = true
99
1010[dependencies ]
11- path-clean = { workspace = true }
1211rustc-hash = { workspace = true }
1312thiserror = { workspace = true }
1413vite_path = { workspace = true }
Original file line number Diff line number Diff line change @@ -9,6 +9,7 @@ rust-version.workspace = true
99[dependencies ]
1010bincode = { workspace = true }
1111diff-struct = { workspace = true }
12+ path-clean = { workspace = true }
1213ref-cast = { workspace = true }
1314serde = { workspace = true , features = [" derive" , " rc" ] }
1415thiserror = { workspace = true }
Original file line number Diff line number Diff line change @@ -200,6 +200,24 @@ impl AbsolutePath {
200200 pub fn ends_with < P : AsRef < Path > > ( & self , path : P ) -> bool {
201201 self . 0 . ends_with ( path. as_ref ( ) )
202202 }
203+
204+ /// Lexically normalizes the path by resolving `.` and `..` components
205+ /// without accessing the filesystem.
206+ ///
207+ /// **Symlink limitation**: Because this is purely lexical, it can produce
208+ /// incorrect results when symlinks are involved. For example, if
209+ /// `/a/link` is a symlink to `/x/y`, then cleaning `/a/link/../c`
210+ /// yields `/a/c` instead of the correct `/x/c`. Use
211+ /// [`std::fs::canonicalize`] when you need symlink-correct resolution.
212+ #[ must_use]
213+ pub fn clean ( & self ) -> AbsolutePathBuf {
214+ use path_clean:: PathClean as _;
215+
216+ let cleaned = self . 0 . clean ( ) ;
217+ // SAFETY: Lexical cleaning of an absolute path preserves absoluteness —
218+ // it only removes `.`/`..` components and redundant separators.
219+ unsafe { AbsolutePathBuf :: assume_absolute ( cleaned) }
220+ }
203221}
204222
205223/// An Error returned from [`AbsolutePath::strip_prefix`] if the stripped path is not a valid `RelativePath`
Original file line number Diff line number Diff line change @@ -62,6 +62,28 @@ impl RelativePath {
6262 relative_path_buf
6363 }
6464
65+ /// Lexically normalizes the path by resolving `..` components without
66+ /// accessing the filesystem. (`.` components are already stripped by
67+ /// [`RelativePathBuf::new`].)
68+ ///
69+ /// **Symlink limitation**: Because this is purely lexical, it can produce
70+ /// incorrect results when symlinks are involved. For example, if
71+ /// `a/link` is a symlink to `x/y`, then cleaning `a/link/../c`
72+ /// yields `a/c` instead of the correct `x/c`. Use
73+ /// [`std::fs::canonicalize`] when you need symlink-correct resolution.
74+ ///
75+ /// # Panics
76+ ///
77+ /// Panics if the cleaned path is no longer a valid relative path, which
78+ /// should never happen in practice.
79+ #[ must_use]
80+ pub fn clean ( & self ) -> RelativePathBuf {
81+ use path_clean:: PathClean as _;
82+
83+ let cleaned = self . as_path ( ) . clean ( ) ;
84+ RelativePathBuf :: new ( cleaned) . expect ( "cleaning a relative path preserves relativity" )
85+ }
86+
6587 /// Returns a path that, when joined onto `base`, yields `self`.
6688 ///
6789 /// If `base` is not a prefix of `self`, returns [`None`].
Original file line number Diff line number Diff line change @@ -23,7 +23,6 @@ fspy = { workspace = true }
2323futures-util = { workspace = true }
2424once_cell = { workspace = true }
2525owo-colors = { workspace = true }
26- path-clean = { workspace = true }
2726pty_terminal_test_client = { workspace = true }
2827rayon = { workspace = true }
2928rusqlite = { workspace = true , features = [" bundled" ] }
Original file line number Diff line number Diff line change @@ -210,10 +210,8 @@ pub async fn spawn_with_tracking(
210210 // like `packages/sub-pkg/../shared/dist/output.js` that won't match
211211 // workspace-root-relative negative globs without normalization.
212212 if !resolved_negatives. is_empty ( ) {
213- let cleaned = path_clean:: PathClean :: clean ( relative. as_path ( ) ) ;
214- if let Some ( cleaned_str) = cleaned. to_str ( )
215- && resolved_negatives. iter ( ) . any ( |neg| neg. is_match ( cleaned_str) )
216- {
213+ let cleaned = relative. clean ( ) ;
214+ if resolved_negatives. iter ( ) . any ( |neg| neg. is_match ( cleaned. as_str ( ) ) ) {
217215 return None ;
218216 }
219217 }
Original file line number Diff line number Diff line change @@ -16,14 +16,13 @@ petgraph = { workspace = true }
1616rustc-hash = { workspace = true }
1717serde = { workspace = true , features = [" derive" ] }
1818serde_json = { workspace = true }
19- path-clean = { workspace = true }
2019thiserror = { workspace = true }
2120tracing = { workspace = true }
22- wax = { workspace = true }
2321vite_graph_ser = { workspace = true }
2422vite_path = { workspace = true }
2523vite_str = { workspace = true }
2624vite_workspace = { workspace = true }
25+ wax = { workspace = true }
2726
2827[dev-dependencies ]
2928pretty_assertions = { workspace = true }
Original file line number Diff line number Diff line change @@ -195,16 +195,15 @@ fn resolve_glob_to_workspace_relative(
195195 workspace_root : & AbsolutePath ,
196196) -> Result < Str , ResolveTaskConfigError > {
197197 use cow_utils:: CowUtils as _;
198- use path_clean:: PathClean as _;
199198
200199 let glob = wax:: Glob :: new ( pattern) . map_err ( |source| ResolveTaskConfigError :: InvalidGlob {
201200 pattern : Str :: from ( pattern) ,
202201 source : Box :: new ( source) ,
203202 } ) ?;
204203 let ( invariant_prefix, variant) = glob. partition ( ) ;
205204
206- let joined = package_dir. as_path ( ) . join ( & invariant_prefix) . clean ( ) ;
207- let stripped = joined. strip_prefix ( workspace_root. as_path ( ) ) . map_err ( |_| {
205+ let joined = package_dir. join ( & invariant_prefix) . clean ( ) ;
206+ let stripped = joined. as_path ( ) . strip_prefix ( workspace_root. as_path ( ) ) . map_err ( |_| {
208207 ResolveTaskConfigError :: GlobOutsideWorkspace { pattern : Str :: from ( pattern) }
209208 } ) ?;
210209
@@ -383,7 +382,6 @@ mod tests {
383382
384383 use super :: * ;
385384
386- #[ expect( clippy:: disallowed_types, reason = "PathBuf needed for AbsolutePathBuf::new in tests" ) ]
387385 fn test_paths ( ) -> ( AbsolutePathBuf , AbsolutePathBuf ) {
388386 if cfg ! ( windows) {
389387 (
Original file line number Diff line number Diff line change @@ -9,7 +9,6 @@ rust-version.workspace = true
99
1010[dependencies ]
1111clap = { workspace = true , features = [" derive" ] }
12- path-clean = { workspace = true }
1312petgraph = { workspace = true , features = [" serde-1" ] }
1413rustc-hash = { workspace = true }
1514serde = { workspace = true , features = [" derive" ] }
You can’t perform that action at this time.
0 commit comments