@@ -21,73 +21,136 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
2121} ) : target , mod ) ) ;
2222
2323//#endregion
24- const path = __toESM ( require ( "path" ) ) ;
25- const fdir = __toESM ( require ( "fdir" ) ) ;
26- const picomatch = __toESM ( require ( "picomatch" ) ) ;
24+ let fs = require ( "fs" ) ;
25+ fs = __toESM ( fs ) ;
26+ let path = require ( "path" ) ;
27+ path = __toESM ( path ) ;
28+ let url = require ( "url" ) ;
29+ url = __toESM ( url ) ;
30+ let fdir = require ( "fdir" ) ;
31+ fdir = __toESM ( fdir ) ;
32+ let picomatch = require ( "picomatch" ) ;
33+ picomatch = __toESM ( picomatch ) ;
2734
2835//#region src/utils.ts
36+ const isReadonlyArray = Array . isArray ;
37+ const isWin = process . platform === "win32" ;
2938const ONLY_PARENT_DIRECTORIES = / ^ ( \/ ? \. \. ) + $ / ;
30- function getPartialMatcher ( patterns , options ) {
39+ function getPartialMatcher ( patterns , options = { } ) {
3140 const patternsCount = patterns . length ;
3241 const patternsParts = Array ( patternsCount ) ;
33- const regexes = Array ( patternsCount ) ;
42+ const matchers = Array ( patternsCount ) ;
43+ const globstarEnabled = ! options . noglobstar ;
3444 for ( let i = 0 ; i < patternsCount ; i ++ ) {
3545 const parts = splitPattern ( patterns [ i ] ) ;
3646 patternsParts [ i ] = parts ;
3747 const partsCount = parts . length ;
38- const partRegexes = Array ( partsCount ) ;
39- for ( let j = 0 ; j < partsCount ; j ++ ) partRegexes [ j ] = picomatch . default . makeRe ( parts [ j ] , options ) ;
40- regexes [ i ] = partRegexes ;
48+ const partMatchers = Array ( partsCount ) ;
49+ for ( let j = 0 ; j < partsCount ; j ++ ) partMatchers [ j ] = ( 0 , picomatch . default ) ( parts [ j ] , options ) ;
50+ matchers [ i ] = partMatchers ;
4151 }
4252 return ( input ) => {
4353 const inputParts = input . split ( "/" ) ;
4454 if ( inputParts [ 0 ] === ".." && ONLY_PARENT_DIRECTORIES . test ( input ) ) return true ;
4555 for ( let i = 0 ; i < patterns . length ; i ++ ) {
4656 const patternParts = patternsParts [ i ] ;
47- const regex = regexes [ i ] ;
57+ const matcher = matchers [ i ] ;
4858 const inputPatternCount = inputParts . length ;
4959 const minParts = Math . min ( inputPatternCount , patternParts . length ) ;
5060 let j = 0 ;
5161 while ( j < minParts ) {
5262 const part = patternParts [ j ] ;
5363 if ( part . includes ( "/" ) ) return true ;
54- const match = regex [ j ] . test ( inputParts [ j ] ) ;
64+ const match = matcher [ j ] ( inputParts [ j ] ) ;
5565 if ( ! match ) break ;
56- if ( part === "**" ) return true ;
66+ if ( globstarEnabled && part === "**" ) return true ;
5767 j ++ ;
5868 }
5969 if ( j === inputPatternCount ) return true ;
6070 }
6171 return false ;
6272 } ;
6373}
74+ /* node:coverage ignore next 2 */
75+ const WIN32_ROOT_DIR = / ^ [ A - Z ] : \/ $ / i;
76+ const isRoot = isWin ? ( p ) => WIN32_ROOT_DIR . test ( p ) : ( p ) => p === "/" ;
77+ function buildFormat ( cwd , root , absolute ) {
78+ if ( cwd === root || root . startsWith ( `${ cwd } /` ) ) {
79+ if ( absolute ) {
80+ const start = isRoot ( cwd ) ? cwd . length : cwd . length + 1 ;
81+ return ( p , isDir ) => p . slice ( start , isDir ? - 1 : void 0 ) || "." ;
82+ }
83+ const prefix = root . slice ( cwd . length + 1 ) ;
84+ if ( prefix ) return ( p , isDir ) => {
85+ if ( p === "." ) return prefix ;
86+ const result = `${ prefix } /${ p } ` ;
87+ return isDir ? result . slice ( 0 , - 1 ) : result ;
88+ } ;
89+ return ( p , isDir ) => isDir && p !== "." ? p . slice ( 0 , - 1 ) : p ;
90+ }
91+ if ( absolute ) return ( p ) => path . posix . relative ( cwd , p ) || "." ;
92+ return ( p ) => path . posix . relative ( cwd , `${ root } /${ p } ` ) || "." ;
93+ }
94+ function buildRelative ( cwd , root ) {
95+ if ( root . startsWith ( `${ cwd } /` ) ) {
96+ const prefix = root . slice ( cwd . length + 1 ) ;
97+ return ( p ) => `${ prefix } /${ p } ` ;
98+ }
99+ return ( p ) => {
100+ const result = path . posix . relative ( cwd , `${ root } /${ p } ` ) ;
101+ if ( p . endsWith ( "/" ) && result !== "" ) return `${ result } /` ;
102+ return result || "." ;
103+ } ;
104+ }
64105const splitPatternOptions = { parts : true } ;
65106function splitPattern ( path$2 ) {
66107 var _result$parts ;
67108 const result = picomatch . default . scan ( path$2 , splitPatternOptions ) ;
68109 return ( ( _result$parts = result . parts ) === null || _result$parts === void 0 ? void 0 : _result$parts . length ) ? result . parts : [ path$2 ] ;
69110}
70- const isWin = process . platform === "win32" ;
71111const ESCAPED_WIN32_BACKSLASHES = / \\ (? ! [ ( ) [ \] { } ! + @ ] ) / g;
72112function convertPosixPathToPattern ( path$2 ) {
73113 return escapePosixPath ( path$2 ) ;
74114}
75115function convertWin32PathToPattern ( path$2 ) {
76116 return escapeWin32Path ( path$2 ) . replace ( ESCAPED_WIN32_BACKSLASHES , "/" ) ;
77117}
118+ /**
119+ * Converts a path to a pattern depending on the platform.
120+ * Identical to {@link escapePath} on POSIX systems.
121+ * @see {@link https://superchupu.dev/tinyglobby/documentation#convertPathToPattern }
122+ */
123+ /* node:coverage ignore next 3 */
78124const convertPathToPattern = isWin ? convertWin32PathToPattern : convertPosixPathToPattern ;
79125const POSIX_UNESCAPED_GLOB_SYMBOLS = / (?< ! \\ ) ( [ ( ) [ \] { } * ? | ] | ^ ! | [ ! + @ ] (? = \( ) | \\ (? ! [ ( ) [ \] { } ! * + ? @ | ] ) ) / g;
80126const WIN32_UNESCAPED_GLOB_SYMBOLS = / (?< ! \\ ) ( [ ( ) [ \] { } ] | ^ ! | [ ! + @ ] (? = \( ) ) / g;
81127const escapePosixPath = ( path$2 ) => path$2 . replace ( POSIX_UNESCAPED_GLOB_SYMBOLS , "\\$&" ) ;
82128const escapeWin32Path = ( path$2 ) => path$2 . replace ( WIN32_UNESCAPED_GLOB_SYMBOLS , "\\$&" ) ;
129+ /**
130+ * Escapes a path's special characters depending on the platform.
131+ * @see {@link https://superchupu.dev/tinyglobby/documentation#escapePath }
132+ */
133+ /* node:coverage ignore next */
83134const escapePath = isWin ? escapeWin32Path : escapePosixPath ;
135+ /**
136+ * Checks if a pattern has dynamic parts.
137+ *
138+ * Has a few minor differences with [`fast-glob`](https://github.com/mrmlnc/fast-glob) for better accuracy:
139+ *
140+ * - Doesn't necessarily return `false` on patterns that include `\`.
141+ * - Returns `true` if the pattern includes parentheses, regardless of them representing one single pattern or not.
142+ * - Returns `true` for unfinished glob extensions i.e. `(h`, `+(h`.
143+ * - Returns `true` for unfinished brace expansions as long as they include `,` or `..`.
144+ *
145+ * @see {@link https://superchupu.dev/tinyglobby/documentation#isDynamicPattern }
146+ */
84147function isDynamicPattern ( pattern , options ) {
85148 if ( ( options === null || options === void 0 ? void 0 : options . caseSensitiveMatch ) === false ) return true ;
86149 const scan = picomatch . default . scan ( pattern ) ;
87150 return scan . isGlob || scan . negated ;
88151}
89152function log ( ...tasks ) {
90- console . log ( `[tinyglobby ${ new Date ( ) . toLocaleTimeString ( "es" ) } ]` , ...tasks ) ;
153+ console . log ( `[tinyglobby ${ ( /* @__PURE__ */ new Date ( ) ) . toLocaleTimeString ( "es" ) } ]` , ...tasks ) ;
91154}
92155
93156//#endregion
@@ -134,13 +197,12 @@ function normalizePattern(pattern, expandDirectories, cwd, props, isIgnore) {
134197 }
135198 props . depthOffset = newCommonPath . length ;
136199 props . commonPath = newCommonPath ;
137- props . root = newCommonPath . length > 0 ? path . default . posix . join ( cwd , ...newCommonPath ) : cwd ;
200+ props . root = newCommonPath . length > 0 ? path . posix . join ( cwd , ...newCommonPath ) : cwd ;
138201 }
139202 return result ;
140203}
141- function processPatterns ( { patterns, ignore = [ ] , expandDirectories = true } , cwd , props ) {
204+ function processPatterns ( { patterns = [ "**/*" ] , ignore = [ ] , expandDirectories = true } , cwd , props ) {
142205 if ( typeof patterns === "string" ) patterns = [ patterns ] ;
143- else if ( ! patterns ) patterns = [ "**/*" ] ;
144206 if ( typeof ignore === "string" ) ignore = [ ignore ] ;
145207 const matchPatterns = [ ] ;
146208 const ignorePatterns = [ ] ;
@@ -158,66 +220,88 @@ function processPatterns({ patterns, ignore = [], expandDirectories = true }, cw
158220 ignore : ignorePatterns
159221 } ;
160222}
161- function getRelativePath ( path$2 , cwd , root ) {
162- return path . posix . relative ( cwd , `${ root } /${ path$2 } ` ) || "." ;
163- }
164- function processPath ( path$2 , cwd , root , isDirectory , absolute ) {
165- const relativePath = absolute ? path$2 . slice ( root === "/" ? 1 : root . length + 1 ) || "." : path$2 ;
166- if ( root === cwd ) return isDirectory && relativePath !== "." ? relativePath . slice ( 0 , - 1 ) : relativePath ;
167- return getRelativePath ( relativePath , cwd , root ) ;
168- }
169- function formatPaths ( paths , cwd , root ) {
223+ function formatPaths ( paths , relative ) {
170224 for ( let i = paths . length - 1 ; i >= 0 ; i -- ) {
171225 const path$2 = paths [ i ] ;
172- paths [ i ] = getRelativePath ( path$2 , cwd , root ) + ( ! path$2 || path$2 . endsWith ( "/" ) ? "/" : "" ) ;
226+ paths [ i ] = relative ( path$2 ) ;
173227 }
174228 return paths ;
175229}
176- function crawl ( options , cwd , sync ) {
177- if ( process . env . TINYGLOBBY_DEBUG ) options . debug = true ;
178- if ( options . debug ) log ( "globbing with options:" , options , "cwd:" , cwd ) ;
179- if ( Array . isArray ( options . patterns ) && options . patterns . length === 0 ) return sync ? [ ] : Promise . resolve ( [ ] ) ;
230+ function normalizeCwd ( cwd ) {
231+ if ( ! cwd ) return process . cwd ( ) . replace ( BACKSLASHES , "/" ) ;
232+ if ( cwd instanceof URL ) return ( 0 , url . fileURLToPath ) ( cwd ) . replace ( BACKSLASHES , "/" ) ;
233+ return path . default . resolve ( cwd ) . replace ( BACKSLASHES , "/" ) ;
234+ }
235+ function getCrawler ( patterns , inputOptions = { } ) {
236+ const options = process . env . TINYGLOBBY_DEBUG ? {
237+ ...inputOptions ,
238+ debug : true
239+ } : inputOptions ;
240+ const cwd = normalizeCwd ( options . cwd ) ;
241+ if ( options . debug ) log ( "globbing with:" , {
242+ patterns,
243+ options,
244+ cwd
245+ } ) ;
246+ if ( Array . isArray ( patterns ) && patterns . length === 0 ) return [ {
247+ sync : ( ) => [ ] ,
248+ withPromise : async ( ) => [ ]
249+ } , false ] ;
180250 const props = {
181251 root : cwd ,
182252 commonPath : null ,
183253 depthOffset : 0
184254 } ;
185- const processed = processPatterns ( options , cwd , props ) ;
186- const nocase = options . caseSensitiveMatch === false ;
255+ const processed = processPatterns ( {
256+ ...options ,
257+ patterns
258+ } , cwd , props ) ;
187259 if ( options . debug ) log ( "internal processing patterns:" , processed ) ;
188- const matcher = ( 0 , picomatch . default ) ( processed . match , {
260+ const matchOptions = {
189261 dot : options . dot ,
190- nocase,
262+ nobrace : options . braceExpansion === false ,
263+ nocase : options . caseSensitiveMatch === false ,
264+ noextglob : options . extglob === false ,
265+ noglobstar : options . globstar === false ,
266+ posix : true
267+ } ;
268+ const matcher = ( 0 , picomatch . default ) ( processed . match , {
269+ ...matchOptions ,
191270 ignore : processed . ignore
192271 } ) ;
193- const ignore = ( 0 , picomatch . default ) ( processed . ignore , {
194- dot : options . dot ,
195- nocase
196- } ) ;
197- const partialMatcher = getPartialMatcher ( processed . match , {
198- dot : options . dot ,
199- nocase
200- } ) ;
272+ const ignore = ( 0 , picomatch . default ) ( processed . ignore , matchOptions ) ;
273+ const partialMatcher = getPartialMatcher ( processed . match , matchOptions ) ;
274+ const format = buildFormat ( cwd , props . root , options . absolute ) ;
275+ const formatExclude = options . absolute ? format : buildFormat ( cwd , props . root , true ) ;
201276 const fdirOptions = {
202277 filters : [ options . debug ? ( p , isDirectory ) => {
203- const path$2 = processPath ( p , cwd , props . root , isDirectory , options . absolute ) ;
278+ const path$2 = format ( p , isDirectory ) ;
204279 const matches = matcher ( path$2 ) ;
205280 if ( matches ) log ( `matched ${ path$2 } ` ) ;
206281 return matches ;
207- } : ( p , isDirectory ) => matcher ( processPath ( p , cwd , props . root , isDirectory , options . absolute ) ) ] ,
282+ } : ( p , isDirectory ) => matcher ( format ( p , isDirectory ) ) ] ,
208283 exclude : options . debug ? ( _ , p ) => {
209- const relativePath = processPath ( p , cwd , props . root , true , true ) ;
284+ const relativePath = formatExclude ( p , true ) ;
210285 const skipped = relativePath !== "." && ! partialMatcher ( relativePath ) || ignore ( relativePath ) ;
211286 if ( skipped ) log ( `skipped ${ p } ` ) ;
212287 else log ( `crawling ${ p } ` ) ;
213288 return skipped ;
214289 } : ( _ , p ) => {
215- const relativePath = processPath ( p , cwd , props . root , true , true ) ;
290+ const relativePath = formatExclude ( p , true ) ;
216291 return relativePath !== "." && ! partialMatcher ( relativePath ) || ignore ( relativePath ) ;
217292 } ,
293+ fs : options . fs ? {
294+ readdir : options . fs . readdir || fs . default . readdir ,
295+ readdirSync : options . fs . readdirSync || fs . default . readdirSync ,
296+ realpath : options . fs . realpath || fs . default . realpath ,
297+ realpathSync : options . fs . realpathSync || fs . default . realpathSync ,
298+ stat : options . fs . stat || fs . default . stat ,
299+ statSync : options . fs . statSync || fs . default . statSync
300+ } : void 0 ,
218301 pathSeparator : "/" ,
219302 relativePaths : true ,
220- resolveSymlinks : true
303+ resolveSymlinks : true ,
304+ signal : options . signal
221305 } ;
222306 if ( options . deep !== void 0 ) fdirOptions . maxDepth = Math . round ( options . deep - props . depthOffset ) ;
223307 if ( options . absolute ) {
@@ -236,27 +320,26 @@ function crawl(options, cwd, sync) {
236320 props . root = props . root . replace ( BACKSLASHES , "" ) ;
237321 const root = props . root ;
238322 if ( options . debug ) log ( "internal properties:" , props ) ;
239- const api = new fdir . fdir ( fdirOptions ) . crawl ( root ) ;
240- if ( cwd === root || options . absolute ) return sync ? api . sync ( ) : api . withPromise ( ) ;
241- return sync ? formatPaths ( api . sync ( ) , cwd , root ) : api . withPromise ( ) . then ( ( paths ) => formatPaths ( paths , cwd , root ) ) ;
323+ const relative = cwd !== root && ! options . absolute && buildRelative ( cwd , props . root ) ;
324+ return [ new fdir . fdir ( fdirOptions ) . crawl ( root ) , relative ] ;
242325}
243326async function glob ( patternsOrOptions , options ) {
244327 if ( patternsOrOptions && ( options === null || options === void 0 ? void 0 : options . patterns ) ) throw new Error ( "Cannot pass patterns as both an argument and an option" ) ;
245- const opts = Array . isArray ( patternsOrOptions ) || typeof patternsOrOptions === "string" ? {
246- ... options ,
247- patterns : patternsOrOptions
248- } : patternsOrOptions ;
249- const cwd = opts . cwd ? path . default . resolve ( opts . cwd ) . replace ( BACKSLASHES , "/" ) : process . cwd ( ) . replace ( BACKSLASHES , "/" ) ;
250- return crawl ( opts , cwd , false ) ;
328+ const isModern = isReadonlyArray ( patternsOrOptions ) || typeof patternsOrOptions === "string" ;
329+ const opts = isModern ? options : patternsOrOptions ;
330+ const patterns = isModern ? patternsOrOptions : patternsOrOptions . patterns ;
331+ const [ crawler , relative ] = getCrawler ( patterns , opts ) ;
332+ if ( ! relative ) return crawler . withPromise ( ) ;
333+ return formatPaths ( await crawler . withPromise ( ) , relative ) ;
251334}
252335function globSync ( patternsOrOptions , options ) {
253336 if ( patternsOrOptions && ( options === null || options === void 0 ? void 0 : options . patterns ) ) throw new Error ( "Cannot pass patterns as both an argument and an option" ) ;
254- const opts = Array . isArray ( patternsOrOptions ) || typeof patternsOrOptions === "string" ? {
255- ... options ,
256- patterns : patternsOrOptions
257- } : patternsOrOptions ;
258- const cwd = opts . cwd ? path . default . resolve ( opts . cwd ) . replace ( BACKSLASHES , "/" ) : process . cwd ( ) . replace ( BACKSLASHES , "/" ) ;
259- return crawl ( opts , cwd , true ) ;
337+ const isModern = isReadonlyArray ( patternsOrOptions ) || typeof patternsOrOptions === "string" ;
338+ const opts = isModern ? options : patternsOrOptions ;
339+ const patterns = isModern ? patternsOrOptions : patternsOrOptions . patterns ;
340+ const [ crawler , relative ] = getCrawler ( patterns , opts ) ;
341+ if ( ! relative ) return crawler . sync ( ) ;
342+ return formatPaths ( crawler . sync ( ) , relative ) ;
260343}
261344
262345//#endregion
0 commit comments