Skip to content

Commit

Permalink
Fix bug with escaped '@' in patterns
Browse files Browse the repository at this point in the history
For example,

```js
  minimatch('@', '\\@*')
```

was returns `false` when `true` expected

Close: isaacs#110
  • Loading branch information
litmit authored and isaacs committed Feb 15, 2022
1 parent dd7aa95 commit 3b1ceaa
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 11 deletions.
25 changes: 14 additions & 11 deletions minimatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,16 +472,23 @@ class Minimatch {
this.debug('%s\t%s %s %j', pattern, i, re, c)

// skip over any that are escaped.
if (escaping && reSpecials[c]) {
re += '\\' + c
if (escaping) {
/* istanbul ignore next - completely not allowed, even escaped. */
if (c === '/') {
return false
}

if (reSpecials[c]) {
re += '\\'
}
re += c
escaping = false
continue
}

switch (c) {
/* istanbul ignore next */
case '/': {
// completely not allowed, even escaped.
// Should already be path-split by now.
return false
}
Expand Down Expand Up @@ -564,9 +571,8 @@ class Minimatch {
continue

case '|':
if (inClass || !patternListStack.length || escaping) {
if (inClass || !patternListStack.length) {
re += '\\|'
escaping = false
continue
}

Expand Down Expand Up @@ -597,7 +603,6 @@ class Minimatch {
// first in the list. -- POSIX.2 2.8.3.2
if (i === classStart + 1 || !inClass) {
re += '\\' + c
escaping = false
continue
}

Expand Down Expand Up @@ -632,15 +637,12 @@ class Minimatch {
// swallow any state char that wasn't consumed
clearStateChar()

if (escaping) {
// no need
escaping = false
} else if (reSpecials[c]
&& !(c === '^' && inClass)) {
if (reSpecials[c] && !(c === '^' && inClass)) {
re += '\\'
}

re += c
break

} // switch
} // for
Expand Down Expand Up @@ -670,6 +672,7 @@ class Minimatch {
this.debug('setting tail', re, pl)
// maybe some even number of \, then maybe 1 \, followed by a |
tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => {
/* istanbul ignore else - should already be done */
if (!$2) {
// the | isn't already escaped, so escape it.
$2 = '\\'
Expand Down
44 changes: 44 additions & 0 deletions test/escaping.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
var tap = require('tap')
var minimatch = require('../')

// test all characters with codes in range [mincc,maxcc]
var mincc = 0x20
var maxcc = 0xFF
// except listed in exceptions array
var exceptions = ['/', '\\']
var pre = 'x' // prepended to the testable character
var post = 'y' // appended to the testable character

function escapeChar (cc) {
return '"\\u' + ('000' + cc.toString(16).toUpperCase()).substr(-4) + '"'
}

tap.test('escaping tests', function (t) {
for (var cc = mincc; cc <= maxcc; ++cc) {
var cp = String.fromCharCode(cc)
if (exceptions.indexOf(cp) === -1) {
var str = pre + cp + post
var pattern = '*\\' + cp + '*'
var msg = JSON.stringify(str) +
' (for codepoint ' + escapeChar(cc) + ')' +
' should match pattern ' + JSON.stringify(pattern)
t.equal(minimatch(str, pattern), true, msg)
}
}
t.end()
})

tap.test('class escaping tests', function (t) {
for (var cc = mincc; cc <= maxcc; ++cc) {
var cp = String.fromCharCode(cc)
if (exceptions.indexOf(cp) === -1) {
var str = pre + cp + post
var pattern = '*[\\' + cp + ']*'
var msg = JSON.stringify(str) +
' (for codepoint ' + escapeChar(cc) + ')' +
' should match pattern ' + JSON.stringify(pattern)
t.equal(minimatch(str, pattern), true, msg)
}
}
t.end()
})

0 comments on commit 3b1ceaa

Please sign in to comment.