diff --git a/.eslintrc.json b/.eslintrc.json index ba84ad6..2613cd2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -62,7 +62,7 @@ "no-irregular-whitespace": 2, "no-iterator": 2, "no-label-var": 2, - "no-labels": 2, + "no-labels": 0, "no-lone-blocks": 2, "no-lonely-if": 2, "no-mixed-spaces-and-tabs": 2, diff --git a/README.md b/README.md index 5062654..6924c81 100644 --- a/README.md +++ b/README.md @@ -474,6 +474,8 @@ isMatch('bar'); isMatch('baz'); ``` +Return `picomatch.constants.UNIGNORE` from `onIgnore` to un-ignore the result. + #### options.onResult ```js diff --git a/lib/constants.js b/lib/constants.js index 27b3e20..c46b4d9 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -3,6 +3,8 @@ const WIN_SLASH = '\\\\/'; const WIN_NO_SLASH = `[^${WIN_SLASH}]`; +const UNIGNORE = Symbol('unignore'); + /** * Posix glob regex */ @@ -89,6 +91,9 @@ module.exports = { MAX_LENGTH: 1024 * 64, POSIX_REGEX_SOURCE, + // token to un-ignore results in onIgnore + UNIGNORE, + // regular expressions REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g, REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/, diff --git a/lib/picomatch.js b/lib/picomatch.js index d0ebd9f..89cc744 100644 --- a/lib/picomatch.js +++ b/lib/picomatch.js @@ -75,12 +75,17 @@ const picomatch = (glob, options, returnState = false) => { return returnObject ? result : false; } - if (isIgnored(input)) { - if (typeof opts.onIgnore === 'function') { - opts.onIgnore(result); + ignored: { + if (isIgnored(input)) { + if (typeof opts.onIgnore === 'function') { + if (opts.onIgnore(result) === constants.UNIGNORE) { + result.isMatch = true; + break ignored; + } + } + result.isMatch = false; + return returnObject ? result : false; } - result.isMatch = false; - return returnObject ? result : false; } if (typeof opts.onMatch === 'function') { diff --git a/test/options.onIgnore.js b/test/options.onIgnore.js new file mode 100644 index 0000000..064a2a2 --- /dev/null +++ b/test/options.onIgnore.js @@ -0,0 +1,69 @@ +'use strict'; + +const assert = require('assert'); +const match = require('./support/match'); +const picomatch = require('..'); +const { isMatch } = picomatch; + +const equal = (actual, expected, msg) => { + assert.deepStrictEqual([].concat(actual).sort(), [].concat(expected).sort(), msg); +}; + +describe('options.onIgnore', () => { + it('should call options.onIgnore on each ignored string', () => { + const ignored = []; + + const options = { + ignore: ['b/*', 'b/*/*'], + onIgnore({ pattern, regex, input, output }) { + ignored.push(input); + } + }; + + const fixtures = ['a', 'b', 'b/a', 'b/b', 'b/a/a']; + + equal(match(fixtures, '**', options), ['a', 'b']); + equal(ignored.length, 3); + }); + + it('should allow to un-ignore from options.onIgnore', () => { + const options = (ignore, unignore) => { + return { + ignore, + onIgnore({ pattern, regex, input, output }) { + if (unignore) return isMatch(input, unignore) && picomatch.constants.UNIGNORE; + } + }; + }; + + const fixtures = ['a', 'b', 'b/a', 'b/b', 'b/a/a']; + + equal(match(fixtures, '**', options(['b/*', 'b/*/*'])), ['a', 'b']); + equal(match(fixtures, '**', options(['b/*', 'b/*/*'], ['b/a'])), ['a', 'b', 'b/a']); + equal(match(fixtures, '**', options(['b/*', 'b/*/*'], ['b/a/a'])), ['a', 'b', 'b/a/a']); + equal(match(fixtures, '**', options(['b/*', 'b/*/*'], ['b/*'])), ['a', 'b', 'b/a', 'b/b']); + equal(match(fixtures, '**', options(['b/*', 'b/*/*'], ['*/a'])), ['a', 'b', 'b/a']); + equal(match(fixtures, '**', options([], ['**'])), ['a', 'b', 'b/a', 'b/b', 'b/a/a']); + }); + + it('should call onMatch for un-ignored results', () => { + const patterns = []; + + const options = (ignore, unignore) => { + return { + ignore, + onIgnore({ pattern, regex, input, output }) { + if (unignore) return isMatch(input, unignore) && picomatch.constants.UNIGNORE; + }, + onMatch({ pattern, regex, input, output }, matches) { + patterns.push(output); + } + }; + }; + + const fixtures = ['a', 'b', 'b/a', 'b/b', 'b/a/a']; + + equal(match(fixtures, '**', options(['b/a**'], ['b/a/a'])), ['a', 'b', 'b/b', 'b/a/a']); + equal(patterns, ['a', 'b', 'b/b', 'b/a/a']); + }); +});