1
1
module . exports = minimatch
2
2
minimatch . Minimatch = Minimatch
3
3
4
- var path = { sep : '/' }
5
- try {
6
- path = require ( 'path' )
7
- } catch ( er ) { }
4
+ var path = ( function ( ) { try { return require ( 'path' ) } catch ( e ) { } } ( ) ) || {
5
+ sep : '/'
6
+ }
7
+ minimatch . sep = path . sep
8
8
9
9
var GLOBSTAR = minimatch . GLOBSTAR = Minimatch . GLOBSTAR = { }
10
10
var expand = require ( 'brace-expansion' )
@@ -56,43 +56,64 @@ function filter (pattern, options) {
56
56
}
57
57
58
58
function ext ( a , b ) {
59
- a = a || { }
60
59
b = b || { }
61
60
var t = { }
62
- Object . keys ( b ) . forEach ( function ( k ) {
63
- t [ k ] = b [ k ]
64
- } )
65
61
Object . keys ( a ) . forEach ( function ( k ) {
66
62
t [ k ] = a [ k ]
67
63
} )
64
+ Object . keys ( b ) . forEach ( function ( k ) {
65
+ t [ k ] = b [ k ]
66
+ } )
68
67
return t
69
68
}
70
69
71
70
minimatch . defaults = function ( def ) {
72
- if ( ! def || ! Object . keys ( def ) . length ) return minimatch
71
+ if ( ! def || typeof def !== 'object' || ! Object . keys ( def ) . length ) {
72
+ return minimatch
73
+ }
73
74
74
75
var orig = minimatch
75
76
76
77
var m = function minimatch ( p , pattern , options ) {
77
- return orig . minimatch ( p , pattern , ext ( def , options ) )
78
+ return orig ( p , pattern , ext ( def , options ) )
78
79
}
79
80
80
81
m . Minimatch = function Minimatch ( pattern , options ) {
81
82
return new orig . Minimatch ( pattern , ext ( def , options ) )
82
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
+ }
95
+
96
+ m . makeRe = function makeRe ( pattern , options ) {
97
+ return orig . makeRe ( pattern , ext ( def , options ) )
98
+ }
99
+
100
+ m . braceExpand = function braceExpand ( pattern , options ) {
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 ) )
106
+ }
83
107
84
108
return m
85
109
}
86
110
87
111
Minimatch . defaults = function ( def ) {
88
- if ( ! def || ! Object . keys ( def ) . length ) return Minimatch
89
112
return minimatch . defaults ( def ) . Minimatch
90
113
}
91
114
92
115
function minimatch ( p , pattern , options ) {
93
- if ( typeof pattern !== 'string' ) {
94
- throw new TypeError ( 'glob pattern string required' )
95
- }
116
+ assertValidPattern ( pattern )
96
117
97
118
if ( ! options ) options = { }
98
119
@@ -101,9 +122,6 @@ function minimatch (p, pattern, options) {
101
122
return false
102
123
}
103
124
104
- // "" only matches ""
105
- if ( pattern . trim ( ) === '' ) return p === ''
106
-
107
125
return new Minimatch ( pattern , options ) . match ( p )
108
126
}
109
127
@@ -112,15 +130,14 @@ function Minimatch (pattern, options) {
112
130
return new Minimatch ( pattern , options )
113
131
}
114
132
115
- if ( typeof pattern !== 'string' ) {
116
- throw new TypeError ( 'glob pattern string required' )
117
- }
133
+ assertValidPattern ( pattern )
118
134
119
135
if ( ! options ) options = { }
136
+
120
137
pattern = pattern . trim ( )
121
138
122
139
// windows support: need to use /, not \
123
- if ( path . sep !== '/' ) {
140
+ if ( ! options . allowWindowsEscape && path . sep !== '/' ) {
124
141
pattern = pattern . split ( path . sep ) . join ( '/' )
125
142
}
126
143
@@ -131,6 +148,7 @@ function Minimatch (pattern, options) {
131
148
this . negate = false
132
149
this . comment = false
133
150
this . empty = false
151
+ this . partial = ! ! options . partial
134
152
135
153
// make the set of regexps etc.
136
154
this . make ( )
@@ -140,9 +158,6 @@ Minimatch.prototype.debug = function () {}
140
158
141
159
Minimatch . prototype . make = make
142
160
function make ( ) {
143
- // don't do it more than once.
144
- if ( this . _made ) return
145
-
146
161
var pattern = this . pattern
147
162
var options = this . options
148
163
@@ -162,7 +177,7 @@ function make () {
162
177
// step 2: expand braces
163
178
var set = this . globSet = this . braceExpand ( )
164
179
165
- if ( options . debug ) this . debug = console . error
180
+ if ( options . debug ) this . debug = function debug ( ) { console . error . apply ( console , arguments ) }
166
181
167
182
this . debug ( this . pattern , set )
168
183
@@ -242,19 +257,29 @@ function braceExpand (pattern, options) {
242
257
pattern = typeof pattern === 'undefined'
243
258
? this . pattern : pattern
244
259
245
- if ( typeof pattern === 'undefined' ) {
246
- throw new TypeError ( 'undefined pattern' )
247
- }
260
+ assertValidPattern ( pattern )
248
261
249
- if ( options . nobrace ||
250
- ! pattern . match ( / \{ .* \} / ) ) {
262
+ // Thanks to Yeting Li <https://github.com/yetingli> for
263
+ // improving this regexp to avoid a ReDOS vulnerability.
264
+ if ( options . nobrace || ! / \{ (?: (? ! \{ ) .) * \} / . test ( pattern ) ) {
251
265
// shortcut. no need to expand.
252
266
return [ pattern ]
253
267
}
254
268
255
269
return expand ( pattern )
256
270
}
257
271
272
+ var MAX_PATTERN_LENGTH = 1024 * 64
273
+ var assertValidPattern = function ( pattern ) {
274
+ if ( typeof pattern !== 'string' ) {
275
+ throw new TypeError ( 'invalid pattern' )
276
+ }
277
+
278
+ if ( pattern . length > MAX_PATTERN_LENGTH ) {
279
+ throw new TypeError ( 'pattern is too long' )
280
+ }
281
+ }
282
+
258
283
// parse a component of the expanded set.
259
284
// At this point, no pattern may contain "/" in it
260
285
// so we're going to return a 2d array, where each entry is the full
@@ -269,14 +294,17 @@ function braceExpand (pattern, options) {
269
294
Minimatch . prototype . parse = parse
270
295
var SUBPARSE = { }
271
296
function parse ( pattern , isSub ) {
272
- if ( pattern . length > 1024 * 64 ) {
273
- throw new TypeError ( 'pattern is too long' )
274
- }
297
+ assertValidPattern ( pattern )
275
298
276
299
var options = this . options
277
300
278
301
// shortcuts
279
- if ( ! options . noglobstar && pattern === '**' ) return GLOBSTAR
302
+ if ( pattern === '**' ) {
303
+ if ( ! options . noglobstar )
304
+ return GLOBSTAR
305
+ else
306
+ pattern = '*'
307
+ }
280
308
if ( pattern === '' ) return ''
281
309
282
310
var re = ''
@@ -332,10 +360,12 @@ function parse (pattern, isSub) {
332
360
}
333
361
334
362
switch ( c ) {
335
- case '/' :
363
+ /* istanbul ignore next */
364
+ case '/' : {
336
365
// completely not allowed, even escaped.
337
366
// Should already be path-split by now.
338
367
return false
368
+ }
339
369
340
370
case '\\' :
341
371
clearStateChar ( )
@@ -454,25 +484,23 @@ function parse (pattern, isSub) {
454
484
455
485
// handle the case where we left a class open.
456
486
// "[z-a]" is valid, equivalent to "\[z-a\]"
457
- if ( inClass ) {
458
- // split where the last [ was, make sure we don't have
459
- // an invalid re. if so, re-walk the contents of the
460
- // would-be class to re-translate any characters that
461
- // were passed through as-is
462
- // TODO: It would probably be faster to determine this
463
- // without a try/catch and a new RegExp, but it's tricky
464
- // to do safely. For now, this is safe and works.
465
- var cs = pattern . substring ( classStart + 1 , i )
466
- try {
467
- RegExp ( '[' + cs + ']' )
468
- } catch ( er ) {
469
- // not a valid class!
470
- var sp = this . parse ( cs , SUBPARSE )
471
- re = re . substr ( 0 , reClassStart ) + '\\[' + sp [ 0 ] + '\\]'
472
- hasMagic = hasMagic || sp [ 1 ]
473
- inClass = false
474
- continue
475
- }
487
+ // split where the last [ was, make sure we don't have
488
+ // an invalid re. if so, re-walk the contents of the
489
+ // would-be class to re-translate any characters that
490
+ // were passed through as-is
491
+ // TODO: It would probably be faster to determine this
492
+ // without a try/catch and a new RegExp, but it's tricky
493
+ // to do safely. For now, this is safe and works.
494
+ var cs = pattern . substring ( classStart + 1 , i )
495
+ try {
496
+ RegExp ( '[' + cs + ']' )
497
+ } catch ( er ) {
498
+ // not a valid class!
499
+ var sp = this . parse ( cs , SUBPARSE )
500
+ re = re . substr ( 0 , reClassStart ) + '\\[' + sp [ 0 ] + '\\]'
501
+ hasMagic = hasMagic || sp [ 1 ]
502
+ inClass = false
503
+ continue
476
504
}
477
505
478
506
// finish up the class.
@@ -556,9 +584,7 @@ function parse (pattern, isSub) {
556
584
// something that could conceivably capture a dot
557
585
var addPatternStart = false
558
586
switch ( re . charAt ( 0 ) ) {
559
- case '.' :
560
- case '[' :
561
- case '(' : addPatternStart = true
587
+ case '[' : case '.' : case '(' : addPatternStart = true
562
588
}
563
589
564
590
// Hack to work around lack of negative lookbehind in JS
@@ -620,7 +646,7 @@ function parse (pattern, isSub) {
620
646
var flags = options . nocase ? 'i' : ''
621
647
try {
622
648
var regExp = new RegExp ( '^' + re + '$' , flags )
623
- } catch ( er ) {
649
+ } catch ( er ) /* istanbul ignore next - should be impossible */ {
624
650
// If it was an invalid regular expression, then it can't match
625
651
// anything. This trick looks for a character after the end of
626
652
// the string, which is of course impossible, except in multi-line
@@ -678,7 +704,7 @@ function makeRe () {
678
704
679
705
try {
680
706
this . regexp = new RegExp ( re , flags )
681
- } catch ( ex ) {
707
+ } catch ( ex ) /* istanbul ignore next - should be impossible */ {
682
708
this . regexp = false
683
709
}
684
710
return this . regexp
@@ -696,8 +722,8 @@ minimatch.match = function (list, pattern, options) {
696
722
return list
697
723
}
698
724
699
- Minimatch . prototype . match = match
700
- function match ( f , partial ) {
725
+ Minimatch . prototype . match = function match ( f , partial ) {
726
+ if ( typeof partial === 'undefined' ) partial = this . partial
701
727
this . debug ( 'match' , f , this . pattern )
702
728
// short-circuit in the case of busted things.
703
729
// comments, etc.
@@ -779,6 +805,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
779
805
780
806
// should be impossible.
781
807
// some invalid regexp stuff in the set.
808
+ /* istanbul ignore if */
782
809
if ( p === false ) return false
783
810
784
811
if ( p === GLOBSTAR ) {
@@ -852,6 +879,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
852
879
// no match was found.
853
880
// However, in partial mode, we can't say this is necessarily over.
854
881
// If there's more *pattern* left, then
882
+ /* istanbul ignore if */
855
883
if ( partial ) {
856
884
// ran out of file
857
885
this . debug ( '\n>>> no match, partial?' , file , fr , pattern , pr )
@@ -865,11 +893,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
865
893
// patterns with magic have been turned into regexps.
866
894
var hit
867
895
if ( typeof p === 'string' ) {
868
- if ( options . nocase ) {
869
- hit = f . toLowerCase ( ) === p . toLowerCase ( )
870
- } else {
871
- hit = f === p
872
- }
896
+ hit = f === p
873
897
this . debug ( 'string match' , p , f , hit )
874
898
} else {
875
899
hit = f . match ( p )
@@ -900,16 +924,16 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
900
924
// this is ok if we're doing the match as part of
901
925
// a glob fs traversal.
902
926
return partial
903
- } else if ( pi === pl ) {
927
+ } else /* istanbul ignore else */ if ( pi === pl ) {
904
928
// ran out of pattern, still have file left.
905
929
// this is only acceptable if we're on the very last
906
930
// empty segment of a file with a trailing slash.
907
931
// a/* should match a/b/
908
- var emptyFileEnd = ( fi === fl - 1 ) && ( file [ fi ] === '' )
909
- return emptyFileEnd
932
+ return ( fi === fl - 1 ) && ( file [ fi ] === '' )
910
933
}
911
934
912
935
// should be unreachable.
936
+ /* istanbul ignore next */
913
937
throw new Error ( 'wtf?' )
914
938
}
915
939
0 commit comments