@@ -21,73 +21,136 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
} ) : target , mod ) ) ;
22
22
23
23
//#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 ) ;
27
34
28
35
//#region src/utils.ts
36
+ const isReadonlyArray = Array . isArray ;
37
+ const isWin = process . platform === "win32" ;
29
38
const ONLY_PARENT_DIRECTORIES = / ^ ( \/ ? \. \. ) + $ / ;
30
- function getPartialMatcher ( patterns , options ) {
39
+ function getPartialMatcher ( patterns , options = { } ) {
31
40
const patternsCount = patterns . length ;
32
41
const patternsParts = Array ( patternsCount ) ;
33
- const regexes = Array ( patternsCount ) ;
42
+ const matchers = Array ( patternsCount ) ;
43
+ const globstarEnabled = ! options . noglobstar ;
34
44
for ( let i = 0 ; i < patternsCount ; i ++ ) {
35
45
const parts = splitPattern ( patterns [ i ] ) ;
36
46
patternsParts [ i ] = parts ;
37
47
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 ;
41
51
}
42
52
return ( input ) => {
43
53
const inputParts = input . split ( "/" ) ;
44
54
if ( inputParts [ 0 ] === ".." && ONLY_PARENT_DIRECTORIES . test ( input ) ) return true ;
45
55
for ( let i = 0 ; i < patterns . length ; i ++ ) {
46
56
const patternParts = patternsParts [ i ] ;
47
- const regex = regexes [ i ] ;
57
+ const matcher = matchers [ i ] ;
48
58
const inputPatternCount = inputParts . length ;
49
59
const minParts = Math . min ( inputPatternCount , patternParts . length ) ;
50
60
let j = 0 ;
51
61
while ( j < minParts ) {
52
62
const part = patternParts [ j ] ;
53
63
if ( part . includes ( "/" ) ) return true ;
54
- const match = regex [ j ] . test ( inputParts [ j ] ) ;
64
+ const match = matcher [ j ] ( inputParts [ j ] ) ;
55
65
if ( ! match ) break ;
56
- if ( part === "**" ) return true ;
66
+ if ( globstarEnabled && part === "**" ) return true ;
57
67
j ++ ;
58
68
}
59
69
if ( j === inputPatternCount ) return true ;
60
70
}
61
71
return false ;
62
72
} ;
63
73
}
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
+ }
64
105
const splitPatternOptions = { parts : true } ;
65
106
function splitPattern ( path$2 ) {
66
107
var _result$parts ;
67
108
const result = picomatch . default . scan ( path$2 , splitPatternOptions ) ;
68
109
return ( ( _result$parts = result . parts ) === null || _result$parts === void 0 ? void 0 : _result$parts . length ) ? result . parts : [ path$2 ] ;
69
110
}
70
- const isWin = process . platform === "win32" ;
71
111
const ESCAPED_WIN32_BACKSLASHES = / \\ (? ! [ ( ) [ \] { } ! + @ ] ) / g;
72
112
function convertPosixPathToPattern ( path$2 ) {
73
113
return escapePosixPath ( path$2 ) ;
74
114
}
75
115
function convertWin32PathToPattern ( path$2 ) {
76
116
return escapeWin32Path ( path$2 ) . replace ( ESCAPED_WIN32_BACKSLASHES , "/" ) ;
77
117
}
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 */
78
124
const convertPathToPattern = isWin ? convertWin32PathToPattern : convertPosixPathToPattern ;
79
125
const POSIX_UNESCAPED_GLOB_SYMBOLS = / (?< ! \\ ) ( [ ( ) [ \] { } * ? | ] | ^ ! | [ ! + @ ] (? = \( ) | \\ (? ! [ ( ) [ \] { } ! * + ? @ | ] ) ) / g;
80
126
const WIN32_UNESCAPED_GLOB_SYMBOLS = / (?< ! \\ ) ( [ ( ) [ \] { } ] | ^ ! | [ ! + @ ] (? = \( ) ) / g;
81
127
const escapePosixPath = ( path$2 ) => path$2 . replace ( POSIX_UNESCAPED_GLOB_SYMBOLS , "\\$&" ) ;
82
128
const 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 */
83
134
const 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
+ */
84
147
function isDynamicPattern ( pattern , options ) {
85
148
if ( ( options === null || options === void 0 ? void 0 : options . caseSensitiveMatch ) === false ) return true ;
86
149
const scan = picomatch . default . scan ( pattern ) ;
87
150
return scan . isGlob || scan . negated ;
88
151
}
89
152
function log ( ...tasks ) {
90
- console . log ( `[tinyglobby ${ new Date ( ) . toLocaleTimeString ( "es" ) } ]` , ...tasks ) ;
153
+ console . log ( `[tinyglobby ${ ( /* @__PURE__ */ new Date ( ) ) . toLocaleTimeString ( "es" ) } ]` , ...tasks ) ;
91
154
}
92
155
93
156
//#endregion
@@ -134,13 +197,12 @@ function normalizePattern(pattern, expandDirectories, cwd, props, isIgnore) {
134
197
}
135
198
props . depthOffset = newCommonPath . length ;
136
199
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 ;
138
201
}
139
202
return result ;
140
203
}
141
- function processPatterns ( { patterns, ignore = [ ] , expandDirectories = true } , cwd , props ) {
204
+ function processPatterns ( { patterns = [ "**/*" ] , ignore = [ ] , expandDirectories = true } , cwd , props ) {
142
205
if ( typeof patterns === "string" ) patterns = [ patterns ] ;
143
- else if ( ! patterns ) patterns = [ "**/*" ] ;
144
206
if ( typeof ignore === "string" ) ignore = [ ignore ] ;
145
207
const matchPatterns = [ ] ;
146
208
const ignorePatterns = [ ] ;
@@ -158,66 +220,88 @@ function processPatterns({ patterns, ignore = [], expandDirectories = true }, cw
158
220
ignore : ignorePatterns
159
221
} ;
160
222
}
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 ) {
170
224
for ( let i = paths . length - 1 ; i >= 0 ; i -- ) {
171
225
const path$2 = paths [ i ] ;
172
- paths [ i ] = getRelativePath ( path$2 , cwd , root ) + ( ! path$2 || path$2 . endsWith ( "/" ) ? "/" : "" ) ;
226
+ paths [ i ] = relative ( path$2 ) ;
173
227
}
174
228
return paths ;
175
229
}
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 ] ;
180
250
const props = {
181
251
root : cwd ,
182
252
commonPath : null ,
183
253
depthOffset : 0
184
254
} ;
185
- const processed = processPatterns ( options , cwd , props ) ;
186
- const nocase = options . caseSensitiveMatch === false ;
255
+ const processed = processPatterns ( {
256
+ ...options ,
257
+ patterns
258
+ } , cwd , props ) ;
187
259
if ( options . debug ) log ( "internal processing patterns:" , processed ) ;
188
- const matcher = ( 0 , picomatch . default ) ( processed . match , {
260
+ const matchOptions = {
189
261
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 ,
191
270
ignore : processed . ignore
192
271
} ) ;
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 ) ;
201
276
const fdirOptions = {
202
277
filters : [ options . debug ? ( p , isDirectory ) => {
203
- const path$2 = processPath ( p , cwd , props . root , isDirectory , options . absolute ) ;
278
+ const path$2 = format ( p , isDirectory ) ;
204
279
const matches = matcher ( path$2 ) ;
205
280
if ( matches ) log ( `matched ${ path$2 } ` ) ;
206
281
return matches ;
207
- } : ( p , isDirectory ) => matcher ( processPath ( p , cwd , props . root , isDirectory , options . absolute ) ) ] ,
282
+ } : ( p , isDirectory ) => matcher ( format ( p , isDirectory ) ) ] ,
208
283
exclude : options . debug ? ( _ , p ) => {
209
- const relativePath = processPath ( p , cwd , props . root , true , true ) ;
284
+ const relativePath = formatExclude ( p , true ) ;
210
285
const skipped = relativePath !== "." && ! partialMatcher ( relativePath ) || ignore ( relativePath ) ;
211
286
if ( skipped ) log ( `skipped ${ p } ` ) ;
212
287
else log ( `crawling ${ p } ` ) ;
213
288
return skipped ;
214
289
} : ( _ , p ) => {
215
- const relativePath = processPath ( p , cwd , props . root , true , true ) ;
290
+ const relativePath = formatExclude ( p , true ) ;
216
291
return relativePath !== "." && ! partialMatcher ( relativePath ) || ignore ( relativePath ) ;
217
292
} ,
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 ,
218
301
pathSeparator : "/" ,
219
302
relativePaths : true ,
220
- resolveSymlinks : true
303
+ resolveSymlinks : true ,
304
+ signal : options . signal
221
305
} ;
222
306
if ( options . deep !== void 0 ) fdirOptions . maxDepth = Math . round ( options . deep - props . depthOffset ) ;
223
307
if ( options . absolute ) {
@@ -236,27 +320,26 @@ function crawl(options, cwd, sync) {
236
320
props . root = props . root . replace ( BACKSLASHES , "" ) ;
237
321
const root = props . root ;
238
322
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 ] ;
242
325
}
243
326
async function glob ( patternsOrOptions , options ) {
244
327
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 ) ;
251
334
}
252
335
function globSync ( patternsOrOptions , options ) {
253
336
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 ) ;
260
343
}
261
344
262
345
//#endregion
0 commit comments