Skip to content

Commit ecabc57

Browse files
committed
Do not throw on unfinished !( extglob patterns
There were some magic numbers that assumed that every extglob pattern starts and ends with a specific number of characters in the regular expression. Since !(||) patterns are a little bit more complicated, this led to creating an invalid regular expression and throwing. Fixes isaacs/node-glob#278
1 parent 81edb7c commit ecabc57

File tree

2 files changed

+32
-20
lines changed

2 files changed

+32
-20
lines changed

minimatch.js

+19-20
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ try {
99
var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
1010
var expand = require('brace-expansion')
1111

12+
var plTypes = {
13+
'!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
14+
'?': { open: '(?:', close: ')?' },
15+
'+': { open: '(?:', close: ')+' },
16+
'*': { open: '(?:', close: ')*' },
17+
'@': { open: '(?:', close: ')' }
18+
}
19+
1220
// any single thing other than /
1321
// don't need to escape / when using new RegExp()
1422
var qmark = '[^/]'
@@ -277,7 +285,6 @@ function parse (pattern, isSub) {
277285
// ? => one single character
278286
var patternListStack = []
279287
var negativeLists = []
280-
var plType
281288
var stateChar
282289
var inClass = false
283290
var reClassStart = -1
@@ -376,11 +383,12 @@ function parse (pattern, isSub) {
376383
continue
377384
}
378385

379-
plType = stateChar
380386
patternListStack.push({
381-
type: plType,
387+
type: stateChar,
382388
start: i - 1,
383-
reStart: re.length
389+
reStart: re.length,
390+
open: plTypes[stateChar].open,
391+
close: plTypes[stateChar].close
384392
})
385393
// negation is (?:(?!js)[^/]*)
386394
re += stateChar === '!' ? '(?:(?!(?:' : '(?:'
@@ -396,24 +404,14 @@ function parse (pattern, isSub) {
396404

397405
clearStateChar()
398406
hasMagic = true
399-
re += ')'
400407
var pl = patternListStack.pop()
401-
plType = pl.type
402408
// negation is (?:(?!js)[^/]*)
403409
// The others are (?:<pattern>)<type>
404-
switch (plType) {
405-
case '!':
406-
negativeLists.push(pl)
407-
re += ')[^/]*?)'
408-
pl.reEnd = re.length
409-
break
410-
case '?':
411-
case '+':
412-
case '*':
413-
re += plType
414-
break
415-
case '@': break // the default anyway
410+
re += pl.close
411+
if (pl.type === '!') {
412+
negativeLists.push(pl)
416413
}
414+
pl.reEnd = re.length
417415
continue
418416

419417
case '|':
@@ -520,7 +518,8 @@ function parse (pattern, isSub) {
520518
// Go through and escape them, taking care not to double-escape any
521519
// | chars that were already escaped.
522520
for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
523-
var tail = re.slice(pl.reStart + 3)
521+
var tail = re.slice(pl.reStart + pl.open.length)
522+
this.debug('setting tail', re, pl)
524523
// maybe some even number of \, then maybe 1 \, followed by a |
525524
tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) {
526525
if (!$2) {
@@ -537,7 +536,7 @@ function parse (pattern, isSub) {
537536
return $1 + $1 + $2 + '|'
538537
})
539538

540-
this.debug('tail=%j\n %s', tail, tail)
539+
this.debug('tail=%j\n %s', tail, tail, pl, re)
541540
var t = pl.type === '*' ? star
542541
: pl.type === '?' ? qmark
543542
: '\\' + pl.type

test/extglob-unfinished.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
var t = require('tap')
2+
var mm = require('../')
3+
4+
var types = '!?+*@'.split('')
5+
6+
t.plan(types.length)
7+
types.forEach(function (type) {
8+
t.test(type, function (t) {
9+
t.plan(2)
10+
t.ok(mm(type + '(a|B', type + '(a|B', { nonegate: true }))
11+
t.notOk(mm(type + '(a|B', 'B', { nonegate: true }))
12+
})
13+
})

0 commit comments

Comments
 (0)