1- import path from 'node:path' ;
1+ import path , { posix } from 'node:path' ;
22import { type Options as FdirOptions , fdir } from 'fdir' ;
33import picomatch from 'picomatch' ;
44
@@ -14,18 +14,34 @@ export interface GlobOptions {
1414 onlyFiles ?: boolean ;
1515}
1616
17+ let root : string ;
18+
1719function normalizePattern ( pattern : string , expandDirectories : boolean , cwd : string ) {
1820 let result : string = pattern ;
1921 if ( pattern . endsWith ( '/' ) ) {
2022 result = pattern . slice ( 0 , - 1 ) ;
2123 }
2224 // using a directory as entry should match all files inside it
23- if ( ! pattern . endsWith ( '*' ) && expandDirectories ) {
25+ if ( ! result . endsWith ( '*' ) && expandDirectories ) {
2426 result += '/**' ;
2527 }
26- if ( result . startsWith ( cwd . replace ( / \\ / g, '/' ) ) ) {
27- result = path . relative ( cwd , result ) . replace ( / \\ / g, '/' ) ;
28+
29+ if ( result . startsWith ( cwd ) ) {
30+ return posix . relative ( cwd , result ) ;
31+ }
32+
33+ if ( result . startsWith ( './' ) ) {
34+ result = result . slice ( 2 ) ;
35+ }
36+
37+ const parentDirectoryMatch = / ^ ( \/ ? \. \. ) + / . exec ( result ) ;
38+ if ( parentDirectoryMatch ?. [ 0 ] ) {
39+ const potentialRoot = posix . join ( cwd , parentDirectoryMatch [ 0 ] ) ;
40+ if ( root . length > potentialRoot . length ) {
41+ root = potentialRoot ;
42+ }
2843 }
44+
2945 return result ;
3046}
3147
@@ -49,13 +65,24 @@ function processPatterns({ patterns, ignore = [], expandDirectories = true }: Gl
4965 return { match : matchPatterns , ignore : ignorePatterns } ;
5066}
5167
52- function processPath ( path : string , cwd : string , absolute ?: boolean ) {
53- const pathWithoutTrailingSlash = path . endsWith ( '/' ) ? path . slice ( 0 , - 1 ) : path ;
68+ // TODO: this is slow, find a better way to do this
69+ function getRelativePath ( path : string , cwd : string ) {
70+ return posix . relative ( cwd , `${ root } /${ path } ` ) ;
71+ }
72+
73+ function processPath ( path : string , cwd : string , isDirectory : boolean , absolute ?: boolean ) {
74+ const relativePath = absolute ? path . slice ( root . length + 1 ) : path ;
75+ if ( root === cwd ) {
76+ return isDirectory ? relativePath . slice ( 0 , - 1 ) : relativePath ;
77+ }
5478
55- return absolute ? pathWithoutTrailingSlash . slice ( cwd . length + 1 ) : pathWithoutTrailingSlash ;
79+ return getRelativePath ( relativePath , cwd ) ;
5680}
5781
58- function getFdirBuilder ( options : GlobOptions , cwd : string ) {
82+ function crawl ( options : GlobOptions , cwd : string , sync : false ) : Promise < string [ ] > ;
83+ function crawl ( options : GlobOptions , cwd : string , sync : true ) : string [ ] ;
84+ function crawl ( options : GlobOptions , cwd : string , sync : boolean ) {
85+ root = cwd ;
5986 const processed = processPatterns ( options , cwd ) ;
6087
6188 const matcher = picomatch ( processed . match , {
@@ -69,8 +96,8 @@ function getFdirBuilder(options: GlobOptions, cwd: string) {
6996
7097 const fdirOptions : Partial < FdirOptions > = {
7198 // use relative paths in the matcher
72- filters : [ p => matcher ( processPath ( p , cwd , options . absolute ) ) ] ,
73- exclude : ( _ , p ) => exclude ( p . slice ( cwd . length + 1 ) . slice ( 0 , - 1 ) ) ,
99+ filters : [ ( p , isDirectory ) => matcher ( processPath ( p , cwd , isDirectory , options . absolute ) ) ] ,
100+ exclude : ( _ , p ) => exclude ( processPath ( p , cwd , true , true ) ) ,
74101 pathSeparator : '/' ,
75102 relativePaths : true
76103 } ;
@@ -92,7 +119,15 @@ function getFdirBuilder(options: GlobOptions, cwd: string) {
92119 fdirOptions . includeDirs = true ;
93120 }
94121
95- return new fdir ( fdirOptions ) ;
122+ const api = new fdir ( fdirOptions ) . crawl ( root ) ;
123+
124+ if ( cwd === root || options . absolute ) {
125+ return sync ? api . sync ( ) : api . withPromise ( ) ;
126+ }
127+
128+ return sync
129+ ? api . sync ( ) . map ( p => getRelativePath ( p , cwd ) )
130+ : api . withPromise ( ) . then ( paths => paths . map ( p => getRelativePath ( p , cwd ) ) ) ;
96131}
97132
98133export function glob ( patterns : string [ ] , options ?: Omit < GlobOptions , 'patterns' > ) : Promise < string [ ] > ;
@@ -103,9 +138,9 @@ export async function glob(patternsOrOptions: string[] | GlobOptions, options?:
103138 }
104139
105140 const opts = Array . isArray ( patternsOrOptions ) ? { ...options , patterns : patternsOrOptions } : patternsOrOptions ;
106- const cwd = opts . cwd ? path . resolve ( opts . cwd ) : process . cwd ( ) ;
141+ const cwd = opts . cwd ? path . resolve ( opts . cwd ) . replace ( / \\ / g , '/' ) : process . cwd ( ) . replace ( / \\ / g , '/' ) ;
107142
108- return getFdirBuilder ( opts , cwd ) . crawl ( cwd ) . withPromise ( ) ;
143+ return crawl ( opts , cwd , false ) ;
109144}
110145
111146export function globSync ( patterns : string [ ] , options ?: Omit < GlobOptions , 'patterns' > ) : string [ ] ;
@@ -116,7 +151,7 @@ export function globSync(patternsOrOptions: string[] | GlobOptions, options?: Gl
116151 }
117152
118153 const opts = Array . isArray ( patternsOrOptions ) ? { ...options , patterns : patternsOrOptions } : patternsOrOptions ;
119- const cwd = opts . cwd ? path . resolve ( opts . cwd ) : process . cwd ( ) ;
154+ const cwd = opts . cwd ? path . resolve ( opts . cwd ) . replace ( / \\ / g , '/' ) : process . cwd ( ) . replace ( / \\ / g , '/' ) ;
120155
121- return getFdirBuilder ( opts , cwd ) . crawl ( cwd ) . sync ( ) ;
156+ return crawl ( opts , cwd , true ) ;
122157}
0 commit comments