minimatch 3.0.3 → 3.1.0

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.
Files changed (3) hide show
  1. package/README.md +22 -1
  2. package/minimatch.js +92 -66
  3. package/package.json +10 -6
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A minimal matching utility.
4
4
 
5
- [![Build Status](https://secure.travis-ci.org/isaacs/minimatch.svg)](http://travis-ci.org/isaacs/minimatch)
5
+ [![Build Status](https://travis-ci.org/isaacs/minimatch.svg?branch=master)](http://travis-ci.org/isaacs/minimatch)
6
6
 
7
7
 
8
8
  This is the matching library used internally by npm.
@@ -171,6 +171,27 @@ Suppress the behavior of treating a leading `!` character as negation.
171
171
  Returns from negate expressions the same as if they were not negated.
172
172
  (Ie, true on a hit, false on a miss.)
173
173
 
174
+ ### partial
175
+
176
+ Compare a partial path to a pattern. As long as the parts of the path that
177
+ are present are not contradicted by the pattern, it will be treated as a
178
+ match. This is useful in applications where you're walking through a
179
+ folder structure, and don't yet have the full path, but want to ensure that
180
+ you do not walk down paths that can never be a match.
181
+
182
+ For example,
183
+
184
+ ```js
185
+ minimatch('/a/b', '/a/*/c/d', { partial: true }) // true, might be /a/b/c/d
186
+ minimatch('/a/b', '/**/d', { partial: true }) // true, might be /a/b/.../d
187
+ minimatch('/x/y/z', '/a/**/z', { partial: true }) // false, because x !== a
188
+ ```
189
+
190
+ ### allowWindowsEscape
191
+
192
+ Windows path separator `\` is by default converted to `/`, which
193
+ prohibits the usage of `\` as a escape character. This flag skips that
194
+ behavior and allows using the escape character.
174
195
 
175
196
  ## Comparisons to other fnmatch/glob implementations
176
197
 
package/minimatch.js CHANGED
@@ -1,10 +1,10 @@
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,12 @@ 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 = {}
120
- pattern = pattern.trim()
121
136
 
122
137
  // windows support: need to use /, not \
123
- if (path.sep !== '/') {
138
+ if (!options.allowWindowsEscape && path.sep !== '/') {
124
139
  pattern = pattern.split(path.sep).join('/')
125
140
  }
126
141
 
@@ -131,6 +146,7 @@ function Minimatch (pattern, options) {
131
146
  this.negate = false
132
147
  this.comment = false
133
148
  this.empty = false
149
+ this.partial = !!options.partial
134
150
 
135
151
  // make the set of regexps etc.
136
152
  this.make()
@@ -140,9 +156,6 @@ Minimatch.prototype.debug = function () {}
140
156
 
141
157
  Minimatch.prototype.make = make
142
158
  function make () {
143
- // don't do it more than once.
144
- if (this._made) return
145
-
146
159
  var pattern = this.pattern
147
160
  var options = this.options
148
161
 
@@ -162,7 +175,7 @@ function make () {
162
175
  // step 2: expand braces
163
176
  var set = this.globSet = this.braceExpand()
164
177
 
165
- if (options.debug) this.debug = console.error
178
+ if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
166
179
 
167
180
  this.debug(this.pattern, set)
168
181
 
@@ -242,12 +255,11 @@ function braceExpand (pattern, options) {
242
255
  pattern = typeof pattern === 'undefined'
243
256
  ? this.pattern : pattern
244
257
 
245
- if (typeof pattern === 'undefined') {
246
- throw new TypeError('undefined pattern')
247
- }
258
+ assertValidPattern(pattern)
248
259
 
249
- if (options.nobrace ||
250
- !pattern.match(/\{.*\}/)) {
260
+ // Thanks to Yeting Li <https://github.com/yetingli> for
261
+ // improving this regexp to avoid a ReDOS vulnerability.
262
+ if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
251
263
  // shortcut. no need to expand.
252
264
  return [pattern]
253
265
  }
@@ -255,6 +267,17 @@ function braceExpand (pattern, options) {
255
267
  return expand(pattern)
256
268
  }
257
269
 
270
+ var MAX_PATTERN_LENGTH = 1024 * 64
271
+ var assertValidPattern = function (pattern) {
272
+ if (typeof pattern !== 'string') {
273
+ throw new TypeError('invalid pattern')
274
+ }
275
+
276
+ if (pattern.length > MAX_PATTERN_LENGTH) {
277
+ throw new TypeError('pattern is too long')
278
+ }
279
+ }
280
+
258
281
  // parse a component of the expanded set.
259
282
  // At this point, no pattern may contain "/" in it
260
283
  // so we're going to return a 2d array, where each entry is the full
@@ -269,18 +292,21 @@ function braceExpand (pattern, options) {
269
292
  Minimatch.prototype.parse = parse
270
293
  var SUBPARSE = {}
271
294
  function parse (pattern, isSub) {
272
- if (pattern.length > 1024 * 64) {
273
- throw new TypeError('pattern is too long')
274
- }
295
+ assertValidPattern(pattern)
275
296
 
276
297
  var options = this.options
277
298
 
278
299
  // shortcuts
279
- if (!options.noglobstar && pattern === '**') return GLOBSTAR
300
+ if (pattern === '**') {
301
+ if (!options.noglobstar)
302
+ return GLOBSTAR
303
+ else
304
+ pattern = '*'
305
+ }
280
306
  if (pattern === '') return ''
281
307
 
282
308
  var re = ''
283
- var hasMagic = !!options.nocase
309
+ var hasMagic = false
284
310
  var escaping = false
285
311
  // ? => one single character
286
312
  var patternListStack = []
@@ -332,10 +358,12 @@ function parse (pattern, isSub) {
332
358
  }
333
359
 
334
360
  switch (c) {
335
- case '/':
361
+ /* istanbul ignore next */
362
+ case '/': {
336
363
  // completely not allowed, even escaped.
337
364
  // Should already be path-split by now.
338
365
  return false
366
+ }
339
367
 
340
368
  case '\\':
341
369
  clearStateChar()
@@ -454,25 +482,23 @@ function parse (pattern, isSub) {
454
482
 
455
483
  // handle the case where we left a class open.
456
484
  // "[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
- }
485
+ // split where the last [ was, make sure we don't have
486
+ // an invalid re. if so, re-walk the contents of the
487
+ // would-be class to re-translate any characters that
488
+ // were passed through as-is
489
+ // TODO: It would probably be faster to determine this
490
+ // without a try/catch and a new RegExp, but it's tricky
491
+ // to do safely. For now, this is safe and works.
492
+ var cs = pattern.substring(classStart + 1, i)
493
+ try {
494
+ RegExp('[' + cs + ']')
495
+ } catch (er) {
496
+ // not a valid class!
497
+ var sp = this.parse(cs, SUBPARSE)
498
+ re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
499
+ hasMagic = hasMagic || sp[1]
500
+ inClass = false
501
+ continue
476
502
  }
477
503
 
478
504
  // finish up the class.
@@ -556,9 +582,7 @@ function parse (pattern, isSub) {
556
582
  // something that could conceivably capture a dot
557
583
  var addPatternStart = false
558
584
  switch (re.charAt(0)) {
559
- case '.':
560
- case '[':
561
- case '(': addPatternStart = true
585
+ case '[': case '.': case '(': addPatternStart = true
562
586
  }
563
587
 
564
588
  // Hack to work around lack of negative lookbehind in JS
@@ -620,7 +644,7 @@ function parse (pattern, isSub) {
620
644
  var flags = options.nocase ? 'i' : ''
621
645
  try {
622
646
  var regExp = new RegExp('^' + re + '$', flags)
623
- } catch (er) {
647
+ } catch (er) /* istanbul ignore next - should be impossible */ {
624
648
  // If it was an invalid regular expression, then it can't match
625
649
  // anything. This trick looks for a character after the end of
626
650
  // the string, which is of course impossible, except in multi-line
@@ -678,7 +702,7 @@ function makeRe () {
678
702
 
679
703
  try {
680
704
  this.regexp = new RegExp(re, flags)
681
- } catch (ex) {
705
+ } catch (ex) /* istanbul ignore next - should be impossible */ {
682
706
  this.regexp = false
683
707
  }
684
708
  return this.regexp
@@ -696,8 +720,8 @@ minimatch.match = function (list, pattern, options) {
696
720
  return list
697
721
  }
698
722
 
699
- Minimatch.prototype.match = match
700
- function match (f, partial) {
723
+ Minimatch.prototype.match = function match (f, partial) {
724
+ if (typeof partial === 'undefined') partial = this.partial
701
725
  this.debug('match', f, this.pattern)
702
726
  // short-circuit in the case of busted things.
703
727
  // comments, etc.
@@ -779,6 +803,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
779
803
 
780
804
  // should be impossible.
781
805
  // some invalid regexp stuff in the set.
806
+ /* istanbul ignore if */
782
807
  if (p === false) return false
783
808
 
784
809
  if (p === GLOBSTAR) {
@@ -852,6 +877,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
852
877
  // no match was found.
853
878
  // However, in partial mode, we can't say this is necessarily over.
854
879
  // If there's more *pattern* left, then
880
+ /* istanbul ignore if */
855
881
  if (partial) {
856
882
  // ran out of file
857
883
  this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
@@ -900,16 +926,16 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
900
926
  // this is ok if we're doing the match as part of
901
927
  // a glob fs traversal.
902
928
  return partial
903
- } else if (pi === pl) {
929
+ } else /* istanbul ignore else */ if (pi === pl) {
904
930
  // ran out of pattern, still have file left.
905
931
  // this is only acceptable if we're on the very last
906
932
  // empty segment of a file with a trailing slash.
907
933
  // a/* should match a/b/
908
- var emptyFileEnd = (fi === fl - 1) && (file[fi] === '')
909
- return emptyFileEnd
934
+ return (fi === fl - 1) && (file[fi] === '')
910
935
  }
911
936
 
912
937
  // should be unreachable.
938
+ /* istanbul ignore next */
913
939
  throw new Error('wtf?')
914
940
  }
915
941
 
package/package.json CHANGED
@@ -2,25 +2,29 @@
2
2
  "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
3
3
  "name": "minimatch",
4
4
  "description": "a glob matcher in javascript",
5
- "version": "3.0.3",
5
+ "version": "3.1.0",
6
+ "publishConfig": {
7
+ "tag": "v3-legacy"
8
+ },
6
9
  "repository": {
7
10
  "type": "git",
8
11
  "url": "git://github.com/isaacs/minimatch.git"
9
12
  },
10
13
  "main": "minimatch.js",
11
14
  "scripts": {
12
- "posttest": "standard minimatch.js test/*.js",
13
- "test": "tap test/*.js"
15
+ "test": "tap",
16
+ "preversion": "npm test",
17
+ "postversion": "npm publish",
18
+ "postpublish": "git push origin --all; git push origin --tags"
14
19
  },
15
20
  "engines": {
16
21
  "node": "*"
17
22
  },
18
23
  "dependencies": {
19
- "brace-expansion": "^1.0.0"
24
+ "brace-expansion": "^1.1.7"
20
25
  },
21
26
  "devDependencies": {
22
- "standard": "^3.7.2",
23
- "tap": "^5.6.0"
27
+ "tap": "^15.1.6"
24
28
  },
25
29
  "license": "ISC",
26
30
  "files": [