@@ -8,15 +8,51 @@ type RelativePathOptions = {
88 includeRootInError ?: boolean ;
99} ;
1010
11+ function normalizeWindowsPathForComparison ( input : string ) : string {
12+ let normalized = path . win32 . normalize ( input ) ;
13+ if ( normalized . startsWith ( "\\\\?\\" ) ) {
14+ normalized = normalized . slice ( 4 ) ;
15+ if ( normalized . toUpperCase ( ) . startsWith ( "UNC\\" ) ) {
16+ normalized = `\\\\${ normalized . slice ( 4 ) } ` ;
17+ }
18+ }
19+ return normalized . replaceAll ( "/" , "\\" ) . toLowerCase ( ) ;
20+ }
21+
1122function toRelativePathUnderRoot ( params : {
1223 root : string ;
1324 candidate : string ;
1425 options ?: RelativePathOptions ;
1526} ) : string {
16- const rootResolved = path . resolve ( params . root ) ;
17- const resolvedCandidate = path . resolve (
18- resolveSandboxInputPath ( params . candidate , params . options ?. cwd ?? params . root ) ,
27+ const resolvedInput = resolveSandboxInputPath (
28+ params . candidate ,
29+ params . options ?. cwd ?? params . root ,
1930 ) ;
31+
32+ if ( process . platform === "win32" ) {
33+ const rootResolved = path . win32 . resolve ( params . root ) ;
34+ const resolvedCandidate = path . win32 . resolve ( resolvedInput ) ;
35+ const rootForCompare = normalizeWindowsPathForComparison ( rootResolved ) ;
36+ const targetForCompare = normalizeWindowsPathForComparison ( resolvedCandidate ) ;
37+ const relative = path . win32 . relative ( rootForCompare , targetForCompare ) ;
38+ if ( relative === "" || relative === "." ) {
39+ if ( params . options ?. allowRoot ) {
40+ return "" ;
41+ }
42+ const boundary = params . options ?. boundaryLabel ?? "workspace root" ;
43+ const suffix = params . options ?. includeRootInError ? ` (${ rootResolved } )` : "" ;
44+ throw new Error ( `Path escapes ${ boundary } ${ suffix } : ${ params . candidate } ` ) ;
45+ }
46+ if ( relative . startsWith ( ".." ) || path . win32 . isAbsolute ( relative ) ) {
47+ const boundary = params . options ?. boundaryLabel ?? "workspace root" ;
48+ const suffix = params . options ?. includeRootInError ? ` (${ rootResolved } )` : "" ;
49+ throw new Error ( `Path escapes ${ boundary } ${ suffix } : ${ params . candidate } ` ) ;
50+ }
51+ return relative ;
52+ }
53+
54+ const rootResolved = path . resolve ( params . root ) ;
55+ const resolvedCandidate = path . resolve ( resolvedInput ) ;
2056 const relative = path . relative ( rootResolved , resolvedCandidate ) ;
2157 if ( relative === "" || relative === "." ) {
2258 if ( params . options ?. allowRoot ) {
0 commit comments