minimatch 3.1.0 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/minimatch.js +708 -781
- package/package.json +3 -6
package/minimatch.js
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
|
+
const minimatch = module.exports = (p, pattern, options = {}) => {
|
|
2
|
+
assertValidPattern(pattern)
|
|
3
|
+
|
|
4
|
+
// shortcut: comments match nothing.
|
|
5
|
+
if (!options.nocomment && pattern.charAt(0) === '#') {
|
|
6
|
+
return false
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return new Minimatch(pattern, options).match(p)
|
|
10
|
+
}
|
|
11
|
+
|
|
1
12
|
module.exports = minimatch
|
|
2
|
-
minimatch.Minimatch = Minimatch
|
|
3
13
|
|
|
4
|
-
|
|
14
|
+
const path = (() => { try { return require('path') } catch (e) {}})() || {
|
|
5
15
|
sep: '/'
|
|
6
16
|
}
|
|
7
17
|
minimatch.sep = path.sep
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
|
|
19
|
+
const GLOBSTAR = Symbol('globstar **')
|
|
20
|
+
minimatch.GLOBSTAR = GLOBSTAR
|
|
21
|
+
const expand = require('brace-expansion')
|
|
11
22
|
|
|
12
|
-
|
|
23
|
+
const plTypes = {
|
|
13
24
|
'!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
|
|
14
25
|
'?': { open: '(?:', close: ')?' },
|
|
15
26
|
'+': { open: '(?:', close: ')+' },
|
|
@@ -19,213 +30,71 @@ var plTypes = {
|
|
|
19
30
|
|
|
20
31
|
// any single thing other than /
|
|
21
32
|
// don't need to escape / when using new RegExp()
|
|
22
|
-
|
|
33
|
+
const qmark = '[^/]'
|
|
23
34
|
|
|
24
35
|
// * => any number of characters
|
|
25
|
-
|
|
36
|
+
const star = qmark + '*?'
|
|
26
37
|
|
|
27
38
|
// ** when dots are allowed. Anything goes, except .. and .
|
|
28
39
|
// not (^ or / followed by one or two dots followed by $ or /),
|
|
29
40
|
// followed by anything, any number of times.
|
|
30
|
-
|
|
41
|
+
const twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?'
|
|
31
42
|
|
|
32
43
|
// not a ^ or / followed by a dot,
|
|
33
44
|
// followed by anything, any number of times.
|
|
34
|
-
|
|
45
|
+
const twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?'
|
|
46
|
+
|
|
47
|
+
// "abc" -> { a:true, b:true, c:true }
|
|
48
|
+
const charSet = s => s.split('').reduce((set, c) => {
|
|
49
|
+
set[c] = true
|
|
50
|
+
return set
|
|
51
|
+
}, {})
|
|
35
52
|
|
|
36
53
|
// characters that need to be escaped in RegExp.
|
|
37
|
-
|
|
54
|
+
const reSpecials = charSet('().*{}+?[]^$\\!')
|
|
38
55
|
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
return s.split('').reduce(function (set, c) {
|
|
42
|
-
set[c] = true
|
|
43
|
-
return set
|
|
44
|
-
}, {})
|
|
45
|
-
}
|
|
56
|
+
// characters that indicate we have to add the pattern start
|
|
57
|
+
const addPatternStartSet = charSet('[.(')
|
|
46
58
|
|
|
47
59
|
// normalizes slashes.
|
|
48
|
-
|
|
60
|
+
const slashSplit = /\/+/
|
|
49
61
|
|
|
50
|
-
minimatch.filter =
|
|
51
|
-
|
|
52
|
-
options = options || {}
|
|
53
|
-
return function (p, i, list) {
|
|
54
|
-
return minimatch(p, pattern, options)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
62
|
+
minimatch.filter = (pattern, options = {}) =>
|
|
63
|
+
(p, i, list) => minimatch(p, pattern, options)
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Object.keys(
|
|
62
|
-
t[k] = a[k]
|
|
63
|
-
})
|
|
64
|
-
Object.keys(b).forEach(function (k) {
|
|
65
|
-
t[k] = b[k]
|
|
66
|
-
})
|
|
65
|
+
const ext = (a, b = {}) => {
|
|
66
|
+
const t = {}
|
|
67
|
+
Object.keys(a).forEach(k => t[k] = a[k])
|
|
68
|
+
Object.keys(b).forEach(k => t[k] = b[k])
|
|
67
69
|
return t
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
minimatch.defaults =
|
|
72
|
+
minimatch.defaults = def => {
|
|
71
73
|
if (!def || typeof def !== 'object' || !Object.keys(def).length) {
|
|
72
74
|
return minimatch
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
var m = function minimatch (p, pattern, options) {
|
|
78
|
-
return orig(p, pattern, ext(def, options))
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
m.Minimatch = function Minimatch (pattern, options) {
|
|
82
|
-
return new orig.Minimatch(pattern, ext(def, options))
|
|
83
|
-
}
|
|
84
|
-
m.Minimatch.defaults = function defaults (options) {
|
|
85
|
-
return orig.defaults(ext(def, options)).Minimatch
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
m.filter = function filter (pattern, options) {
|
|
89
|
-
return orig.filter(pattern, ext(def, options))
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
m.defaults = function defaults (options) {
|
|
93
|
-
return orig.defaults(ext(def, options))
|
|
94
|
-
}
|
|
77
|
+
const orig = minimatch
|
|
95
78
|
|
|
96
|
-
m
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return orig.braceExpand(pattern, ext(def, options))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
m.match = function (list, pattern, options) {
|
|
105
|
-
return orig.match(list, pattern, ext(def, options))
|
|
79
|
+
const m = (p, pattern, options) => orig(p, pattern, ext(def, options))
|
|
80
|
+
m.Minimatch = class Minimatch extends orig.Minimatch {
|
|
81
|
+
constructor (pattern, options) {
|
|
82
|
+
super(pattern, ext(def, options))
|
|
83
|
+
}
|
|
106
84
|
}
|
|
85
|
+
m.Minimatch.defaults = options => orig.defaults(ext(def, options)).Minimatch
|
|
86
|
+
m.filter = (pattern, options) => orig.filter(pattern, ext(def, options))
|
|
87
|
+
m.defaults = options => orig.defaults(ext(def, options))
|
|
88
|
+
m.makeRe = (pattern, options) => orig.makeRe(pattern, ext(def, options))
|
|
89
|
+
m.braceExpand = (pattern, options) => orig.braceExpand(pattern, ext(def, options))
|
|
90
|
+
m.match = (list, pattern, options) => orig.match(list, pattern, ext(def, options))
|
|
107
91
|
|
|
108
92
|
return m
|
|
109
93
|
}
|
|
110
94
|
|
|
111
|
-
Minimatch.defaults = function (def) {
|
|
112
|
-
return minimatch.defaults(def).Minimatch
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function minimatch (p, pattern, options) {
|
|
116
|
-
assertValidPattern(pattern)
|
|
117
|
-
|
|
118
|
-
if (!options) options = {}
|
|
119
|
-
|
|
120
|
-
// shortcut: comments match nothing.
|
|
121
|
-
if (!options.nocomment && pattern.charAt(0) === '#') {
|
|
122
|
-
return false
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return new Minimatch(pattern, options).match(p)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function Minimatch (pattern, options) {
|
|
129
|
-
if (!(this instanceof Minimatch)) {
|
|
130
|
-
return new Minimatch(pattern, options)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
assertValidPattern(pattern)
|
|
134
|
-
|
|
135
|
-
if (!options) options = {}
|
|
136
|
-
|
|
137
|
-
// windows support: need to use /, not \
|
|
138
|
-
if (!options.allowWindowsEscape && path.sep !== '/') {
|
|
139
|
-
pattern = pattern.split(path.sep).join('/')
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
this.options = options
|
|
143
|
-
this.set = []
|
|
144
|
-
this.pattern = pattern
|
|
145
|
-
this.regexp = null
|
|
146
|
-
this.negate = false
|
|
147
|
-
this.comment = false
|
|
148
|
-
this.empty = false
|
|
149
|
-
this.partial = !!options.partial
|
|
150
|
-
|
|
151
|
-
// make the set of regexps etc.
|
|
152
|
-
this.make()
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
Minimatch.prototype.debug = function () {}
|
|
156
|
-
|
|
157
|
-
Minimatch.prototype.make = make
|
|
158
|
-
function make () {
|
|
159
|
-
var pattern = this.pattern
|
|
160
|
-
var options = this.options
|
|
161
95
|
|
|
162
|
-
// empty patterns and comments match nothing.
|
|
163
|
-
if (!options.nocomment && pattern.charAt(0) === '#') {
|
|
164
|
-
this.comment = true
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
if (!pattern) {
|
|
168
|
-
this.empty = true
|
|
169
|
-
return
|
|
170
|
-
}
|
|
171
96
|
|
|
172
|
-
// step 1: figure out negation, etc.
|
|
173
|
-
this.parseNegate()
|
|
174
97
|
|
|
175
|
-
// step 2: expand braces
|
|
176
|
-
var set = this.globSet = this.braceExpand()
|
|
177
|
-
|
|
178
|
-
if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
|
|
179
|
-
|
|
180
|
-
this.debug(this.pattern, set)
|
|
181
|
-
|
|
182
|
-
// step 3: now we have a set, so turn each one into a series of path-portion
|
|
183
|
-
// matching patterns.
|
|
184
|
-
// These will be regexps, except in the case of "**", which is
|
|
185
|
-
// set to the GLOBSTAR object for globstar behavior,
|
|
186
|
-
// and will not contain any / characters
|
|
187
|
-
set = this.globParts = set.map(function (s) {
|
|
188
|
-
return s.split(slashSplit)
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
this.debug(this.pattern, set)
|
|
192
|
-
|
|
193
|
-
// glob --> regexps
|
|
194
|
-
set = set.map(function (s, si, set) {
|
|
195
|
-
return s.map(this.parse, this)
|
|
196
|
-
}, this)
|
|
197
|
-
|
|
198
|
-
this.debug(this.pattern, set)
|
|
199
|
-
|
|
200
|
-
// filter out everything that didn't compile properly.
|
|
201
|
-
set = set.filter(function (s) {
|
|
202
|
-
return s.indexOf(false) === -1
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
this.debug(this.pattern, set)
|
|
206
|
-
|
|
207
|
-
this.set = set
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
Minimatch.prototype.parseNegate = parseNegate
|
|
211
|
-
function parseNegate () {
|
|
212
|
-
var pattern = this.pattern
|
|
213
|
-
var negate = false
|
|
214
|
-
var options = this.options
|
|
215
|
-
var negateOffset = 0
|
|
216
|
-
|
|
217
|
-
if (options.nonegate) return
|
|
218
|
-
|
|
219
|
-
for (var i = 0, l = pattern.length
|
|
220
|
-
; i < l && pattern.charAt(i) === '!'
|
|
221
|
-
; i++) {
|
|
222
|
-
negate = !negate
|
|
223
|
-
negateOffset++
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (negateOffset) this.pattern = pattern.substr(negateOffset)
|
|
227
|
-
this.negate = negate
|
|
228
|
-
}
|
|
229
98
|
|
|
230
99
|
// Brace expansion:
|
|
231
100
|
// a{b,c}d -> abd acd
|
|
@@ -237,24 +106,9 @@ function parseNegate () {
|
|
|
237
106
|
// Invalid sets are not expanded.
|
|
238
107
|
// a{2..}b -> a{2..}b
|
|
239
108
|
// a{b}c -> a{b}c
|
|
240
|
-
minimatch.braceExpand =
|
|
241
|
-
return braceExpand(pattern, options)
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
Minimatch.prototype.braceExpand = braceExpand
|
|
245
|
-
|
|
246
|
-
function braceExpand (pattern, options) {
|
|
247
|
-
if (!options) {
|
|
248
|
-
if (this instanceof Minimatch) {
|
|
249
|
-
options = this.options
|
|
250
|
-
} else {
|
|
251
|
-
options = {}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
pattern = typeof pattern === 'undefined'
|
|
256
|
-
? this.pattern : pattern
|
|
109
|
+
minimatch.braceExpand = (pattern, options) => braceExpand(pattern, options)
|
|
257
110
|
|
|
111
|
+
const braceExpand = (pattern, options = {}) => {
|
|
258
112
|
assertValidPattern(pattern)
|
|
259
113
|
|
|
260
114
|
// Thanks to Yeting Li <https://github.com/yetingli> for
|
|
@@ -267,8 +121,8 @@ function braceExpand (pattern, options) {
|
|
|
267
121
|
return expand(pattern)
|
|
268
122
|
}
|
|
269
123
|
|
|
270
|
-
|
|
271
|
-
|
|
124
|
+
const MAX_PATTERN_LENGTH = 1024 * 64
|
|
125
|
+
const assertValidPattern = pattern => {
|
|
272
126
|
if (typeof pattern !== 'string') {
|
|
273
127
|
throw new TypeError('invalid pattern')
|
|
274
128
|
}
|
|
@@ -289,661 +143,734 @@ var assertValidPattern = function (pattern) {
|
|
|
289
143
|
// when it is the *only* thing in a path portion. Otherwise, any series
|
|
290
144
|
// of * is equivalent to a single *. Globstar behavior is enabled by
|
|
291
145
|
// default, and can be disabled by setting options.noglobstar.
|
|
292
|
-
|
|
293
|
-
var SUBPARSE = {}
|
|
294
|
-
function parse (pattern, isSub) {
|
|
295
|
-
assertValidPattern(pattern)
|
|
146
|
+
const SUBPARSE = Symbol('subparse')
|
|
296
147
|
|
|
297
|
-
|
|
148
|
+
minimatch.makeRe = (pattern, options) =>
|
|
149
|
+
new Minimatch(pattern, options || {}).makeRe()
|
|
298
150
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
pattern = '*'
|
|
151
|
+
minimatch.match = (list, pattern, options = {}) => {
|
|
152
|
+
const mm = new Minimatch(pattern, options)
|
|
153
|
+
list = list.filter(f => mm.match(f))
|
|
154
|
+
if (mm.options.nonull && !list.length) {
|
|
155
|
+
list.push(pattern)
|
|
305
156
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
: options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))'
|
|
323
|
-
: '(?!\\.)'
|
|
324
|
-
var self = this
|
|
325
|
-
|
|
326
|
-
function clearStateChar () {
|
|
327
|
-
if (stateChar) {
|
|
328
|
-
// we had some state-tracking character
|
|
329
|
-
// that wasn't consumed by this pass.
|
|
330
|
-
switch (stateChar) {
|
|
331
|
-
case '*':
|
|
332
|
-
re += star
|
|
333
|
-
hasMagic = true
|
|
334
|
-
break
|
|
335
|
-
case '?':
|
|
336
|
-
re += qmark
|
|
337
|
-
hasMagic = true
|
|
338
|
-
break
|
|
339
|
-
default:
|
|
340
|
-
re += '\\' + stateChar
|
|
341
|
-
break
|
|
342
|
-
}
|
|
343
|
-
self.debug('clearStateChar %j %j', stateChar, re)
|
|
344
|
-
stateChar = false
|
|
157
|
+
return list
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// replace stuff like \* with *
|
|
161
|
+
const globUnescape = s => s.replace(/\\(.)/g, '$1')
|
|
162
|
+
const regExpEscape = s => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
|
|
163
|
+
|
|
164
|
+
class Minimatch {
|
|
165
|
+
constructor (pattern, options) {
|
|
166
|
+
assertValidPattern(pattern)
|
|
167
|
+
|
|
168
|
+
if (!options) options = {}
|
|
169
|
+
|
|
170
|
+
// windows support: need to use /, not \
|
|
171
|
+
if (!options.allowWindowsEscape && path.sep !== '/') {
|
|
172
|
+
pattern = pattern.split(path.sep).join('/')
|
|
345
173
|
}
|
|
174
|
+
|
|
175
|
+
this.options = options
|
|
176
|
+
this.set = []
|
|
177
|
+
this.pattern = pattern
|
|
178
|
+
this.regexp = null
|
|
179
|
+
this.negate = false
|
|
180
|
+
this.comment = false
|
|
181
|
+
this.empty = false
|
|
182
|
+
this.partial = !!options.partial
|
|
183
|
+
|
|
184
|
+
// make the set of regexps etc.
|
|
185
|
+
this.make()
|
|
346
186
|
}
|
|
347
187
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
188
|
+
debug () {}
|
|
189
|
+
|
|
190
|
+
make () {
|
|
191
|
+
const pattern = this.pattern
|
|
192
|
+
const options = this.options
|
|
352
193
|
|
|
353
|
-
//
|
|
354
|
-
if (
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
194
|
+
// empty patterns and comments match nothing.
|
|
195
|
+
if (!options.nocomment && pattern.charAt(0) === '#') {
|
|
196
|
+
this.comment = true
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
if (!pattern) {
|
|
200
|
+
this.empty = true
|
|
201
|
+
return
|
|
358
202
|
}
|
|
359
203
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
case '/': {
|
|
363
|
-
// completely not allowed, even escaped.
|
|
364
|
-
// Should already be path-split by now.
|
|
365
|
-
return false
|
|
366
|
-
}
|
|
204
|
+
// step 1: figure out negation, etc.
|
|
205
|
+
this.parseNegate()
|
|
367
206
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
escaping = true
|
|
371
|
-
continue
|
|
372
|
-
|
|
373
|
-
// the various stateChar values
|
|
374
|
-
// for the "extglob" stuff.
|
|
375
|
-
case '?':
|
|
376
|
-
case '*':
|
|
377
|
-
case '+':
|
|
378
|
-
case '@':
|
|
379
|
-
case '!':
|
|
380
|
-
this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c)
|
|
381
|
-
|
|
382
|
-
// all of those are literals inside a class, except that
|
|
383
|
-
// the glob [!a] means [^a] in regexp
|
|
384
|
-
if (inClass) {
|
|
385
|
-
this.debug(' in class')
|
|
386
|
-
if (c === '!' && i === classStart + 1) c = '^'
|
|
387
|
-
re += c
|
|
388
|
-
continue
|
|
389
|
-
}
|
|
207
|
+
// step 2: expand braces
|
|
208
|
+
let set = this.globSet = this.braceExpand()
|
|
390
209
|
|
|
391
|
-
|
|
392
|
-
// that there was something like ** or +? in there.
|
|
393
|
-
// Handle the stateChar, then proceed with this one.
|
|
394
|
-
self.debug('call clearStateChar %j', stateChar)
|
|
395
|
-
clearStateChar()
|
|
396
|
-
stateChar = c
|
|
397
|
-
// if extglob is disabled, then +(asdf|foo) isn't a thing.
|
|
398
|
-
// just clear the statechar *now*, rather than even diving into
|
|
399
|
-
// the patternList stuff.
|
|
400
|
-
if (options.noext) clearStateChar()
|
|
401
|
-
continue
|
|
402
|
-
|
|
403
|
-
case '(':
|
|
404
|
-
if (inClass) {
|
|
405
|
-
re += '('
|
|
406
|
-
continue
|
|
407
|
-
}
|
|
210
|
+
if (options.debug) this.debug = (...args) => console.error(...args)
|
|
408
211
|
|
|
409
|
-
|
|
410
|
-
re += '\\('
|
|
411
|
-
continue
|
|
412
|
-
}
|
|
212
|
+
this.debug(this.pattern, set)
|
|
413
213
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
})
|
|
421
|
-
// negation is (?:(?!js)[^/]*)
|
|
422
|
-
re += stateChar === '!' ? '(?:(?!(?:' : '(?:'
|
|
423
|
-
this.debug('plType %j %j', stateChar, re)
|
|
424
|
-
stateChar = false
|
|
425
|
-
continue
|
|
214
|
+
// step 3: now we have a set, so turn each one into a series of path-portion
|
|
215
|
+
// matching patterns.
|
|
216
|
+
// These will be regexps, except in the case of "**", which is
|
|
217
|
+
// set to the GLOBSTAR object for globstar behavior,
|
|
218
|
+
// and will not contain any / characters
|
|
219
|
+
set = this.globParts = set.map(s => s.split(slashSplit))
|
|
426
220
|
|
|
427
|
-
|
|
428
|
-
if (inClass || !patternListStack.length) {
|
|
429
|
-
re += '\\)'
|
|
430
|
-
continue
|
|
431
|
-
}
|
|
221
|
+
this.debug(this.pattern, set)
|
|
432
222
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
var pl = patternListStack.pop()
|
|
436
|
-
// negation is (?:(?!js)[^/]*)
|
|
437
|
-
// The others are (?:<pattern>)<type>
|
|
438
|
-
re += pl.close
|
|
439
|
-
if (pl.type === '!') {
|
|
440
|
-
negativeLists.push(pl)
|
|
441
|
-
}
|
|
442
|
-
pl.reEnd = re.length
|
|
443
|
-
continue
|
|
444
|
-
|
|
445
|
-
case '|':
|
|
446
|
-
if (inClass || !patternListStack.length || escaping) {
|
|
447
|
-
re += '\\|'
|
|
448
|
-
escaping = false
|
|
449
|
-
continue
|
|
450
|
-
}
|
|
223
|
+
// glob --> regexps
|
|
224
|
+
set = set.map((s, si, set) => s.map(this.parse, this))
|
|
451
225
|
|
|
452
|
-
|
|
453
|
-
re += '|'
|
|
454
|
-
continue
|
|
226
|
+
this.debug(this.pattern, set)
|
|
455
227
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
// swallow any state-tracking char before the [
|
|
459
|
-
clearStateChar()
|
|
228
|
+
// filter out everything that didn't compile properly.
|
|
229
|
+
set = set.filter(s => s.indexOf(false) === -1)
|
|
460
230
|
|
|
461
|
-
|
|
462
|
-
re += '\\' + c
|
|
463
|
-
continue
|
|
464
|
-
}
|
|
231
|
+
this.debug(this.pattern, set)
|
|
465
232
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
reClassStart = re.length
|
|
469
|
-
re += c
|
|
470
|
-
continue
|
|
471
|
-
|
|
472
|
-
case ']':
|
|
473
|
-
// a right bracket shall lose its special
|
|
474
|
-
// meaning and represent itself in
|
|
475
|
-
// a bracket expression if it occurs
|
|
476
|
-
// first in the list. -- POSIX.2 2.8.3.2
|
|
477
|
-
if (i === classStart + 1 || !inClass) {
|
|
478
|
-
re += '\\' + c
|
|
479
|
-
escaping = false
|
|
480
|
-
continue
|
|
481
|
-
}
|
|
233
|
+
this.set = set
|
|
234
|
+
}
|
|
482
235
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
236
|
+
parseNegate () {
|
|
237
|
+
if (this.options.nonegate) return
|
|
238
|
+
|
|
239
|
+
const pattern = this.pattern
|
|
240
|
+
let negate = false
|
|
241
|
+
let negateOffset = 0
|
|
242
|
+
|
|
243
|
+
for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
|
|
244
|
+
negate = !negate
|
|
245
|
+
negateOffset++
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (negateOffset) this.pattern = pattern.substr(negateOffset)
|
|
249
|
+
this.negate = negate
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// set partial to true to test if, for example,
|
|
253
|
+
// "/a/b" matches the start of "/*/b/*/d"
|
|
254
|
+
// Partial means, if you run out of file before you run
|
|
255
|
+
// out of pattern, then that's fine, as long as all
|
|
256
|
+
// the parts match.
|
|
257
|
+
matchOne (file, pattern, partial) {
|
|
258
|
+
var options = this.options
|
|
259
|
+
|
|
260
|
+
this.debug('matchOne',
|
|
261
|
+
{ 'this': this, file: file, pattern: pattern })
|
|
262
|
+
|
|
263
|
+
this.debug('matchOne', file.length, pattern.length)
|
|
264
|
+
|
|
265
|
+
for (var fi = 0,
|
|
266
|
+
pi = 0,
|
|
267
|
+
fl = file.length,
|
|
268
|
+
pl = pattern.length
|
|
269
|
+
; (fi < fl) && (pi < pl)
|
|
270
|
+
; fi++, pi++) {
|
|
271
|
+
this.debug('matchOne loop')
|
|
272
|
+
var p = pattern[pi]
|
|
273
|
+
var f = file[fi]
|
|
274
|
+
|
|
275
|
+
this.debug(pattern, p, f)
|
|
276
|
+
|
|
277
|
+
// should be impossible.
|
|
278
|
+
// some invalid regexp stuff in the set.
|
|
279
|
+
/* istanbul ignore if */
|
|
280
|
+
if (p === false) return false
|
|
281
|
+
|
|
282
|
+
if (p === GLOBSTAR) {
|
|
283
|
+
this.debug('GLOBSTAR', [pattern, p, f])
|
|
284
|
+
|
|
285
|
+
// "**"
|
|
286
|
+
// a/**/b/**/c would match the following:
|
|
287
|
+
// a/b/x/y/z/c
|
|
288
|
+
// a/x/y/z/b/c
|
|
289
|
+
// a/b/x/b/x/c
|
|
290
|
+
// a/b/c
|
|
291
|
+
// To do this, take the rest of the pattern after
|
|
292
|
+
// the **, and see if it would match the file remainder.
|
|
293
|
+
// If so, return success.
|
|
294
|
+
// If not, the ** "swallows" a segment, and try again.
|
|
295
|
+
// This is recursively awful.
|
|
296
|
+
//
|
|
297
|
+
// a/**/b/**/c matching a/b/x/y/z/c
|
|
298
|
+
// - a matches a
|
|
299
|
+
// - doublestar
|
|
300
|
+
// - matchOne(b/x/y/z/c, b/**/c)
|
|
301
|
+
// - b matches b
|
|
302
|
+
// - doublestar
|
|
303
|
+
// - matchOne(x/y/z/c, c) -> no
|
|
304
|
+
// - matchOne(y/z/c, c) -> no
|
|
305
|
+
// - matchOne(z/c, c) -> no
|
|
306
|
+
// - matchOne(c, c) yes, hit
|
|
307
|
+
var fr = fi
|
|
308
|
+
var pr = pi + 1
|
|
309
|
+
if (pr === pl) {
|
|
310
|
+
this.debug('** at the end')
|
|
311
|
+
// a ** at the end will just swallow the rest.
|
|
312
|
+
// We have found a match.
|
|
313
|
+
// however, it will not swallow /.x, unless
|
|
314
|
+
// options.dot is set.
|
|
315
|
+
// . and .. are *never* matched by **, for explosively
|
|
316
|
+
// exponential reasons.
|
|
317
|
+
for (; fi < fl; fi++) {
|
|
318
|
+
if (file[fi] === '.' || file[fi] === '..' ||
|
|
319
|
+
(!options.dot && file[fi].charAt(0) === '.')) return false
|
|
320
|
+
}
|
|
321
|
+
return true
|
|
502
322
|
}
|
|
503
323
|
|
|
504
|
-
//
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
324
|
+
// ok, let's see if we can swallow whatever we can.
|
|
325
|
+
while (fr < fl) {
|
|
326
|
+
var swallowee = file[fr]
|
|
327
|
+
|
|
328
|
+
this.debug('\nglobstar while', file, fr, pattern, pr, swallowee)
|
|
329
|
+
|
|
330
|
+
// XXX remove this slice. Just pass the start index.
|
|
331
|
+
if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
|
|
332
|
+
this.debug('globstar found match!', fr, fl, swallowee)
|
|
333
|
+
// found a match.
|
|
334
|
+
return true
|
|
335
|
+
} else {
|
|
336
|
+
// can't swallow "." or ".." ever.
|
|
337
|
+
// can only swallow ".foo" when explicitly asked.
|
|
338
|
+
if (swallowee === '.' || swallowee === '..' ||
|
|
339
|
+
(!options.dot && swallowee.charAt(0) === '.')) {
|
|
340
|
+
this.debug('dot detected!', file, fr, pattern, pr)
|
|
341
|
+
break
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// ** swallows a segment, and continue.
|
|
345
|
+
this.debug('globstar swallow a segment, and continue')
|
|
346
|
+
fr++
|
|
347
|
+
}
|
|
520
348
|
}
|
|
521
349
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
// any characters that were passed through as-is
|
|
534
|
-
cs = pattern.substr(classStart + 1)
|
|
535
|
-
sp = this.parse(cs, SUBPARSE)
|
|
536
|
-
re = re.substr(0, reClassStart) + '\\[' + sp[0]
|
|
537
|
-
hasMagic = hasMagic || sp[1]
|
|
538
|
-
}
|
|
350
|
+
// no match was found.
|
|
351
|
+
// However, in partial mode, we can't say this is necessarily over.
|
|
352
|
+
// If there's more *pattern* left, then
|
|
353
|
+
/* istanbul ignore if */
|
|
354
|
+
if (partial) {
|
|
355
|
+
// ran out of file
|
|
356
|
+
this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
|
|
357
|
+
if (fr === fl) return true
|
|
358
|
+
}
|
|
359
|
+
return false
|
|
360
|
+
}
|
|
539
361
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) {
|
|
551
|
-
if (!$2) {
|
|
552
|
-
// the | isn't already escaped, so escape it.
|
|
553
|
-
$2 = '\\'
|
|
362
|
+
// something other than **
|
|
363
|
+
// non-magic patterns just have to match exactly
|
|
364
|
+
// patterns with magic have been turned into regexps.
|
|
365
|
+
var hit
|
|
366
|
+
if (typeof p === 'string') {
|
|
367
|
+
hit = f === p
|
|
368
|
+
this.debug('string match', p, f, hit)
|
|
369
|
+
} else {
|
|
370
|
+
hit = f.match(p)
|
|
371
|
+
this.debug('pattern match', p, f, hit)
|
|
554
372
|
}
|
|
555
373
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
374
|
+
if (!hit) return false
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Note: ending in / means that we'll get a final ""
|
|
378
|
+
// at the end of the pattern. This can only match a
|
|
379
|
+
// corresponding "" at the end of the file.
|
|
380
|
+
// If the file ends in /, then it can only match a
|
|
381
|
+
// a pattern that ends in /, unless the pattern just
|
|
382
|
+
// doesn't have any more for it. But, a/b/ should *not*
|
|
383
|
+
// match "a/b/*", even though "" matches against the
|
|
384
|
+
// [^/]*? pattern, except in partial mode, where it might
|
|
385
|
+
// simply not be reached yet.
|
|
386
|
+
// However, a/b/ should still satisfy a/*
|
|
387
|
+
|
|
388
|
+
// now either we fell off the end of the pattern, or we're done.
|
|
389
|
+
if (fi === fl && pi === pl) {
|
|
390
|
+
// ran out of pattern and filename at the same time.
|
|
391
|
+
// an exact hit!
|
|
392
|
+
return true
|
|
393
|
+
} else if (fi === fl) {
|
|
394
|
+
// ran out of file, but still had pattern left.
|
|
395
|
+
// this is ok if we're doing the match as part of
|
|
396
|
+
// a glob fs traversal.
|
|
397
|
+
return partial
|
|
398
|
+
} else /* istanbul ignore else */ if (pi === pl) {
|
|
399
|
+
// ran out of pattern, still have file left.
|
|
400
|
+
// this is only acceptable if we're on the very last
|
|
401
|
+
// empty segment of a file with a trailing slash.
|
|
402
|
+
// a/* should match a/b/
|
|
403
|
+
return (fi === fl - 1) && (file[fi] === '')
|
|
404
|
+
}
|
|
573
405
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
// trailing \\
|
|
578
|
-
re += '\\\\'
|
|
406
|
+
// should be unreachable.
|
|
407
|
+
/* istanbul ignore next */
|
|
408
|
+
throw new Error('wtf?')
|
|
579
409
|
}
|
|
580
410
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
var addPatternStart = false
|
|
584
|
-
switch (re.charAt(0)) {
|
|
585
|
-
case '[': case '.': case '(': addPatternStart = true
|
|
411
|
+
braceExpand () {
|
|
412
|
+
return braceExpand(this.pattern, this.options)
|
|
586
413
|
}
|
|
587
414
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
// the pattern.
|
|
593
|
-
for (var n = negativeLists.length - 1; n > -1; n--) {
|
|
594
|
-
var nl = negativeLists[n]
|
|
595
|
-
|
|
596
|
-
var nlBefore = re.slice(0, nl.reStart)
|
|
597
|
-
var nlFirst = re.slice(nl.reStart, nl.reEnd - 8)
|
|
598
|
-
var nlLast = re.slice(nl.reEnd - 8, nl.reEnd)
|
|
599
|
-
var nlAfter = re.slice(nl.reEnd)
|
|
600
|
-
|
|
601
|
-
nlLast += nlAfter
|
|
602
|
-
|
|
603
|
-
// Handle nested stuff like *(*.js|!(*.json)), where open parens
|
|
604
|
-
// mean that we should *not* include the ) in the bit that is considered
|
|
605
|
-
// "after" the negated section.
|
|
606
|
-
var openParensBefore = nlBefore.split('(').length - 1
|
|
607
|
-
var cleanAfter = nlAfter
|
|
608
|
-
for (i = 0; i < openParensBefore; i++) {
|
|
609
|
-
cleanAfter = cleanAfter.replace(/\)[+*?]?/, '')
|
|
610
|
-
}
|
|
611
|
-
nlAfter = cleanAfter
|
|
415
|
+
parse (pattern, isSub) {
|
|
416
|
+
assertValidPattern(pattern)
|
|
417
|
+
|
|
418
|
+
const options = this.options
|
|
612
419
|
|
|
613
|
-
|
|
614
|
-
if (
|
|
615
|
-
|
|
420
|
+
// shortcuts
|
|
421
|
+
if (pattern === '**') {
|
|
422
|
+
if (!options.noglobstar)
|
|
423
|
+
return GLOBSTAR
|
|
424
|
+
else
|
|
425
|
+
pattern = '*'
|
|
426
|
+
}
|
|
427
|
+
if (pattern === '') return ''
|
|
428
|
+
|
|
429
|
+
let re = ''
|
|
430
|
+
let hasMagic = !!options.nocase
|
|
431
|
+
let escaping = false
|
|
432
|
+
// ? => one single character
|
|
433
|
+
const patternListStack = []
|
|
434
|
+
const negativeLists = []
|
|
435
|
+
let stateChar
|
|
436
|
+
let inClass = false
|
|
437
|
+
let reClassStart = -1
|
|
438
|
+
let classStart = -1
|
|
439
|
+
let cs
|
|
440
|
+
let pl
|
|
441
|
+
let sp
|
|
442
|
+
// . and .. never match anything that doesn't start with .,
|
|
443
|
+
// even when options.dot is set.
|
|
444
|
+
const patternStart = pattern.charAt(0) === '.' ? '' // anything
|
|
445
|
+
// not (start or / followed by . or .. followed by / or end)
|
|
446
|
+
: options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))'
|
|
447
|
+
: '(?!\\.)'
|
|
448
|
+
|
|
449
|
+
const clearStateChar = () => {
|
|
450
|
+
if (stateChar) {
|
|
451
|
+
// we had some state-tracking character
|
|
452
|
+
// that wasn't consumed by this pass.
|
|
453
|
+
switch (stateChar) {
|
|
454
|
+
case '*':
|
|
455
|
+
re += star
|
|
456
|
+
hasMagic = true
|
|
457
|
+
break
|
|
458
|
+
case '?':
|
|
459
|
+
re += qmark
|
|
460
|
+
hasMagic = true
|
|
461
|
+
break
|
|
462
|
+
default:
|
|
463
|
+
re += '\\' + stateChar
|
|
464
|
+
break
|
|
465
|
+
}
|
|
466
|
+
this.debug('clearStateChar %j %j', stateChar, re)
|
|
467
|
+
stateChar = false
|
|
468
|
+
}
|
|
616
469
|
}
|
|
617
|
-
var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast
|
|
618
|
-
re = newRe
|
|
619
|
-
}
|
|
620
470
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
// Otherwise a/* will match a/, which it should not.
|
|
624
|
-
if (re !== '' && hasMagic) {
|
|
625
|
-
re = '(?=.)' + re
|
|
626
|
-
}
|
|
471
|
+
for (let i = 0, c; (i < pattern.length) && (c = pattern.charAt(i)); i++) {
|
|
472
|
+
this.debug('%s\t%s %s %j', pattern, i, re, c)
|
|
627
473
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
474
|
+
// skip over any that are escaped.
|
|
475
|
+
if (escaping && reSpecials[c]) {
|
|
476
|
+
re += '\\' + c
|
|
477
|
+
escaping = false
|
|
478
|
+
continue
|
|
479
|
+
}
|
|
631
480
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
481
|
+
switch (c) {
|
|
482
|
+
/* istanbul ignore next */
|
|
483
|
+
case '/': {
|
|
484
|
+
// completely not allowed, even escaped.
|
|
485
|
+
// Should already be path-split by now.
|
|
486
|
+
return false
|
|
487
|
+
}
|
|
636
488
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
return globUnescape(pattern)
|
|
642
|
-
}
|
|
489
|
+
case '\\':
|
|
490
|
+
clearStateChar()
|
|
491
|
+
escaping = true
|
|
492
|
+
continue
|
|
643
493
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
494
|
+
// the various stateChar values
|
|
495
|
+
// for the "extglob" stuff.
|
|
496
|
+
case '?':
|
|
497
|
+
case '*':
|
|
498
|
+
case '+':
|
|
499
|
+
case '@':
|
|
500
|
+
case '!':
|
|
501
|
+
this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c)
|
|
502
|
+
|
|
503
|
+
// all of those are literals inside a class, except that
|
|
504
|
+
// the glob [!a] means [^a] in regexp
|
|
505
|
+
if (inClass) {
|
|
506
|
+
this.debug(' in class')
|
|
507
|
+
if (c === '!' && i === classStart + 1) c = '^'
|
|
508
|
+
re += c
|
|
509
|
+
continue
|
|
510
|
+
}
|
|
654
511
|
|
|
655
|
-
|
|
656
|
-
|
|
512
|
+
// if we already have a stateChar, then it means
|
|
513
|
+
// that there was something like ** or +? in there.
|
|
514
|
+
// Handle the stateChar, then proceed with this one.
|
|
515
|
+
this.debug('call clearStateChar %j', stateChar)
|
|
516
|
+
clearStateChar()
|
|
517
|
+
stateChar = c
|
|
518
|
+
// if extglob is disabled, then +(asdf|foo) isn't a thing.
|
|
519
|
+
// just clear the statechar *now*, rather than even diving into
|
|
520
|
+
// the patternList stuff.
|
|
521
|
+
if (options.noext) clearStateChar()
|
|
522
|
+
continue
|
|
523
|
+
|
|
524
|
+
case '(':
|
|
525
|
+
if (inClass) {
|
|
526
|
+
re += '('
|
|
527
|
+
continue
|
|
528
|
+
}
|
|
657
529
|
|
|
658
|
-
|
|
659
|
-
|
|
530
|
+
if (!stateChar) {
|
|
531
|
+
re += '\\('
|
|
532
|
+
continue
|
|
533
|
+
}
|
|
660
534
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
535
|
+
patternListStack.push({
|
|
536
|
+
type: stateChar,
|
|
537
|
+
start: i - 1,
|
|
538
|
+
reStart: re.length,
|
|
539
|
+
open: plTypes[stateChar].open,
|
|
540
|
+
close: plTypes[stateChar].close
|
|
541
|
+
})
|
|
542
|
+
// negation is (?:(?!js)[^/]*)
|
|
543
|
+
re += stateChar === '!' ? '(?:(?!(?:' : '(?:'
|
|
544
|
+
this.debug('plType %j %j', stateChar, re)
|
|
545
|
+
stateChar = false
|
|
546
|
+
continue
|
|
547
|
+
|
|
548
|
+
case ')':
|
|
549
|
+
if (inClass || !patternListStack.length) {
|
|
550
|
+
re += '\\)'
|
|
551
|
+
continue
|
|
552
|
+
}
|
|
664
553
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
554
|
+
clearStateChar()
|
|
555
|
+
hasMagic = true
|
|
556
|
+
pl = patternListStack.pop()
|
|
557
|
+
// negation is (?:(?!js)[^/]*)
|
|
558
|
+
// The others are (?:<pattern>)<type>
|
|
559
|
+
re += pl.close
|
|
560
|
+
if (pl.type === '!') {
|
|
561
|
+
negativeLists.push(pl)
|
|
562
|
+
}
|
|
563
|
+
pl.reEnd = re.length
|
|
564
|
+
continue
|
|
565
|
+
|
|
566
|
+
case '|':
|
|
567
|
+
if (inClass || !patternListStack.length || escaping) {
|
|
568
|
+
re += '\\|'
|
|
569
|
+
escaping = false
|
|
570
|
+
continue
|
|
571
|
+
}
|
|
668
572
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
// It's better to use .match(). This function shouldn't
|
|
673
|
-
// be used, really, but it's pretty convenient sometimes,
|
|
674
|
-
// when you just want to work with a regex.
|
|
675
|
-
var set = this.set
|
|
573
|
+
clearStateChar()
|
|
574
|
+
re += '|'
|
|
575
|
+
continue
|
|
676
576
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
var options = this.options
|
|
682
|
-
|
|
683
|
-
var twoStar = options.noglobstar ? star
|
|
684
|
-
: options.dot ? twoStarDot
|
|
685
|
-
: twoStarNoDot
|
|
686
|
-
var flags = options.nocase ? 'i' : ''
|
|
687
|
-
|
|
688
|
-
var re = set.map(function (pattern) {
|
|
689
|
-
return pattern.map(function (p) {
|
|
690
|
-
return (p === GLOBSTAR) ? twoStar
|
|
691
|
-
: (typeof p === 'string') ? regExpEscape(p)
|
|
692
|
-
: p._src
|
|
693
|
-
}).join('\\\/')
|
|
694
|
-
}).join('|')
|
|
695
|
-
|
|
696
|
-
// must match entire pattern
|
|
697
|
-
// ending in a * or ** will make it less strict.
|
|
698
|
-
re = '^(?:' + re + ')$'
|
|
699
|
-
|
|
700
|
-
// can match anything, as long as it's not this.
|
|
701
|
-
if (this.negate) re = '^(?!' + re + ').*$'
|
|
702
|
-
|
|
703
|
-
try {
|
|
704
|
-
this.regexp = new RegExp(re, flags)
|
|
705
|
-
} catch (ex) /* istanbul ignore next - should be impossible */ {
|
|
706
|
-
this.regexp = false
|
|
707
|
-
}
|
|
708
|
-
return this.regexp
|
|
709
|
-
}
|
|
577
|
+
// these are mostly the same in regexp and glob
|
|
578
|
+
case '[':
|
|
579
|
+
// swallow any state-tracking char before the [
|
|
580
|
+
clearStateChar()
|
|
710
581
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
582
|
+
if (inClass) {
|
|
583
|
+
re += '\\' + c
|
|
584
|
+
continue
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
inClass = true
|
|
588
|
+
classStart = i
|
|
589
|
+
reClassStart = re.length
|
|
590
|
+
re += c
|
|
591
|
+
continue
|
|
592
|
+
|
|
593
|
+
case ']':
|
|
594
|
+
// a right bracket shall lose its special
|
|
595
|
+
// meaning and represent itself in
|
|
596
|
+
// a bracket expression if it occurs
|
|
597
|
+
// first in the list. -- POSIX.2 2.8.3.2
|
|
598
|
+
if (i === classStart + 1 || !inClass) {
|
|
599
|
+
re += '\\' + c
|
|
600
|
+
escaping = false
|
|
601
|
+
continue
|
|
602
|
+
}
|
|
722
603
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
604
|
+
// handle the case where we left a class open.
|
|
605
|
+
// "[z-a]" is valid, equivalent to "\[z-a\]"
|
|
606
|
+
// split where the last [ was, make sure we don't have
|
|
607
|
+
// an invalid re. if so, re-walk the contents of the
|
|
608
|
+
// would-be class to re-translate any characters that
|
|
609
|
+
// were passed through as-is
|
|
610
|
+
// TODO: It would probably be faster to determine this
|
|
611
|
+
// without a try/catch and a new RegExp, but it's tricky
|
|
612
|
+
// to do safely. For now, this is safe and works.
|
|
613
|
+
cs = pattern.substring(classStart + 1, i)
|
|
614
|
+
try {
|
|
615
|
+
RegExp('[' + cs + ']')
|
|
616
|
+
} catch (er) {
|
|
617
|
+
// not a valid class!
|
|
618
|
+
sp = this.parse(cs, SUBPARSE)
|
|
619
|
+
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
|
|
620
|
+
hasMagic = hasMagic || sp[1]
|
|
621
|
+
inClass = false
|
|
622
|
+
continue
|
|
623
|
+
}
|
|
730
624
|
|
|
731
|
-
|
|
625
|
+
// finish up the class.
|
|
626
|
+
hasMagic = true
|
|
627
|
+
inClass = false
|
|
628
|
+
re += c
|
|
629
|
+
continue
|
|
732
630
|
|
|
733
|
-
|
|
631
|
+
default:
|
|
632
|
+
// swallow any state char that wasn't consumed
|
|
633
|
+
clearStateChar()
|
|
634
|
+
|
|
635
|
+
if (escaping) {
|
|
636
|
+
// no need
|
|
637
|
+
escaping = false
|
|
638
|
+
} else if (reSpecials[c]
|
|
639
|
+
&& !(c === '^' && inClass)) {
|
|
640
|
+
re += '\\'
|
|
641
|
+
}
|
|
734
642
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
643
|
+
re += c
|
|
644
|
+
|
|
645
|
+
} // switch
|
|
646
|
+
} // for
|
|
647
|
+
|
|
648
|
+
// handle the case where we left a class open.
|
|
649
|
+
// "[abc" is valid, equivalent to "\[abc"
|
|
650
|
+
if (inClass) {
|
|
651
|
+
// split where the last [ was, and escape it
|
|
652
|
+
// this is a huge pita. We now have to re-walk
|
|
653
|
+
// the contents of the would-be class to re-translate
|
|
654
|
+
// any characters that were passed through as-is
|
|
655
|
+
cs = pattern.substr(classStart + 1)
|
|
656
|
+
sp = this.parse(cs, SUBPARSE)
|
|
657
|
+
re = re.substr(0, reClassStart) + '\\[' + sp[0]
|
|
658
|
+
hasMagic = hasMagic || sp[1]
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// handle the case where we had a +( thing at the *end*
|
|
662
|
+
// of the pattern.
|
|
663
|
+
// each pattern list stack adds 3 chars, and we need to go through
|
|
664
|
+
// and escape any | chars that were passed through as-is for the regexp.
|
|
665
|
+
// Go through and escape them, taking care not to double-escape any
|
|
666
|
+
// | chars that were already escaped.
|
|
667
|
+
for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
|
|
668
|
+
let tail
|
|
669
|
+
tail = re.slice(pl.reStart + pl.open.length)
|
|
670
|
+
this.debug('setting tail', re, pl)
|
|
671
|
+
// maybe some even number of \, then maybe 1 \, followed by a |
|
|
672
|
+
tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => {
|
|
673
|
+
if (!$2) {
|
|
674
|
+
// the | isn't already escaped, so escape it.
|
|
675
|
+
$2 = '\\'
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// need to escape all those slashes *again*, without escaping the
|
|
679
|
+
// one that we need for escaping the | character. As it works out,
|
|
680
|
+
// escaping an even number of slashes can be done by simply repeating
|
|
681
|
+
// it exactly after itself. That's why this trick works.
|
|
682
|
+
//
|
|
683
|
+
// I am sorry that you have to see this.
|
|
684
|
+
return $1 + $1 + $2 + '|'
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
this.debug('tail=%j\n %s', tail, tail, pl, re)
|
|
688
|
+
const t = pl.type === '*' ? star
|
|
689
|
+
: pl.type === '?' ? qmark
|
|
690
|
+
: '\\' + pl.type
|
|
691
|
+
|
|
692
|
+
hasMagic = true
|
|
693
|
+
re = re.slice(0, pl.reStart) + t + '\\(' + tail
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// handle trailing things that only matter at the very end.
|
|
697
|
+
clearStateChar()
|
|
698
|
+
if (escaping) {
|
|
699
|
+
// trailing \\
|
|
700
|
+
re += '\\\\'
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// only need to apply the nodot start if the re starts with
|
|
704
|
+
// something that could conceivably capture a dot
|
|
705
|
+
const addPatternStart = addPatternStartSet[re.charAt(0)]
|
|
706
|
+
|
|
707
|
+
// Hack to work around lack of negative lookbehind in JS
|
|
708
|
+
// A pattern like: *.!(x).!(y|z) needs to ensure that a name
|
|
709
|
+
// like 'a.xyz.yz' doesn't match. So, the first negative
|
|
710
|
+
// lookahead, has to look ALL the way ahead, to the end of
|
|
711
|
+
// the pattern.
|
|
712
|
+
for (let n = negativeLists.length - 1; n > -1; n--) {
|
|
713
|
+
const nl = negativeLists[n]
|
|
714
|
+
|
|
715
|
+
const nlBefore = re.slice(0, nl.reStart)
|
|
716
|
+
const nlFirst = re.slice(nl.reStart, nl.reEnd - 8)
|
|
717
|
+
let nlAfter = re.slice(nl.reEnd)
|
|
718
|
+
const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter
|
|
719
|
+
|
|
720
|
+
// Handle nested stuff like *(*.js|!(*.json)), where open parens
|
|
721
|
+
// mean that we should *not* include the ) in the bit that is considered
|
|
722
|
+
// "after" the negated section.
|
|
723
|
+
const openParensBefore = nlBefore.split('(').length - 1
|
|
724
|
+
let cleanAfter = nlAfter
|
|
725
|
+
for (let i = 0; i < openParensBefore; i++) {
|
|
726
|
+
cleanAfter = cleanAfter.replace(/\)[+*?]?/, '')
|
|
727
|
+
}
|
|
728
|
+
nlAfter = cleanAfter
|
|
729
|
+
|
|
730
|
+
const dollar = nlAfter === '' && isSub !== SUBPARSE ? '$' : ''
|
|
731
|
+
re = nlBefore + nlFirst + nlAfter + dollar + nlLast
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// if the re is not "" at this point, then we need to make sure
|
|
735
|
+
// it doesn't match against an empty path part.
|
|
736
|
+
// Otherwise a/* will match a/, which it should not.
|
|
737
|
+
if (re !== '' && hasMagic) {
|
|
738
|
+
re = '(?=.)' + re
|
|
739
|
+
}
|
|
739
740
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
741
|
+
if (addPatternStart) {
|
|
742
|
+
re = patternStart + re
|
|
743
|
+
}
|
|
743
744
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
745
|
+
// parsing just a piece of a larger pattern.
|
|
746
|
+
if (isSub === SUBPARSE) {
|
|
747
|
+
return [re, hasMagic]
|
|
748
|
+
}
|
|
748
749
|
|
|
749
|
-
|
|
750
|
-
|
|
750
|
+
// skip the regexp for non-magical patterns
|
|
751
|
+
// unescape anything in it, though, so that it'll be
|
|
752
|
+
// an exact match against a file etc.
|
|
753
|
+
if (!hasMagic) {
|
|
754
|
+
return globUnescape(pattern)
|
|
755
|
+
}
|
|
751
756
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
757
|
+
const flags = options.nocase ? 'i' : ''
|
|
758
|
+
try {
|
|
759
|
+
return Object.assign(new RegExp('^' + re + '$', flags), {
|
|
760
|
+
_glob: pattern,
|
|
761
|
+
_src: re,
|
|
762
|
+
})
|
|
763
|
+
} catch (er) /* istanbul ignore next - should be impossible */ {
|
|
764
|
+
// If it was an invalid regular expression, then it can't match
|
|
765
|
+
// anything. This trick looks for a character after the end of
|
|
766
|
+
// the string, which is of course impossible, except in multi-line
|
|
767
|
+
// mode, but it's not a /m regex.
|
|
768
|
+
return new RegExp('$.')
|
|
769
|
+
}
|
|
758
770
|
}
|
|
759
771
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
772
|
+
makeRe () {
|
|
773
|
+
if (this.regexp || this.regexp === false) return this.regexp
|
|
774
|
+
|
|
775
|
+
// at this point, this.set is a 2d array of partial
|
|
776
|
+
// pattern strings, or "**".
|
|
777
|
+
//
|
|
778
|
+
// It's better to use .match(). This function shouldn't
|
|
779
|
+
// be used, really, but it's pretty convenient sometimes,
|
|
780
|
+
// when you just want to work with a regex.
|
|
781
|
+
const set = this.set
|
|
782
|
+
|
|
783
|
+
if (!set.length) {
|
|
784
|
+
this.regexp = false
|
|
785
|
+
return this.regexp
|
|
765
786
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
787
|
+
const options = this.options
|
|
788
|
+
|
|
789
|
+
const twoStar = options.noglobstar ? star
|
|
790
|
+
: options.dot ? twoStarDot
|
|
791
|
+
: twoStarNoDot
|
|
792
|
+
const flags = options.nocase ? 'i' : ''
|
|
793
|
+
|
|
794
|
+
let re = set.map(pattern =>
|
|
795
|
+
pattern.map(p =>
|
|
796
|
+
(p === GLOBSTAR) ? twoStar
|
|
797
|
+
: (typeof p === 'string') ? regExpEscape(p)
|
|
798
|
+
: p._src
|
|
799
|
+
).join('\\\/')
|
|
800
|
+
).join('|')
|
|
801
|
+
|
|
802
|
+
// must match entire pattern
|
|
803
|
+
// ending in a * or ** will make it less strict.
|
|
804
|
+
re = '^(?:' + re + ')$'
|
|
805
|
+
|
|
806
|
+
// can match anything, as long as it's not this.
|
|
807
|
+
if (this.negate) re = '^(?!' + re + ').*$'
|
|
808
|
+
|
|
809
|
+
try {
|
|
810
|
+
this.regexp = new RegExp(re, flags)
|
|
811
|
+
} catch (ex) /* istanbul ignore next - should be impossible */ {
|
|
812
|
+
this.regexp = false
|
|
770
813
|
}
|
|
814
|
+
return this.regexp
|
|
771
815
|
}
|
|
772
816
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
817
|
+
match (f, partial = this.partial) {
|
|
818
|
+
this.debug('match', f, this.pattern)
|
|
819
|
+
// short-circuit in the case of busted things.
|
|
820
|
+
// comments, etc.
|
|
821
|
+
if (this.comment) return false
|
|
822
|
+
if (this.empty) return f === ''
|
|
778
823
|
|
|
779
|
-
|
|
780
|
-
// "/a/b" matches the start of "/*/b/*/d"
|
|
781
|
-
// Partial means, if you run out of file before you run
|
|
782
|
-
// out of pattern, then that's fine, as long as all
|
|
783
|
-
// the parts match.
|
|
784
|
-
Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
|
785
|
-
var options = this.options
|
|
786
|
-
|
|
787
|
-
this.debug('matchOne',
|
|
788
|
-
{ 'this': this, file: file, pattern: pattern })
|
|
789
|
-
|
|
790
|
-
this.debug('matchOne', file.length, pattern.length)
|
|
791
|
-
|
|
792
|
-
for (var fi = 0,
|
|
793
|
-
pi = 0,
|
|
794
|
-
fl = file.length,
|
|
795
|
-
pl = pattern.length
|
|
796
|
-
; (fi < fl) && (pi < pl)
|
|
797
|
-
; fi++, pi++) {
|
|
798
|
-
this.debug('matchOne loop')
|
|
799
|
-
var p = pattern[pi]
|
|
800
|
-
var f = file[fi]
|
|
801
|
-
|
|
802
|
-
this.debug(pattern, p, f)
|
|
803
|
-
|
|
804
|
-
// should be impossible.
|
|
805
|
-
// some invalid regexp stuff in the set.
|
|
806
|
-
/* istanbul ignore if */
|
|
807
|
-
if (p === false) return false
|
|
808
|
-
|
|
809
|
-
if (p === GLOBSTAR) {
|
|
810
|
-
this.debug('GLOBSTAR', [pattern, p, f])
|
|
811
|
-
|
|
812
|
-
// "**"
|
|
813
|
-
// a/**/b/**/c would match the following:
|
|
814
|
-
// a/b/x/y/z/c
|
|
815
|
-
// a/x/y/z/b/c
|
|
816
|
-
// a/b/x/b/x/c
|
|
817
|
-
// a/b/c
|
|
818
|
-
// To do this, take the rest of the pattern after
|
|
819
|
-
// the **, and see if it would match the file remainder.
|
|
820
|
-
// If so, return success.
|
|
821
|
-
// If not, the ** "swallows" a segment, and try again.
|
|
822
|
-
// This is recursively awful.
|
|
823
|
-
//
|
|
824
|
-
// a/**/b/**/c matching a/b/x/y/z/c
|
|
825
|
-
// - a matches a
|
|
826
|
-
// - doublestar
|
|
827
|
-
// - matchOne(b/x/y/z/c, b/**/c)
|
|
828
|
-
// - b matches b
|
|
829
|
-
// - doublestar
|
|
830
|
-
// - matchOne(x/y/z/c, c) -> no
|
|
831
|
-
// - matchOne(y/z/c, c) -> no
|
|
832
|
-
// - matchOne(z/c, c) -> no
|
|
833
|
-
// - matchOne(c, c) yes, hit
|
|
834
|
-
var fr = fi
|
|
835
|
-
var pr = pi + 1
|
|
836
|
-
if (pr === pl) {
|
|
837
|
-
this.debug('** at the end')
|
|
838
|
-
// a ** at the end will just swallow the rest.
|
|
839
|
-
// We have found a match.
|
|
840
|
-
// however, it will not swallow /.x, unless
|
|
841
|
-
// options.dot is set.
|
|
842
|
-
// . and .. are *never* matched by **, for explosively
|
|
843
|
-
// exponential reasons.
|
|
844
|
-
for (; fi < fl; fi++) {
|
|
845
|
-
if (file[fi] === '.' || file[fi] === '..' ||
|
|
846
|
-
(!options.dot && file[fi].charAt(0) === '.')) return false
|
|
847
|
-
}
|
|
848
|
-
return true
|
|
849
|
-
}
|
|
824
|
+
if (f === '/' && partial) return true
|
|
850
825
|
|
|
851
|
-
|
|
852
|
-
while (fr < fl) {
|
|
853
|
-
var swallowee = file[fr]
|
|
826
|
+
const options = this.options
|
|
854
827
|
|
|
855
|
-
|
|
828
|
+
// windows: need to use /, not \
|
|
829
|
+
if (path.sep !== '/') {
|
|
830
|
+
f = f.split(path.sep).join('/')
|
|
831
|
+
}
|
|
856
832
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
// found a match.
|
|
861
|
-
return true
|
|
862
|
-
} else {
|
|
863
|
-
// can't swallow "." or ".." ever.
|
|
864
|
-
// can only swallow ".foo" when explicitly asked.
|
|
865
|
-
if (swallowee === '.' || swallowee === '..' ||
|
|
866
|
-
(!options.dot && swallowee.charAt(0) === '.')) {
|
|
867
|
-
this.debug('dot detected!', file, fr, pattern, pr)
|
|
868
|
-
break
|
|
869
|
-
}
|
|
833
|
+
// treat the test path as a set of pathparts.
|
|
834
|
+
f = f.split(slashSplit)
|
|
835
|
+
this.debug(this.pattern, 'split', f)
|
|
870
836
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
}
|
|
837
|
+
// just ONE of the pattern sets in this.set needs to match
|
|
838
|
+
// in order for it to be valid. If negating, then just one
|
|
839
|
+
// match means that we have failed.
|
|
840
|
+
// Either way, return on the first hit.
|
|
876
841
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
}
|
|
886
|
-
return false
|
|
842
|
+
const set = this.set
|
|
843
|
+
this.debug(this.pattern, 'set', set)
|
|
844
|
+
|
|
845
|
+
// Find the basename of the path by looking for the last non-empty segment
|
|
846
|
+
let filename
|
|
847
|
+
for (let i = f.length - 1; i >= 0; i--) {
|
|
848
|
+
filename = f[i]
|
|
849
|
+
if (filename) break
|
|
887
850
|
}
|
|
888
851
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
852
|
+
for (let i = 0; i < set.length; i++) {
|
|
853
|
+
const pattern = set[i]
|
|
854
|
+
let file = f
|
|
855
|
+
if (options.matchBase && pattern.length === 1) {
|
|
856
|
+
file = [filename]
|
|
857
|
+
}
|
|
858
|
+
const hit = this.matchOne(file, pattern, partial)
|
|
859
|
+
if (hit) {
|
|
860
|
+
if (options.flipNegate) return true
|
|
861
|
+
return !this.negate
|
|
898
862
|
}
|
|
899
|
-
this.debug('string match', p, f, hit)
|
|
900
|
-
} else {
|
|
901
|
-
hit = f.match(p)
|
|
902
|
-
this.debug('pattern match', p, f, hit)
|
|
903
863
|
}
|
|
904
864
|
|
|
905
|
-
if
|
|
865
|
+
// didn't get any hits. this is success if it's a negative
|
|
866
|
+
// pattern, failure otherwise.
|
|
867
|
+
if (options.flipNegate) return false
|
|
868
|
+
return this.negate
|
|
906
869
|
}
|
|
907
870
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
// corresponding "" at the end of the file.
|
|
911
|
-
// If the file ends in /, then it can only match a
|
|
912
|
-
// a pattern that ends in /, unless the pattern just
|
|
913
|
-
// doesn't have any more for it. But, a/b/ should *not*
|
|
914
|
-
// match "a/b/*", even though "" matches against the
|
|
915
|
-
// [^/]*? pattern, except in partial mode, where it might
|
|
916
|
-
// simply not be reached yet.
|
|
917
|
-
// However, a/b/ should still satisfy a/*
|
|
918
|
-
|
|
919
|
-
// now either we fell off the end of the pattern, or we're done.
|
|
920
|
-
if (fi === fl && pi === pl) {
|
|
921
|
-
// ran out of pattern and filename at the same time.
|
|
922
|
-
// an exact hit!
|
|
923
|
-
return true
|
|
924
|
-
} else if (fi === fl) {
|
|
925
|
-
// ran out of file, but still had pattern left.
|
|
926
|
-
// this is ok if we're doing the match as part of
|
|
927
|
-
// a glob fs traversal.
|
|
928
|
-
return partial
|
|
929
|
-
} else /* istanbul ignore else */ if (pi === pl) {
|
|
930
|
-
// ran out of pattern, still have file left.
|
|
931
|
-
// this is only acceptable if we're on the very last
|
|
932
|
-
// empty segment of a file with a trailing slash.
|
|
933
|
-
// a/* should match a/b/
|
|
934
|
-
return (fi === fl - 1) && (file[fi] === '')
|
|
871
|
+
static defaults (def) {
|
|
872
|
+
return minimatch.defaults(def).Minimatch
|
|
935
873
|
}
|
|
936
|
-
|
|
937
|
-
// should be unreachable.
|
|
938
|
-
/* istanbul ignore next */
|
|
939
|
-
throw new Error('wtf?')
|
|
940
874
|
}
|
|
941
875
|
|
|
942
|
-
|
|
943
|
-
function globUnescape (s) {
|
|
944
|
-
return s.replace(/\\(.)/g, '$1')
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
function regExpEscape (s) {
|
|
948
|
-
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
|
|
949
|
-
}
|
|
876
|
+
minimatch.Minimatch = Minimatch
|