From 1a14fd523aca65b7614d5635c654475efc0ccfc2 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Sun, 4 Sep 2016 02:48:05 -0400 Subject: [PATCH 01/68] run update --- .editorconfig | 13 ++----------- .gitignore | 23 +++++++++++++++-------- .travis.yml | 2 ++ LICENSE | 2 +- package.json | 19 +++++++++++++++++-- 5 files changed, 37 insertions(+), 22 deletions(-) mode change 100755 => 100644 .gitignore diff --git a/.editorconfig b/.editorconfig index 408d8707..818e0724 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,3 @@ -# http://editorconfig.org root = true [*] @@ -9,14 +8,6 @@ indent_size = 2 trim_trailing_whitespace = true insert_final_newline = true -[*.md] +[{**/{actual,fixtures,expected,templates}/**,*.md}] trim_trailing_whitespace = false -insert_final_newline = false - -[**/{actual,fixtures,expected}/**] -trim_trailing_whitespace = false -insert_final_newline = false - -[**/templates/**] -trim_trailing_whitespace = false -insert_final_newline = false +insert_final_newline = false \ No newline at end of file diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 index d44a263a..79881544 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,21 @@ +# always ignore files +*.DS_Store *.sublime-* -_gh_pages -bower_components + +# test related, or directories generated by tests +test/actual +actual +coverage + +# npm node_modules npm-debug.log + +# misc +_gh_pages +benchmark +bower_components +vendor temp tmp TODO.md -vendor -*.DS_Store -staging -wip -test/bash -coverage diff --git a/.travis.yml b/.travis.yml index 76003c36..3932eaa2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,4 +9,6 @@ node_js: matrix: fast_finish: true allow_failures: + - node_js: '4' - node_js: '0.10' + - node_js: '0.12' diff --git a/LICENSE b/LICENSE index fa30c4cb..842218cf 100755 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2015, Jon Schlinkert. +Copyright (c) 2014-2016, Jon Schlinkert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/package.json b/package.json index f2aef5b1..640a3d11 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,18 @@ "version": "2.3.11", "homepage": "https://github.com/jonschlinkert/micromatch", "author": "Jon Schlinkert (https://github.com/jonschlinkert)", + "contributors": [ + "Amila Welihinda (http://amilawelihinda.com)", + "Bogdan Chadkin (https://github.com/TrySound)", + "Brian Woodward (https://github.com/doowb)", + "Charlike Mike Reagent (http://www.tunnckocore.tk)", + "Elan Shanker (https://github.com/es128)", + "Fabrício Matté (http://ultcombo.js.org)", + "Jon Schlinkert (http://twitter.com/jonschlinkert)", + "Martin Kolárik (http://kolarik.sk)", + "Paul Miller (paulmillr.com)", + "Tom Byrer (https://github.com/tomByrer)" + ], "repository": "jonschlinkert/micromatch", "bugs": { "url": "https://github.com/jonschlinkert/micromatch/issues" @@ -11,7 +23,9 @@ "license": "MIT", "files": [ "index.js", - "lib" + "lib", + "LICENSE", + "README.md" ], "main": "index.js", "engines": { @@ -67,6 +81,7 @@ "matcher", "matches", "matching", + "micromatch", "minimatch", "multimatch", "path", @@ -111,4 +126,4 @@ "reflinks": true } } -} +} \ No newline at end of file From 93a6cbeb5c3bf23a99aa82a163f908571809f99c Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Wed, 7 Sep 2016 00:37:03 -0400 Subject: [PATCH 02/68] start refactoring to parser/compiler --- benchmark/check.js | 25 -- benchmark/code/micromatch.js | 3 - benchmark/code/minimatch.js | 12 - benchmark/index.js | 33 +- examples/extglob.js | 8 + examples/parser.js | 10 + examples/source-map.js | 7 + index.js | 564 ++++++++++++++++------------------- lib/chars.js | 67 ----- lib/compilers.js | 27 ++ lib/expand.js | 304 ------------------- lib/glob.js | 193 ------------ lib/micromatch.js | 99 ++++++ lib/parsers.js | 38 +++ lib/utils.js | 190 ++++++------ package.json | 30 +- roadmap.md | 9 + test/any.js | 333 ++++++++++----------- test/bash-extglob.js | 96 ------ test/bash.js | 122 -------- test/braces.js | 186 ------------ test/brackets.js | 242 +++++++++++++++ test/character-classes.js | 27 -- test/contains.js | 340 +++++++++++---------- test/dotfiles.js | 164 ++++------ test/expand.js | 59 ---- test/extglob-char-class.js | 38 --- test/extglob.js | 68 ----- test/extglob1a.js | 161 ---------- test/extglobs.js | 332 +++++++++++++++++++++ test/filter.js | 64 ---- test/glob.js | 120 -------- test/globstars.js | 20 ++ test/isMatch.js | 361 +++++++++++----------- test/issue-related.js | 34 +++ test/makeRe.js | 247 --------------- test/match.js | 222 -------------- test/matchKeys.js | 45 --- test/matcher.js | 90 ------ test/micromatch.js | 255 ---------------- test/minimatch/basic.js | 2 +- test/minimatch/defaults.js | 2 +- test/minimatch/temp.js | 2 +- test/negation.js | 81 ++--- test/options.js | 158 ---------- test/pattern-string.js | 245 --------------- test/posix-brackets.js | 55 ---- test/qmarks.js | 31 ++ test/reference/index.js | 1 + test/reference/matcher.js | 11 + test/reference/negations.js | 107 +++++++ test/regex.js | 31 -- test/special-chars.js | 81 ----- test/support/cc.sh | 35 +++ test/support/dotglob.sh | 44 +++ test/support/extglob.sh | 342 +++++++++++++++++++++ test/support/glob.sh | 101 +++++++ test/support/globstar.sh | 51 ++++ test/support/negation.sh | 34 +++ test/support/run.js | 39 +++ test/support/spawn.js | 37 +++ test/t3070-wildmatch.js | 181 ----------- test/utils.js | 73 ----- 63 files changed, 2630 insertions(+), 4359 deletions(-) delete mode 100644 benchmark/check.js delete mode 100755 benchmark/code/micromatch.js delete mode 100755 benchmark/code/minimatch.js create mode 100644 examples/extglob.js create mode 100644 examples/parser.js create mode 100644 examples/source-map.js mode change 100755 => 100644 index.js delete mode 100644 lib/chars.js create mode 100644 lib/compilers.js delete mode 100644 lib/expand.js delete mode 100644 lib/glob.js create mode 100644 lib/micromatch.js create mode 100644 lib/parsers.js create mode 100644 roadmap.md delete mode 100644 test/bash-extglob.js delete mode 100644 test/bash.js delete mode 100644 test/braces.js create mode 100644 test/brackets.js delete mode 100644 test/character-classes.js delete mode 100644 test/expand.js delete mode 100644 test/extglob-char-class.js delete mode 100644 test/extglob.js delete mode 100644 test/extglob1a.js create mode 100644 test/extglobs.js delete mode 100644 test/filter.js delete mode 100644 test/glob.js create mode 100644 test/globstars.js create mode 100644 test/issue-related.js delete mode 100644 test/makeRe.js delete mode 100644 test/match.js delete mode 100644 test/matchKeys.js delete mode 100644 test/matcher.js delete mode 100644 test/micromatch.js delete mode 100644 test/options.js delete mode 100644 test/pattern-string.js delete mode 100644 test/posix-brackets.js create mode 100644 test/qmarks.js create mode 100644 test/reference/index.js create mode 100644 test/reference/matcher.js create mode 100644 test/reference/negations.js delete mode 100644 test/regex.js delete mode 100644 test/special-chars.js create mode 100644 test/support/cc.sh create mode 100644 test/support/dotglob.sh create mode 100644 test/support/extglob.sh create mode 100644 test/support/glob.sh create mode 100644 test/support/globstar.sh create mode 100644 test/support/negation.sh create mode 100644 test/support/run.js create mode 100644 test/support/spawn.js delete mode 100644 test/t3070-wildmatch.js delete mode 100644 test/utils.js diff --git a/benchmark/check.js b/benchmark/check.js deleted file mode 100644 index 7fbb2b17..00000000 --- a/benchmark/check.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var chalk = require('chalk'); -var path = require('path'); -var mm = require('..'); - -/** - * Sanity check. run to ensure that all fns return a correct - * result. - */ - -fs.readdirSync(__dirname + '/code').forEach(function (fp) { - if (mm.isMatch(fp, 'micromatch.js')) { - var fn = require(path.resolve(__dirname, 'code', fp)); - var name = path.basename(fp, path.extname(fp)); - - fs.readdirSync(__dirname + '/fixtures').forEach(function (fixture) { - if (mm.isMatch(fixture, 'large.js')) { - fixture = path.resolve(__dirname, 'fixtures', fixture); - console.log(chalk.bold(name) + ':', fn.apply(null, require(fixture))); - } - }); - } -}); diff --git a/benchmark/code/micromatch.js b/benchmark/code/micromatch.js deleted file mode 100755 index 0f85e827..00000000 --- a/benchmark/code/micromatch.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; - -module.exports = require('../..'); \ No newline at end of file diff --git a/benchmark/code/minimatch.js b/benchmark/code/minimatch.js deleted file mode 100755 index 41be0976..00000000 --- a/benchmark/code/minimatch.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - - -var minimatch = require('minimatch').match; -var multimatch = require('multimatch'); - -module.exports = function (files, patterns, options) { - if (Array.isArray(patterns)) { - return multimatch(files, patterns, options); - } - return minimatch(files, patterns, options); -}; \ No newline at end of file diff --git a/benchmark/index.js b/benchmark/index.js index ed80d2b3..d52932ef 100755 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -1,11 +1,28 @@ 'use strict'; +var path = require('path'); +var util = require('util'); +var cyan = require('ansi-cyan'); +var argv = require('yargs-parser')(process.argv.slice(2)); var Suite = require('benchmarked'); -var suite = new Suite({ - result: false, - fixtures: 'fixtures/*.js', - add: 'code/*.js', - cwd: __dirname -}); - -suite.run(); + +function run(type) { + var suite = new Suite({ + cwd: __dirname, + fixtures: path.join('fixtures', type, '*.js'), + code: path.join('code', type, '*.js') + }); + + if (argv.dry) { + suite.dryRun(function(code, fixture) { + console.log(cyan('%s > %s'), code.key, fixture.key); + var args = require(fixture.path); + console.log(util.inspect(code.run(args), null, 10)); + console.log(); + }); + } else { + suite.run(); + } +} + +run(argv._[0] || 'match'); diff --git a/examples/extglob.js b/examples/extglob.js new file mode 100644 index 00000000..26ecc08a --- /dev/null +++ b/examples/extglob.js @@ -0,0 +1,8 @@ +'use strict'; + +var nanomatch = require('..'); +var pattern = '*(*(of*(a)x)z)'; + +var res = nanomatch(pattern); +console.log(res.ast.nodes); +console.log(res); diff --git a/examples/parser.js b/examples/parser.js new file mode 100644 index 00000000..aed7531d --- /dev/null +++ b/examples/parser.js @@ -0,0 +1,10 @@ +'use strict'; + +var parsers = require('../lib/parsers'); +var Extglob = require('../lib/extglob'); +var extglob = new Extglob(); +extglob.use(parsers); + +var pattern = '*(*(of*(a)x)z)'; +var res = extglob.parse(pattern); +console.log(res); diff --git a/examples/source-map.js b/examples/source-map.js new file mode 100644 index 00000000..106f97c9 --- /dev/null +++ b/examples/source-map.js @@ -0,0 +1,7 @@ +'use strict'; + +var extglob = require('..'); +var pattern = '*(*(of*(a)x)z)'; + +var res = extglob(pattern, {sourcemap: true}); +console.log(res); diff --git a/index.js b/index.js old mode 100755 new mode 100644 index f898ec17..51ce7a68 --- a/index.js +++ b/index.js @@ -1,218 +1,128 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - 'use strict'; -var expand = require('./lib/expand'); +var path = require('path'); +var util = require('util'); +var debug = require('debug')('micromatch'); +var Micromatch = require('./lib/micromatch'); +var compilers = require('./lib/compilers'); +var parsers = require('./lib/parsers'); var utils = require('./lib/utils'); +var regexCache = {}; /** - * The main function. Pass an array of filepaths, - * and a string or array of glob patterns + * Convert the given glob `pattern` into a regex-compatible string. * - * @param {Array|String} `files` - * @param {Array|String} `patterns` - * @param {Object} `opts` - * @return {Array} Array of matches + * ```js + * var micromatch = require('micromatch'); + * var str = micromatch('*.js'); + * console.log(str); + * ``` + * @param {String} `str` + * @param {Object} `options` + * @return {String} + * @api public */ -function micromatch(files, patterns, opts) { - if (!files || !patterns) return []; - opts = opts || {}; - - if (typeof opts.cache === 'undefined') { - opts.cache = true; - } - - if (!Array.isArray(patterns)) { - return match(files, patterns, opts); - } - - var len = patterns.length, i = 0; - var omit = [], keep = []; - - while (len--) { - var glob = patterns[i++]; - if (typeof glob === 'string' && glob.charCodeAt(0) === 33 /* ! */) { - omit.push.apply(omit, match(files, glob.slice(1), opts)); - } else { - keep.push.apply(keep, match(files, glob, opts)); - } - } - return utils.diff(keep, omit); +function micromatch(str, options) { + var matcher = new Micromatch(options); + var ast = matcher.parse(str, options); + return matcher.compile(ast, options); } /** - * Return an array of files that match the given glob pattern. - * - * This function is called by the main `micromatch` function If you only - * need to pass a single pattern you might get very minor speed improvements - * using this function. + * Takes an array of strings and a glob pattern and returns a new + * array that contains only the strings that match the pattern. * - * @param {Array} `files` - * @param {String} `pattern` - * @param {Object} `options` + * ```js + * var nano = require('micromatch'); + * console.log(nano.match(['a.a', 'a.b', 'a.c'], '*.!(*a)')); + * //=> ['a.b', 'a.c'] + * ``` + * @param {Array} `arr` Array of strings to match + * @param {String} `pattern` Glob pattern + * @param {Object} `options` * @return {Array} + * @api public */ -function match(files, pattern, opts) { - if (utils.typeOf(files) !== 'string' && !Array.isArray(files)) { - throw new Error(msg('match', 'files', 'a string or array')); - } +micromatch.match = function(files, pattern, options) { + var opts = utils.extend({}, options); + var isMatch = micromatch.matcher(pattern, opts); + var unixify = utils.unixify(opts); + var matches = []; files = utils.arrayify(files); - opts = opts || {}; - - var negate = opts.negate || false; - var orig = pattern; + var len = files.length; + var idx = -1; - if (typeof pattern === 'string') { - negate = pattern.charAt(0) === '!'; - if (negate) { - pattern = pattern.slice(1); + while (++idx < len) { + var file = unixify(files[idx]); + if (isMatch(file)) { + matches.push(file); } - - // we need to remove the character regardless, - // so the above logic is still needed - if (opts.nonegate === true) { - negate = false; - } - } - - var _isMatch = matcher(pattern, opts); - var len = files.length, i = 0; - var res = []; - - while (i < len) { - var file = files[i++]; - var fp = utils.unixify(file, opts); - - if (!_isMatch(fp)) { continue; } - res.push(fp); } - if (res.length === 0) { + if (matches.length === 0) { if (opts.failglob === true) { - throw new Error('micromatch.match() found no matches for: "' + orig + '".'); + throw new Error('no matches found for "' + pattern + '"'); } - - if (opts.nonull || opts.nullglob) { - res.push(utils.unescapeGlob(orig)); + if (opts.nonull === true || opts.nullglob === true) { + return [pattern.split('\\').join('')]; } } - // if `negate` was defined, diff negated files - if (negate) { res = utils.diff(files, res); } - - // if `ignore` was defined, diff ignored filed - if (opts.ignore && opts.ignore.length) { - pattern = opts.ignore; - opts = utils.omit(opts, ['ignore']); - res = utils.diff(res, micromatch(res, pattern, opts)); + // if `ignore` was defined, diff ignored files + if (opts.ignore) { + var ignore = utils.arrayify(opts.ignore); + delete opts.ignore; + var ignored = micromatch.matchEach(matches, ignore, opts); + matches = utils.diff(matches, ignored); } - - if (opts.nodupes) { - return utils.unique(res); - } - return res; -} + return opts.nodupes ? utils.unique(matches) : matches; +}; /** - * Returns a function that takes a glob pattern or array of glob patterns - * to be used with `Array#filter()`. (Internally this function generates - * the matching function using the [matcher] method). + * Takes an array of strings and a one or more glob patterns and returns a new + * array with strings that match any of the given patterns. * * ```js - * var fn = mm.filter('[a-c]'); - * ['a', 'b', 'c', 'd', 'e'].filter(fn); - * //=> ['a', 'b', 'c'] + * var nano = require('micromatch'); + * console.log(nano.matchEach(['a.a', 'a.b', 'a.c'], ['*.!(*a)'])); + * //=> ['a.b', 'a.c'] * ``` - * @param {String|Array} `patterns` Can be a glob or array of globs. - * @param {Options} `opts` Options to pass to the [matcher] method. - * @return {Function} Filter function to be passed to `Array#filter()`. - */ - -function filter(patterns, opts) { - if (!Array.isArray(patterns) && typeof patterns !== 'string') { - throw new TypeError(msg('filter', 'patterns', 'a string or array')); - } - - patterns = utils.arrayify(patterns); - var len = patterns.length, i = 0; - var patternMatchers = Array(len); - while (i < len) { - patternMatchers[i] = matcher(patterns[i++], opts); - } - - return function(fp) { - if (fp == null) return []; - var len = patternMatchers.length, i = 0; - var res = true; - - fp = utils.unixify(fp, opts); - while (i < len) { - var fn = patternMatchers[i++]; - if (!fn(fp)) { - res = false; - break; - } - } - return res; - }; -} - -/** - * Returns true if the filepath contains the given - * pattern. Can also return a function for matching. - * - * ```js - * isMatch('foo.md', '*.md', {}); - * //=> true - * - * isMatch('*.md', {})('foo.md') - * //=> true - * ``` - * @param {String} `fp` - * @param {String} `pattern` - * @param {Object} `opts` - * @return {Boolean} + * @param {Array} `arr` Array of strings to match + * @param {String} `pattern` Glob pattern + * @param {Object} `options` + * @return {Array} + * @api public */ -function isMatch(fp, pattern, opts) { - if (typeof fp !== 'string') { - throw new TypeError(msg('isMatch', 'filepath', 'a string')); +micromatch.matchEach = function(files, patterns, options) { + if (!Array.isArray(files)) { + return []; } - fp = utils.unixify(fp, opts); - if (utils.typeOf(pattern) === 'object') { - return matcher(fp, pattern); + if (!Array.isArray(patterns)) { + return micromatch.match.apply(micromatch, arguments); } - return matcher(pattern, opts)(fp); -} -/** - * Returns true if the filepath matches the - * given pattern. - */ - -function contains(fp, pattern, opts) { - if (typeof fp !== 'string') { - throw new TypeError(msg('contains', 'pattern', 'a string')); - } + var opts = utils.extend({cache: true}, options); + var omit = []; + var keep = []; - opts = opts || {}; - opts.contains = (pattern !== ''); - fp = utils.unixify(fp, opts); + var len = patterns.length; + var idx = -1; - if (opts.contains && !utils.isGlob(pattern)) { - return fp.indexOf(pattern) !== -1; + while (++idx < len) { + var pattern = patterns[idx]; + if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) { + omit.push.apply(omit, micromatch.match(files, pattern.slice(1), opts)); + } else { + keep.push.apply(keep, micromatch.match(files, pattern, opts)); + } } - return matcher(pattern, opts)(fp); -} + return utils.diff(keep, omit); +}; /** * Returns true if a file path matches any of the @@ -224,208 +134,234 @@ function contains(fp, pattern, opts) { * @return {String} */ -function any(fp, patterns, opts) { +micromatch.any = function(filepath, patterns, options) { if (!Array.isArray(patterns) && typeof patterns !== 'string') { - throw new TypeError(msg('any', 'patterns', 'a string or array')); + throw new TypeError('expected patterns to be a string or array'); } + var unixify = utils.unixify(opts); + var opts = utils.extend({}, options); + patterns = utils.arrayify(patterns); + filepath = unixify(filepath); var len = patterns.length; - fp = utils.unixify(fp, opts); - while (len--) { - var isMatch = matcher(patterns[len], opts); - if (isMatch(fp)) { + for (var i = 0; i < len; i++) { + var pattern = patterns[i]; + if (!utils.isString(pattern)) { + continue; + } + + if (!utils.isGlob(pattern)) { + if (filepath === pattern) { + return true; + } + if (opts.contains && filepath.indexOf(pattern) !== -1) { + return true; + } + continue; + } + + if (micromatch.isMatch(filepath, pattern, opts)) { return true; } } return false; -} +}; + +/** + * Returns true if the filepath matches the + * given pattern. + */ + +micromatch.contains = function(filepath, pattern, options) { + if (typeof filepath !== 'string') { + throw new TypeError('expected filepath to be a string'); + } + if (typeof pattern !== 'string') { + throw new TypeError('expected pattern to be a string'); + } + + var opts = utils.extend({contains: pattern !== ''}, options); + opts.strictClose = false; + opts.strictOpen = false; + + if (opts.contains && !utils.isGlob(pattern)) { + filepath = utils.unixify(opts)(filepath); + return filepath.indexOf(pattern) !== -1; + } + return micromatch.matcher(pattern, opts)(filepath); +}; /** - * Filter the keys of an object with the given `glob` pattern - * and `options` + * Returns true if the specified `string` matches the given + * glob `pattern`. * - * @param {Object} `object` - * @param {Pattern} `object` - * @return {Array} + * ```js + * var nano = require('micromatch'); + * + * console.log(nano.isMatch('a.a', '*.!(*a)')); + * //=> false + * console.log(nano.isMatch('a.b', '*.!(*a)')); + * //=> true + * ``` + * @param {String} `string` String to match + * @param {String} `pattern` Glob pattern + * @param {String} `options` + * @return {Boolean} + * @api public */ -function matchKeys(obj, glob, options) { - if (utils.typeOf(obj) !== 'object') { - throw new TypeError(msg('matchKeys', 'first argument', 'an object')); +micromatch.isMatch = function(filepath, pattern, options) { + if (pattern === '' || pattern === ' ') { + return filepath === pattern; } - var fn = matcher(glob, options); - var res = {}; + if (typeof pattern !== 'string') { + throw new TypeError('expected pattern to be a string'); + } - for (var key in obj) { - if (obj.hasOwnProperty(key) && fn(key)) { - res[key] = obj[key]; - } + var opts = utils.extend({}, options); + if (micromatch.matchBase(pattern, opts)) { + filepath = path.basename(filepath); + + } else if (opts.extname === true) { + filepath = path.extname(filepath); + + } else if (opts.dirname === true) { + filepath = path.dirname(filepath); } - return res; -} + + var re = micromatch.makeRe(pattern, utils.extend({prepend: false}, opts)); + return re.test(filepath); +}; /** - * Return a function for matching based on the - * given `pattern` and `options`. + * Takes a glob pattern and returns a matcher function. The returned + * function takes the string to match as its only argument. * - * @param {String} `pattern` - * @param {Object} `options` - * @return {Function} + * ```js + * var nano = require('micromatch'); + * var isMatch = micromatch.matcher('*.!(*a)'); + * + * console.log(isMatch('a.a')); + * //=> false + * console.log(isMatch('a.b')); + * //=> true + * ``` + * @param {String} `pattern` Glob pattern + * @param {String} `options` + * @return {Boolean} + * @api public */ -function matcher(pattern, opts) { +micromatch.matcher = function(pattern, options) { // pattern is a function if (typeof pattern === 'function') { return pattern; } + + var opts = utils.extend({}, options); + var unixify = utils.unixify(opts); + // pattern is a regex if (pattern instanceof RegExp) { return function(fp) { - return pattern.test(fp); + return pattern.test(unixify(fp)); }; } if (typeof pattern !== 'string') { - throw new TypeError(msg('matcher', 'pattern', 'a string, regex, or function')); + throw new TypeError('expected pattern to be a string, regex or function'); } - // strings, all the way down... - pattern = utils.unixify(pattern, opts); - - // pattern is a non-glob string - if (!utils.isGlob(pattern)) { - return utils.matchPath(pattern, opts); + // pattern is an empty string, only match an empty string. + if (pattern === '') { + return function(fp) { + return fp === pattern; + } } + // pattern is a glob string - var re = makeRe(pattern, opts); + var re = micromatch.makeRe(pattern, utils.extend({prepend: false}, opts)); // `matchBase` is defined - if (opts && opts.matchBase) { - return utils.hasFilename(re, opts); + if (micromatch.matchBase(pattern, options)) { + return utils.matchBasename(re); } + // `matchBase` is not defined return function(fp) { - fp = utils.unixify(fp, opts); - return re.test(fp); + return re.test(unixify(fp)); }; -} +}; /** - * Create and cache a regular expression for matching - * file paths. - * - * If the leading character in the `glob` is `!`, a negation - * regex is returned. - * - * @param {String} `glob` - * @param {Object} `options` - * @return {RegExp} - */ - -function toRegex(glob, options) { - // clone options to prevent mutating the original object - var opts = Object.create(options || {}); - var flags = opts.flags || ''; - if (opts.nocase && flags.indexOf('i') === -1) { - flags += 'i'; - } - - var parsed = expand(glob, opts); - - // pass in tokens to avoid parsing more than once - opts.negated = opts.negated || parsed.negated; - opts.negate = opts.negated; - glob = wrapGlob(parsed.pattern, opts); - var re; - - try { - re = new RegExp(glob, flags); - return re; - } catch (err) { - err.reason = 'micromatch invalid regex: (' + re + ')'; - if (opts.strict) throw new SyntaxError(err); - } - - // we're only here if a bad pattern was used and the user - // passed `options.silent`, so match nothing - return /$^/; -} - -/** - * Create the regex to do the matching. If the leading - * character in the `glob` is `!` a negation regex is returned. - * - * @param {String} `glob` - * @param {Boolean} `negate` + * Returns true if the given pattern and options should enable + * the `matchBase` option. + * @return {Boolean} */ -function wrapGlob(glob, opts) { - var prefix = (opts && !opts.contains) ? '^' : ''; - var after = (opts && !opts.contains) ? '$' : ''; - glob = ('(?:' + glob + ')' + after); - if (opts && opts.negate) { - return prefix + ('(?!^' + glob + ').*$'); - } - return prefix + glob; -} +micromatch.matchBase = function(pattern, options) { + if (pattern && pattern.indexOf('/') !== -1 || !options) return false; + return options.basename === true + || options.matchBase === true; +}; /** - * Create and cache a regular expression for matching file paths. - * If the leading character in the `glob` is `!`, a negation - * regex is returned. + * Create a regular expression from the given string `pattern`. * - * @param {String} `glob` - * @param {Object} `options` + * ```js + * var micromatch = require('micromatch'); + * var re = micromatch.makeRe('[[:alpha:]]'); + * console.log(re); + * //=> /^(?:[a-zA-Z])$/ + * ``` + * @param {String} `pattern` The pattern to convert to regex. + * @param {Object} `options` * @return {RegExp} + * @api public */ -function makeRe(glob, opts) { - if (utils.typeOf(glob) !== 'string') { - throw new Error(msg('makeRe', 'glob', 'a string')); +micromatch.makeRe = function(pattern, options) { + if (!pattern) return /$^/; + var key = pattern; + var regex; + + if (options) { + for (var prop in options) { + if (options.hasOwnProperty(prop)) { + key += ';' + prop + '=' + String(options[prop]); + } + } } - return utils.cache(toRegex, glob, opts); -} -/** - * Make error messages consistent. Follows this format: - * - * ```js - * msg(methodName, argNumber, nativeType); - * // example: - * msg('matchKeys', 'first', 'an object'); - * ``` - * - * @param {String} `method` - * @param {String} `num` - * @param {String} `type` - * @return {String} - */ + options = options || {}; + if (pattern.charAt(0) === '^') { + pattern = pattern.slice(1); + options.strictOpen = true; + } -function msg(method, what, type) { - return 'micromatch.' + method + '(): ' + what + ' should be ' + type + '.'; -} + if (pattern[pattern.length - 1] === '$') { + pattern = pattern.slice(0, pattern.length -1); + options.strictClose = true; + } -/** - * Public methods - */ + if (options.cache !== false && regexCache.hasOwnProperty(key)) { + return regexCache[key]; + } -/* eslint no-multi-spaces: 0 */ -micromatch.any = any; -micromatch.braces = micromatch.braceExpand = utils.braces; -micromatch.contains = contains; -micromatch.expand = expand; -micromatch.filter = filter; -micromatch.isMatch = isMatch; -micromatch.makeRe = makeRe; -micromatch.match = match; -micromatch.matcher = matcher; -micromatch.matchKeys = matchKeys; + var mm = new Micromatch(options); + regex = regexCache[key] = mm.makeRe(pattern, options); + return regex; +}; /** - * Expose `micromatch` + * Expose `Micromatch` constructor + * @type {Function} */ module.exports = micromatch; +module.exports.Micromatch = Micromatch; +module.exports.compilers = compilers; +module.exports.parsers = parsers; diff --git a/lib/chars.js b/lib/chars.js deleted file mode 100644 index a1ffe371..00000000 --- a/lib/chars.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -var chars = {}, unesc, temp; - -function reverse(object, prepender) { - return Object.keys(object).reduce(function(reversed, key) { - var newKey = prepender ? prepender + key : key; // Optionally prepend a string to key. - reversed[object[key]] = newKey; // Swap key and value. - return reversed; // Return the result. - }, {}); -} - -/** - * Regex for common characters - */ - -chars.escapeRegex = { - '?': /\?/g, - '@': /\@/g, - '!': /\!/g, - '+': /\+/g, - '*': /\*/g, - '(': /\(/g, - ')': /\)/g, - '[': /\[/g, - ']': /\]/g -}; - -/** - * Escape characters - */ - -chars.ESC = { - '?': '__UNESC_QMRK__', - '@': '__UNESC_AMPE__', - '!': '__UNESC_EXCL__', - '+': '__UNESC_PLUS__', - '*': '__UNESC_STAR__', - ',': '__UNESC_COMMA__', - '(': '__UNESC_LTPAREN__', - ')': '__UNESC_RTPAREN__', - '[': '__UNESC_LTBRACK__', - ']': '__UNESC_RTBRACK__' -}; - -/** - * Unescape characters - */ - -chars.UNESC = unesc || (unesc = reverse(chars.ESC, '\\')); - -chars.ESC_TEMP = { - '?': '__TEMP_QMRK__', - '@': '__TEMP_AMPE__', - '!': '__TEMP_EXCL__', - '*': '__TEMP_STAR__', - '+': '__TEMP_PLUS__', - ',': '__TEMP_COMMA__', - '(': '__TEMP_LTPAREN__', - ')': '__TEMP_RTPAREN__', - '[': '__TEMP_LTBRACK__', - ']': '__TEMP_RTBRACK__' -}; - -chars.TEMP = temp || (temp = reverse(chars.ESC_TEMP)); - -module.exports = chars; diff --git a/lib/compilers.js b/lib/compilers.js new file mode 100644 index 00000000..142b1efe --- /dev/null +++ b/lib/compilers.js @@ -0,0 +1,27 @@ +'use strict'; + +var nanomatch = require('nanomatch'); +var brackets = require('expand-brackets'); +var extglob = require('extglob'); + +module.exports = function(micromatch) { + + /** + * Compiler plugins + */ + + micromatch.use(nanomatch.compilers); + if (micromatch.options.brackets !== false) { + micromatch.use(brackets.compilers); + } + if (micromatch.options.extglob !== false) { + micromatch.use(extglob.compilers); + } + + /** + * Micromatch compilers + */ + + // micromatch.compiler + +}; diff --git a/lib/expand.js b/lib/expand.js deleted file mode 100644 index e99b081e..00000000 --- a/lib/expand.js +++ /dev/null @@ -1,304 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -var utils = require('./utils'); -var Glob = require('./glob'); - -/** - * Expose `expand` - */ - -module.exports = expand; - -/** - * Expand a glob pattern to resolve braces and - * similar patterns before converting to regex. - * - * @param {String|Array} `pattern` - * @param {Array} `files` - * @param {Options} `opts` - * @return {Array} - */ - -function expand(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('micromatch.expand(): argument should be a string.'); - } - - var glob = new Glob(pattern, options || {}); - var opts = glob.options; - - if (!utils.isGlob(pattern)) { - glob.pattern = glob.pattern.replace(/([\/.])/g, '\\$1'); - return glob; - } - - glob.pattern = glob.pattern.replace(/(\+)(?!\()/g, '\\$1'); - glob.pattern = glob.pattern.split('$').join('\\$'); - - if (typeof opts.braces !== 'boolean' && typeof opts.nobraces !== 'boolean') { - opts.braces = true; - } - - if (glob.pattern === '.*') { - return { - pattern: '\\.' + star, - tokens: tok, - options: opts - }; - } - - if (glob.pattern === '*') { - return { - pattern: oneStar(opts.dot), - tokens: tok, - options: opts - }; - } - - // parse the glob pattern into tokens - glob.parse(); - var tok = glob.tokens; - tok.is.negated = opts.negated; - - // dotfile handling - if ((opts.dotfiles === true || tok.is.dotfile) && opts.dot !== false) { - opts.dotfiles = true; - opts.dot = true; - } - - if ((opts.dotdirs === true || tok.is.dotdir) && opts.dot !== false) { - opts.dotdirs = true; - opts.dot = true; - } - - // check for braces with a dotfile pattern - if (/[{,]\./.test(glob.pattern)) { - opts.makeRe = false; - opts.dot = true; - } - - if (opts.nonegate !== true) { - opts.negated = glob.negated; - } - - // if the leading character is a dot or a slash, escape it - if (glob.pattern.charAt(0) === '.' && glob.pattern.charAt(1) !== '/') { - glob.pattern = '\\' + glob.pattern; - } - - /** - * Extended globs - */ - - // expand braces, e.g `{1..5}` - glob.track('before braces'); - if (tok.is.braces) { - glob.braces(); - } - glob.track('after braces'); - - // expand extglobs, e.g `foo/!(a|b)` - glob.track('before extglob'); - if (tok.is.extglob) { - glob.extglob(); - } - glob.track('after extglob'); - - // expand brackets, e.g `[[:alpha:]]` - glob.track('before brackets'); - if (tok.is.brackets) { - glob.brackets(); - } - glob.track('after brackets'); - - // special patterns - glob._replace('[!', '[^'); - glob._replace('(?', '(%~'); - glob._replace(/\[\]/, '\\[\\]'); - glob._replace('/[', '/' + (opts.dot ? dotfiles : nodot) + '[', true); - glob._replace('/?', '/' + (opts.dot ? dotfiles : nodot) + '[^/]', true); - glob._replace('/.', '/(?=.)\\.', true); - - // windows drives - glob._replace(/^(\w):([\\\/]+?)/gi, '(?=.)$1:$2', true); - - // negate slashes in exclusion ranges - if (glob.pattern.indexOf('[^') !== -1) { - glob.pattern = negateSlash(glob.pattern); - } - - if (opts.globstar !== false && glob.pattern === '**') { - glob.pattern = globstar(opts.dot); - - } else { - glob.pattern = balance(glob.pattern, '[', ']'); - glob.escape(glob.pattern); - - // if the pattern has `**` - if (tok.is.globstar) { - glob.pattern = collapse(glob.pattern, '/**'); - glob.pattern = collapse(glob.pattern, '**/'); - glob._replace('/**/', '(?:/' + globstar(opts.dot) + '/|/)', true); - glob._replace(/\*{2,}/g, '**'); - - // 'foo/*' - glob._replace(/(\w+)\*(?!\/)/g, '$1[^/]*?', true); - glob._replace(/\*\*\/\*(\w)/g, globstar(opts.dot) + '\\/' + (opts.dot ? dotfiles : nodot) + '[^/]*?$1', true); - - if (opts.dot !== true) { - glob._replace(/\*\*\/(.)/g, '(?:**\\/|)$1'); - } - - // 'foo/**' or '{**,*}', but not 'foo**' - if (tok.path.dirname !== '' || /,\*\*|\*\*,/.test(glob.orig)) { - glob._replace('**', globstar(opts.dot), true); - } - } - - // ends with /* - glob._replace(/\/\*$/, '\\/' + oneStar(opts.dot), true); - // ends with *, no slashes - glob._replace(/(?!\/)\*$/, star, true); - // has 'n*.' (partial wildcard w/ file extension) - glob._replace(/([^\/]+)\*/, '$1' + oneStar(true), true); - // has '*' - glob._replace('*', oneStar(opts.dot), true); - glob._replace('?.', '?\\.', true); - glob._replace('?:', '?:', true); - - glob._replace(/\?+/g, function(match) { - var len = match.length; - if (len === 1) { - return qmark; - } - return qmark + '{' + len + '}'; - }); - - // escape '.abc' => '\\.abc' - glob._replace(/\.([*\w]+)/g, '\\.$1'); - // fix '[^\\\\/]' - glob._replace(/\[\^[\\\/]+\]/g, qmark); - // '///' => '\/' - glob._replace(/\/+/g, '\\/'); - // '\\\\\\' => '\\' - glob._replace(/\\{2,}/g, '\\'); - } - - // unescape previously escaped patterns - glob.unescape(glob.pattern); - glob._replace('__UNESC_STAR__', '*'); - - // escape dots that follow qmarks - glob._replace('?.', '?\\.'); - - // remove unnecessary slashes in character classes - glob._replace('[^\\/]', qmark); - - if (glob.pattern.length > 1) { - if (/^[\[?*]/.test(glob.pattern)) { - // only prepend the string if we don't want to match dotfiles - glob.pattern = (opts.dot ? dotfiles : nodot) + glob.pattern; - } - } - - return glob; -} - -/** - * Collapse repeated character sequences. - * - * ```js - * collapse('a/../../../b', '../'); - * //=> 'a/../b' - * ``` - * - * @param {String} `str` - * @param {String} `ch` Character sequence to collapse - * @return {String} - */ - -function collapse(str, ch) { - var res = str.split(ch); - var isFirst = res[0] === ''; - var isLast = res[res.length - 1] === ''; - res = res.filter(Boolean); - if (isFirst) res.unshift(''); - if (isLast) res.push(''); - return res.join(ch); -} - -/** - * Negate slashes in exclusion ranges, per glob spec: - * - * ```js - * negateSlash('[^foo]'); - * //=> '[^\\/foo]' - * ``` - * - * @param {String} `str` glob pattern - * @return {String} - */ - -function negateSlash(str) { - return str.replace(/\[\^([^\]]*?)\]/g, function(match, inner) { - if (inner.indexOf('/') === -1) { - inner = '\\/' + inner; - } - return '[^' + inner + ']'; - }); -} - -/** - * Escape imbalanced braces/bracket. This is a very - * basic, naive implementation that only does enough - * to serve the purpose. - */ - -function balance(str, a, b) { - var aarr = str.split(a); - var alen = aarr.join('').length; - var blen = str.split(b).join('').length; - - if (alen !== blen) { - str = aarr.join('\\' + a); - return str.split(b).join('\\' + b); - } - return str; -} - -/** - * Special patterns to be converted to regex. - * Heuristics are used to simplify patterns - * and speed up processing. - */ - -/* eslint no-multi-spaces: 0 */ -var qmark = '[^/]'; -var star = qmark + '*?'; -var nodot = '(?!\\.)(?=.)'; -var dotfileGlob = '(?:\\/|^)\\.{1,2}($|\\/)'; -var dotfiles = '(?!' + dotfileGlob + ')(?=.)'; -var twoStarDot = '(?:(?!' + dotfileGlob + ').)*?'; - -/** - * Create a regex for `*`. - * - * If `dot` is true, or the pattern does not begin with - * a leading star, then return the simpler regex. - */ - -function oneStar(dotfile) { - return dotfile ? '(?!' + dotfileGlob + ')(?=.)' + star : (nodot + star); -} - -function globstar(dotfile) { - if (dotfile) { return twoStarDot; } - return '(?:(?!(?:\\/|^)\\.).)*?'; -} diff --git a/lib/glob.js b/lib/glob.js deleted file mode 100644 index c6133267..00000000 --- a/lib/glob.js +++ /dev/null @@ -1,193 +0,0 @@ -'use strict'; - -var chars = require('./chars'); -var utils = require('./utils'); - -/** - * Expose `Glob` - */ - -var Glob = module.exports = function Glob(pattern, options) { - if (!(this instanceof Glob)) { - return new Glob(pattern, options); - } - this.options = options || {}; - this.pattern = pattern; - this.history = []; - this.tokens = {}; - this.init(pattern); -}; - -/** - * Initialize defaults - */ - -Glob.prototype.init = function(pattern) { - this.orig = pattern; - this.negated = this.isNegated(); - this.options.track = this.options.track || false; - this.options.makeRe = true; -}; - -/** - * Push a change into `glob.history`. Useful - * for debugging. - */ - -Glob.prototype.track = function(msg) { - if (this.options.track) { - this.history.push({msg: msg, pattern: this.pattern}); - } -}; - -/** - * Return true if `glob.pattern` was negated - * with `!`, also remove the `!` from the pattern. - * - * @return {Boolean} - */ - -Glob.prototype.isNegated = function() { - if (this.pattern.charCodeAt(0) === 33 /* '!' */) { - this.pattern = this.pattern.slice(1); - return true; - } - return false; -}; - -/** - * Expand braces in the given glob pattern. - * - * We only need to use the [braces] lib when - * patterns are nested. - */ - -Glob.prototype.braces = function() { - if (this.options.nobraces !== true && this.options.nobrace !== true) { - // naive/fast check for imbalanced characters - var a = this.pattern.match(/[\{\(\[]/g); - var b = this.pattern.match(/[\}\)\]]/g); - - // if imbalanced, don't optimize the pattern - if (a && b && (a.length !== b.length)) { - this.options.makeRe = false; - } - - // expand brace patterns and join the resulting array - var expanded = utils.braces(this.pattern, this.options); - this.pattern = expanded.join('|'); - } -}; - -/** - * Expand bracket expressions in `glob.pattern` - */ - -Glob.prototype.brackets = function() { - if (this.options.nobrackets !== true) { - this.pattern = utils.brackets(this.pattern); - } -}; - -/** - * Expand bracket expressions in `glob.pattern` - */ - -Glob.prototype.extglob = function() { - if (this.options.noextglob === true) return; - - if (utils.isExtglob(this.pattern)) { - this.pattern = utils.extglob(this.pattern, {escape: true}); - } -}; - -/** - * Parse the given pattern - */ - -Glob.prototype.parse = function(pattern) { - this.tokens = utils.parseGlob(pattern || this.pattern, true); - return this.tokens; -}; - -/** - * Replace `a` with `b`. Also tracks the change before and - * after each replacement. This is disabled by default, but - * can be enabled by setting `options.track` to true. - * - * Also, when the pattern is a string, `.split()` is used, - * because it's much faster than replace. - * - * @param {RegExp|String} `a` - * @param {String} `b` - * @param {Boolean} `escape` When `true`, escapes `*` and `?` in the replacement. - * @return {String} - */ - -Glob.prototype._replace = function(a, b, escape) { - this.track('before (find): "' + a + '" (replace with): "' + b + '"'); - if (escape) b = esc(b); - if (a && b && typeof a === 'string') { - this.pattern = this.pattern.split(a).join(b); - } else { - this.pattern = this.pattern.replace(a, b); - } - this.track('after'); -}; - -/** - * Escape special characters in the given string. - * - * @param {String} `str` Glob pattern - * @return {String} - */ - -Glob.prototype.escape = function(str) { - this.track('before escape: '); - var re = /["\\](['"]?[^"'\\]['"]?)/g; - - this.pattern = str.replace(re, function($0, $1) { - var o = chars.ESC; - var ch = o && o[$1]; - if (ch) { - return ch; - } - if (/[a-z]/i.test($0)) { - return $0.split('\\').join(''); - } - return $0; - }); - - this.track('after escape: '); -}; - -/** - * Unescape special characters in the given string. - * - * @param {String} `str` - * @return {String} - */ - -Glob.prototype.unescape = function(str) { - var re = /__([A-Z]+)_([A-Z]+)__/g; - this.pattern = str.replace(re, function($0, $1) { - return chars[$1][$0]; - }); - this.pattern = unesc(this.pattern); -}; - -/** - * Escape/unescape utils - */ - -function esc(str) { - str = str.split('?').join('%~'); - str = str.split('*').join('%%'); - return str; -} - -function unesc(str) { - str = str.split('%~').join('?'); - str = str.split('%%').join('*'); - return str; -} diff --git a/lib/micromatch.js b/lib/micromatch.js new file mode 100644 index 00000000..6f3808a2 --- /dev/null +++ b/lib/micromatch.js @@ -0,0 +1,99 @@ +'use strict'; + +var debug = require('debug')('micromatch'); +var Snapdragon = require('snapdragon'); +var compilers = require('./compilers'); +var parsers = require('./parsers'); +var utils = require('./utils'); + +/** + * Customize Snapdragon parser and renderer + */ + +function Micromatch(options) { + debug('initializing from <%s>', __filename); + this.options = utils.extend({source: 'micromatch'}, options); + this.snapdragon = this.options.snapdragon || new Snapdragon(this.options); + + /** + * Override Snapdragon `.parse` method + */ + + utils.define(this.snapdragon, 'parse', function(str, options) { + var parsed = Snapdragon.prototype.parse.apply(this, arguments); + + // escape ummatched brace/bracket/parens + var last = this.parser.stack.pop(); + if (last) { + var node = last.nodes[0]; + + if (last.type !== 'bracket') { + node.val = '\\' + node.val; + } + + var sibling = node.parent.nodes[1]; + if (sibling.type === 'star') { + sibling.loose = true; + } + } + + // add non-enumerable parser reference + utils.define(parsed, 'parser', this.parser); + return parsed; + }); + + /** + * Decorate `.parse` method + */ + + utils.define(this, 'parse', function(ast, options) { + return this.snapdragon.parse.apply(this.snapdragon, arguments); + }); + + /** + * Decorate `.compile` method + */ + + utils.define(this, 'compile', function(ast, options) { + return this.snapdragon.compile.apply(this.snapdragon, arguments); + }); + + /** + * Create a regular expression from the given glob `pattern`. + * + * ```js + * var mm = require('micromatch'); + * var re = mm.makeRe('*.!(*a)'); + * console.log(re); + * //=> /^[^\/]*?\.(?![^\/]*?a)[^\/]*?$/ + * ``` + * @param {String} `pattern` The glob pattern to convert + * @param {Object} `options` + * @return {RegExp} + * @api public + */ + + utils.define(this, 'makeRe', function() { + return this.snapdragon.makeRe.apply(this.snapdragon, arguments); + }); + + /** + * Create a regex from the given `string` and `options` + */ + + utils.define(this, 'toRegex', function() { + return this.snapdragon.toRegex.apply(this.snapdragon, arguments); + }); + + this.compiler = this.snapdragon.compiler; + this.parser = this.snapdragon.parser; + + compilers(this.snapdragon); + parsers(this.snapdragon); +} + +/** + * Expose `Micromatch` + */ + +module.exports = Micromatch; diff --git a/lib/parsers.js b/lib/parsers.js new file mode 100644 index 00000000..9ee733f1 --- /dev/null +++ b/lib/parsers.js @@ -0,0 +1,38 @@ +'use strict'; + +var nanomatch = require('nanomatch'); +var brackets = require('expand-brackets'); +var extglob = require('extglob'); +var utils = require('./utils'); + +module.exports = function(micromatch) { + + /** + * Parser plugins + */ + + micromatch.use(nanomatch.parsers); + if (micromatch.options.brackets !== false) { + micromatch.use(brackets.parsers); + } + if (micromatch.options.extglob !== false) { + micromatch.use(extglob.parsers); + } + + /** + * Micromatch parsers + */ + + micromatch.parser + .capture('star', /^(?:\*(?![(])|[*]{3,})/) + .set('text', function() { + var pos = this.position(); + var m = this.match(/^((?!(?:([!@*?+])?\(|[*.+?^\/\(\[\])\\]|\[\]\])).)*/); + if (!m || !m[0]) return; + + return pos({ + type: 'text', + val: m[0] + }); + }) +}; diff --git a/lib/utils.js b/lib/utils.js index 7c24a510..4486ce37 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,69 +1,80 @@ 'use strict'; -var win32 = process && process.platform === 'win32'; +var isWindows = process.platform === 'win32'; var path = require('path'); -var fileRe = require('filename-regex'); var utils = module.exports; +utils.fill = require('fill-array'); +utils.unique = require('array-unique'); +utils.define = require('define-property'); +utils.extend = require('extend-shallow'); +utils.repeat = require('repeat-string'); +utils.normalize = require('normalize-path'); +utils.isGlob = require('is-glob'); +utils.diff = require('arr-diff'); +var unixifyCache = {}; + /** - * Module dependencies + * Create a negation regex from the given string + * @param {String} `str` + * @return {RegExp} */ -utils.diff = require('arr-diff'); -utils.unique = require('array-unique'); -utils.braces = require('braces'); -utils.brackets = require('expand-brackets'); -utils.extglob = require('extglob'); -utils.isExtglob = require('is-extglob'); -utils.isGlob = require('is-glob'); -utils.typeOf = require('kind-of'); -utils.normalize = require('normalize-path'); -utils.omit = require('object.omit'); -utils.parseGlob = require('parse-glob'); -utils.cache = require('regex-cache'); +utils.not = function(str) { + return '^((?!(?:' + str + ')).)*'; +}; + +utils.expand = function(str) { + var segs = str.split(',').filter(Boolean); + var arr = segs.slice(); + + if (arr.length === 1) { + arr = str.split('..'); + + if (arr.length > 1) { + segs = utils.fill.apply(null, arr); + } + } + return segs; +}; + +utils.arrayify = function(val) { + return val ? (Array.isArray(val) ? val : [val]) : []; +}; /** - * Get the filename of a filepath - * - * @param {String} `string` - * @return {String} + * Return true if `val` is a non-empty string */ -utils.filename = function filename(fp) { - var seg = fp.match(fileRe()); - return seg && seg[0]; +utils.isString = function(val) { + return val && typeof val === 'string'; }; /** - * Returns a function that returns true if the given - * pattern is the same as a given `filepath` - * - * @param {String} `pattern` - * @return {Function} + * Get the last element from `array` + * @param {Array} `array` + * @return {*} */ -utils.isPath = function isPath(pattern, opts) { - opts = opts || {}; - return function(fp) { - var unixified = utils.unixify(fp, opts); - if(opts.nocase){ - return pattern.toLowerCase() === unixified.toLowerCase(); - } - return pattern === unixified; - }; +utils.last = function(arr) { + return arr[arr.length - 1]; +}; + +utils.hasSpecialChars = function(str) { + return /(?:(^|\/)[!.]|[*?()\[\]{}]|[+@]\()/.test(str); }; /** * Returns a function that returns true if the given - * pattern contains a `filepath` + * regex matches the `filename` of a file path. * - * @param {String} `pattern` + * @param {RegExp} `re` Matching regex * @return {Function} */ -utils.hasPath = function hasPath(pattern, opts) { - return function(fp) { - return utils.unixify(pattern, opts).indexOf(fp) !== -1; +utils.matchBasename = function(re) { + return function(filepath) { + return re.test(filepath) || re.test(path.basename(filepath)); }; }; @@ -75,75 +86,82 @@ utils.hasPath = function hasPath(pattern, opts) { * @return {Function} */ -utils.matchPath = function matchPath(pattern, opts) { - var fn = (opts && opts.contains) - ? utils.hasPath(pattern, opts) - : utils.isPath(pattern, opts); - return fn; +utils.matchPath = function(pattern, options) { + return (options && options.contains) + ? utils.containsPath(pattern, options) + : utils.equalsPath(pattern, options); }; /** * Returns a function that returns true if the given - * regex matches the `filename` of a file path. + * pattern is the same as a given `filepath` * - * @param {RegExp} `re` - * @return {Boolean} + * @param {String} `pattern` + * @return {Function} */ -utils.hasFilename = function hasFilename(re) { - return function(fp) { - var name = utils.filename(fp); - return name && re.test(name); +utils.equalsPath = function(pattern, options) { + options = options || {}; + return function(filepath) { + if (options.nocase === true) { + return pattern.toLowerCase() === filepath.toLowerCase(); + } else { + return pattern === filepath; + } }; }; /** - * Coerce `val` to an array + * Returns a function that returns true if the given + * pattern contains a `filepath` * - * @param {*} val - * @return {Array} + * @param {String} `pattern` + * @return {Function} */ -utils.arrayify = function arrayify(val) { - return !Array.isArray(val) - ? [val] - : val; +utils.containsPath = function(pattern) { + return function(filepath) { + return pattern.indexOf(filepath) !== -1; + }; }; -/** - * Normalize all slashes in a file path or glob pattern to - * forward slashes. - */ - -utils.unixify = function unixify(fp, opts) { - if (opts && opts.unixify === false) return fp; - if (opts && opts.unixify === true || win32 || path.sep === '\\') { - return utils.normalize(fp, false); +utils.stripPrefix = function(filepath, options) { + var opts = utils.extend({}, options); + if (opts.normalize !== true) { + return filepath; } - if (opts && opts.unescape === true) { - return fp ? fp.toString().replace(/\\(\w)/g, '$1') : ''; + + filepath = String(filepath || ''); + if (filepath.slice(0, 2) === './') { + return filepath.slice(2); } - return fp; + return filepath; }; /** - * Escape/unescape utils + * Normalize all slashes in a file path or glob pattern to + * forward slashes. */ -utils.escapePath = function escapePath(fp) { - return fp.replace(/[\\.]/g, '\\$&'); -}; +utils.unixify = function(options) { + var opts = utils.extend({}, options); + var unixify; -utils.unescapeGlob = function unescapeGlob(fp) { - return fp.replace(/[\\"']/g, ''); -}; + if (path.sep !== '/' || opts.unixify === true) { + unixify = function(filepath) { + return utils.normalize(utils.stripPrefix(filepath, opts), false); + }; -utils.escapeRe = function escapeRe(str) { - return str.replace(/[-[\\$*+?.#^\s{}(|)\]]/g, '\\$&'); -}; + } else if (opts.unescape === true) { + unixify = function(filepath) { + return utils.stripPrefix(filepath, opts).replace(/\\([-.\w])/g, '$1'); + }; -/** - * Expose `utils` - */ + } else { + unixify = function(filepath) { + return utils.stripPrefix(filepath, opts); + }; + } -module.exports = utils; + return unixify; +}; diff --git a/package.json b/package.json index 640a3d11..9e1db4f6 100644 --- a/package.json +++ b/package.json @@ -35,34 +35,32 @@ "test": "mocha" }, "dependencies": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", + "arr-diff": "^3.0.0", + "array-unique": "^0.3.2", + "debug": "^2.2.0", + "define-property": "^0.2.5", "expand-brackets": "^0.1.4", + "extend-shallow": "^2.0.1", "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", + "fill-array": "^1.0.0", + "is-glob": "^3.0.0", "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" + "repeat-string": "^1.5.4" }, "devDependencies": { - "benchmarked": "^0.1.4", - "chalk": "^1.1.1", + "ansi-cyan": "^0.1.1", + "cross-spawn": "^4.0.0", + "delete": "^0.3.2", + "export-files": "^2.1.1", "gulp": "^3.9.0", "gulp-eslint": "^1.1.1", "gulp-format-md": "^0.1.8", "gulp-istanbul": "^0.10.1", "gulp-mocha": "^2.1.3", "minimatch": "^3.0.0", - "minimist": "^1.2.0", "mocha": "^2", - "multimatch": "^2.0.0", "should": "^8", - "write": "^0.2.1" + "yargs-parser": "^3.2.0" }, "keywords": [ "bash", @@ -126,4 +124,4 @@ "reflinks": true } } -} \ No newline at end of file +} diff --git a/roadmap.md b/roadmap.md new file mode 100644 index 00000000..01e1dd8c --- /dev/null +++ b/roadmap.md @@ -0,0 +1,9 @@ +# Roadmap + +``` +micromatch + L braces + L nanomatch + L extglob + L expand-brackets (POSIX character classes) +``` \ No newline at end of file diff --git a/test/any.js b/test/any.js index 64220089..6eb844c0 100644 --- a/test/any.js +++ b/test/any.js @@ -1,232 +1,225 @@ 'use strict'; -require('should'); -var mm = require('..'); +require('mocha'); +var assert = require('assert'); +var nm = require('..'); describe('.any()', function() { - describe('errors:', function() { + describe('error handling', function() { it('should throw on undefined args:', function() { - (function() { - mm.any(); - }).should.throw('micromatch.any(): patterns should be a string or array.'); + assert.throws(function() { + nm.any(); + }, /expected patterns to be a string or array/); }); it('should throw on bad args:', function() { - (function() { - mm.any({}); - }).should.throw('micromatch.any(): patterns should be a string or array.'); + assert.throws(function() { + nm.any({}); + }, /expected patterns to be a string or array/); }); }); it('should correctly handle empty patterns', function() { - mm.any('ab', '').should.be.false(); - mm.any('a', '').should.be.false(); - mm.any('.', '').should.be.false(); + assert(!nm.any('ab', '')); + assert(!nm.any('a', '')); + assert(!nm.any('.', '')); }); it('should support an array of patterns', function() { - mm.any('ab', ['']).should.be.false(); - mm.any('a', ['']).should.be.false(); - mm.any('.', ['']).should.be.false(); + assert(!nm.any('ab', [''])); + assert(!nm.any('a', [''])); + assert(!nm.any('.', [''])); }); it('should return true when the path contains the pattern', function() { - mm.any('ab', 'b').should.be.false(); - mm.any('.', '.').should.be.true(); - mm.any('a/b/c', 'a/b').should.be.false(); - mm.any('/ab', '/a').should.be.false(); - mm.any('a', 'a').should.be.true(); - mm.any('ab', 'a').should.be.false(); - mm.any('ab', 'ab').should.be.true(); - mm.any('abcd', 'd').should.be.false(); - mm.any('abcd', 'c').should.be.false(); - mm.any('abcd', 'cd').should.be.false(); - mm.any('abcd', 'bc').should.be.false(); - mm.any('abcd', 'ab').should.be.false(); + assert(!nm.any('ab', 'b')); + assert(nm.any('.', '.')); + assert(!nm.any('a/b/c', 'a/b')); + assert(!nm.any('/ab', '/a')); + assert(nm.any('a', 'a')); + assert(!nm.any('ab', 'a')); + assert(nm.any('ab', 'ab')); + assert(!nm.any('abcd', 'd')); + assert(!nm.any('abcd', 'c')); + assert(!nm.any('abcd', 'cd')); + assert(!nm.any('abcd', 'bc')); + assert(!nm.any('abcd', 'ab')); }); it('should return true when the path contains any of the patterns', function() { - mm.any('ab', ['b', 'foo']).should.be.false(); - mm.any('.', ['.', 'foo']).should.be.true(); - mm.any('a/b/c', ['a/b', 'foo']).should.be.false(); - mm.any('/ab', ['/a', 'foo']).should.be.false(); - mm.any('a', ['a', 'foo']).should.be.true(); - mm.any('ab', ['a', 'foo']).should.be.false(); - mm.any('ab', ['ab', 'foo']).should.be.true(); - mm.any('abcd', ['d', 'foo']).should.be.false(); - mm.any('abcd', ['c', 'foo']).should.be.false(); - mm.any('abcd', ['cd', 'foo']).should.be.false(); - mm.any('abcd', ['bc', 'foo']).should.be.false(); - mm.any('abcd', ['ab', 'foo']).should.be.false(); - }); - - it('should match with common glob patterns', function() { - mm.any('a/b/c', 'a/*').should.be.false(); - mm.any('/ab', '/a').should.be.false(); - mm.any('/ab', '/*').should.be.true(); - mm.any('/cd', '/*').should.be.true(); - mm.any('ab', '*').should.be.true(); - mm.any('ab', 'ab').should.be.true(); - mm.any('/ab', '*/a').should.be.false(); - mm.any('/ab', '*/').should.be.false(); - mm.any('/ab', '*/*').should.be.true(); - mm.any('/ab', '/').should.be.false(); - mm.any('/ab', '/??').should.be.true(); - mm.any('/ab', '/?b').should.be.true(); - mm.any('/ab', '/?').should.be.false(); - mm.any('a/b', '?/?').should.be.true(); + assert(!nm.any('ab', ['b', 'foo'])); + assert(nm.any('.', ['.', 'foo'])); + assert(!nm.any('a/b/c', ['a/b', 'foo'])); + assert(!nm.any('/ab', ['/a', 'foo'])); + assert(nm.any('a', ['a', 'foo'])); + assert(!nm.any('ab', ['a', 'foo'])); + assert(nm.any('ab', ['ab', 'foo'])); + assert(!nm.any('abcd', ['d', 'foo'])); + assert(!nm.any('abcd', ['c', 'foo'])); + assert(!nm.any('abcd', ['cd', 'foo'])); + assert(!nm.any('abcd', ['bc', 'foo'])); + assert(!nm.any('abcd', ['ab', 'foo'])); + }); + + it('should match with conmon glob patterns', function() { + assert(nm.any('/ab', '*/*')); + assert(nm.any('/ab', '/*')); + assert(nm.any('/ab', '/??')); + assert(nm.any('/ab', '/?b')); + assert(nm.any('/cd', '/*')); + assert(nm.any('a/b', '?/?')); + assert(nm.any('ab', '*')); + assert(nm.any('ab', 'ab')); + assert(!nm.any('/ab', '*/')); + assert(!nm.any('/ab', '*/a')); + assert(!nm.any('/ab', '/')); + assert(!nm.any('/ab', '/?')); + assert(!nm.any('/ab', '/a')); + assert(!nm.any('a/b/c', 'a/*')); }); it('should return false when the path does not contain the pattern', function() { - mm.any('/ab', '?/?').should.be.false(); - mm.any('ab', '*/*').should.be.false(); - mm.any('abcd', 'f').should.be.false(); - mm.any('ab', 'c').should.be.false(); - mm.any('ab', '/a').should.be.false(); - mm.any('/ab', 'a/*').should.be.false(); - mm.any('ef', '/*').should.be.false(); - mm.any('ab', './*').should.be.false(); + assert(!nm.any('/ab', '?/?')); + assert(!nm.any('ab', '*/*')); + assert(!nm.any('abcd', 'f')); + assert(!nm.any('ab', 'c')); + assert(!nm.any('ab', '/a')); + assert(!nm.any('/ab', 'a/*')); + assert(!nm.any('ef', '/*')); + assert(!nm.any('ab', './*')); }); it('should return false when the path does not contain any pattern', function() { - mm.any('/ab', ['?/?', 'foo', 'bar']).should.be.false(); - mm.any('ab', ['*/*', 'foo', 'bar']).should.be.false(); - mm.any('abcd', ['f', 'foo', 'bar']).should.be.false(); - mm.any('ab', ['c', 'foo', 'bar']).should.be.false(); - mm.any('ab', ['/a', 'foo', 'bar']).should.be.false(); - mm.any('/ab', ['a/*', 'foo', 'bar']).should.be.false(); - mm.any('ef', ['/*', 'foo', 'bar']).should.be.false(); - mm.any('ab', ['./*', 'foo', 'bar']).should.be.false(); + assert(!nm.any('/ab', ['?/?', 'foo', 'bar'])); + assert(!nm.any('ab', ['*/*', 'foo', 'bar'])); + assert(!nm.any('abcd', ['f', 'foo', 'bar'])); + assert(!nm.any('ab', ['c', 'foo', 'bar'])); + assert(!nm.any('ab', ['/a', 'foo', 'bar'])); + assert(!nm.any('/ab', ['a/*', 'foo', 'bar'])); + assert(!nm.any('ef', ['/*', 'foo', 'bar'])); + assert(!nm.any('ab', ['./*', 'foo', 'bar'])); }); it('should match files that contain the given extension:', function() { - mm.any('.md', '.m').should.be.false(); - mm.any('.c.md', '.*.md').should.be.true(); - mm.any('c.md', '*.md').should.be.true(); - mm.any('a/b/c.md', '.md').should.be.false(); - mm.any('a/b/c.md', 'a/*/*.md').should.be.true(); - mm.any('a/b/c.md', '**/*.md').should.be.true(); - mm.any('c.md', '*.md').should.be.true(); - mm.any('.c.md', '.md').should.be.false(); - mm.any('.c.md', '.c.').should.be.false(); - mm.any('a/b/c.md', '*.md').should.be.false(); - mm.any('a/b/c/c.md', '*.md').should.be.false(); - mm.any('.c.md', '*.md').should.be.false(); + assert(!nm.any('.md', '.m')); + assert(nm.any('.c.md', '.*.md')); + assert(nm.any('c.md', '*.md')); + assert(!nm.any('a/b/c.md', '.md')); + assert(nm.any('a/b/c.md', 'a/*/*.md')); + assert(nm.any('a/b/c.md', '**/*.md')); + assert(nm.any('c.md', '*.md')); + assert(!nm.any('.c.md', '.md')); + assert(!nm.any('.c.md', '.c.')); + assert(!nm.any('a/b/c.md', '*.md')); + assert(!nm.any('a/b/c/c.md', '*.md')); + assert(!nm.any('.c.md', '*.md')); }); it('should not match files that do not contain the given extension:', function() { - mm.any('.md', '*.md').should.be.false(); - mm.any('a/b/c/c.md', 'c.js').should.be.false(); - mm.any('a/b/c.md', 'a/*.md').should.be.false(); + assert(!nm.any('.md', '*.md')); + assert(!nm.any('a/b/c/c.md', 'c.js')); + assert(!nm.any('a/b/c.md', 'a/*.md')); }); it('should match dotfiles when a dot is explicitly defined in the pattern:', function() { - mm.any('.a', '.a').should.be.true(); - mm.any('.ab', '.*').should.be.true(); - mm.any('.ab', '.a*').should.be.true(); - mm.any('.abc', '.a').should.be.false(); - mm.any('.b', '.b*').should.be.true(); - mm.any('.md', '.md').should.be.true(); - mm.any('.c.md', '*.md').should.be.false(); - mm.any('a/.c.md', 'a/.c.md').should.be.true(); - mm.any('a/b/c/.xyz.md', 'a/b/c/.*.md').should.be.true(); - mm.any('a/.c.md', '*.md').should.be.false(); - mm.any('a/b/c/d.a.md', 'a/b/c/*.md').should.be.true(); + assert(nm.any('.a', '.a')); + assert(nm.any('.ab', '.*')); + assert(nm.any('.ab', '.a*')); + assert(!nm.any('.abc', '.a')); + assert(nm.any('.b', '.b*')); + assert(nm.any('.md', '.md')); + assert(!nm.any('.c.md', '*.md')); + assert(nm.any('a/.c.md', 'a/.c.md')); + assert(nm.any('a/b/c/.xyz.md', 'a/b/c/.*.md')); + assert(!nm.any('a/.c.md', '*.md')); + assert(nm.any('a/b/c/d.a.md', 'a/b/c/*.md')); }); it('should match dotfiles when `dot` or `dotfiles` is set:', function() { - mm.any('a/b/c/.xyz.md', '.*.md', {dot: true}).should.be.false(); - mm.any('.c.md', '*.md', {dot: true}).should.be.true(); - mm.any('.c.md', '.*', {dot: true}).should.be.true(); - mm.any('a/b/c/.xyz.md', '**/*.md', {dot: true}).should.be.true(); - mm.any('a/b/c/.xyz.md', '**/.*.md', {dot: true}).should.be.true(); - mm.any('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true}).should.be.true(); - mm.any('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true}).should.be.true(); + assert(!nm.any('a/b/c/.xyz.md', '.*.md', {dot: true})); + assert(nm.any('.c.md', '*.md', {dot: true})); + assert(nm.any('.c.md', '.*', {dot: true})); + assert(nm.any('a/b/c/.xyz.md', '**/*.md', {dot: true})); + assert(nm.any('a/b/c/.xyz.md', '**/.*.md', {dot: true})); + assert(nm.any('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true})); + assert(nm.any('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true})); }); it('should not match dotfiles when `dot` or `dotfiles` is not set:', function() { - mm.any('.a', '*.md').should.be.false(); - mm.any('.ba', '.a').should.be.false(); - mm.any('.a.md', 'a/b/c/*.md').should.be.false(); - mm.any('.ab', '*.*').should.be.false(); - mm.any('.md', 'a/b/c/*.md').should.be.false(); - mm.any('.txt', '.md').should.be.false(); - mm.any('.verb.txt', '*.md').should.be.false(); - mm.any('a/b/d/.md', 'a/b/c/*.md').should.be.false(); + assert(!nm.any('.a', '*.md')); + assert(!nm.any('.ba', '.a')); + assert(!nm.any('.a.md', 'a/b/c/*.md')); + assert(!nm.any('.ab', '*.*')); + assert(!nm.any('.md', 'a/b/c/*.md')); + assert(!nm.any('.txt', '.md')); + assert(!nm.any('.verb.txt', '*.md')); + assert(!nm.any('a/b/d/.md', 'a/b/c/*.md')); }); it('should match file paths:', function() { - mm.any('a/b/c/xyz.md', 'a/b/c/*.md').should.be.true(); - mm.any('a/bb/c/xyz.md', 'a/*/c/*.md').should.be.true(); - mm.any('a/bbbb/c/xyz.md', 'a/*/c/*.md').should.be.true(); - mm.any('a/bb.bb/c/xyz.md', 'a/*/c/*.md').should.be.true(); - mm.any('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md').should.be.true(); - mm.any('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md').should.be.true(); + assert(nm.any('a/b/c/xyz.md', 'a/b/c/*.md')); + assert(nm.any('a/bb/c/xyz.md', 'a/*/c/*.md')); + assert(nm.any('a/bbbb/c/xyz.md', 'a/*/c/*.md')); + assert(nm.any('a/bb.bb/c/xyz.md', 'a/*/c/*.md')); + assert(nm.any('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md')); + assert(nm.any('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md')); }); it('should return true when full file paths are matched:', function() { - mm.any('a/.b', 'a/.*').should.be.true(); - mm.any('a/.b', 'a/').should.be.false(); - mm.any('a/b/z/.a', 'b/z').should.be.false(); - mm.any('a/b/z/.a', 'a/*/z/.a').should.be.true(); - mm.any('a/b/c/d/e/z/c.md', 'a/**/z/*.md').should.be.true(); - mm.any('a/b/c/d/e/z/c.md', 'b/c/d/e').should.be.false(); - mm.any('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md').should.be.true(); - mm.any('a/b/c/cd/bbb/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.true(); - mm.any('a/b/baz/ce/fez/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.true(); + assert(nm.any('a/.b', 'a/.*')); + assert(!nm.any('a/.b', 'a/')); + assert(!nm.any('a/b/z/.a', 'b/z')); + assert(nm.any('a/b/z/.a', 'a/*/z/.a')); + assert(nm.any('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(!nm.any('a/b/c/d/e/z/c.md', 'b/c/d/e')); + assert(nm.any('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); }); it('question marks should not match slashes:', function() { - mm.any('aaa/bbb', 'aaa?bbb').should.be.false(); + assert(!nm.any('aaa/bbb', 'aaa?bbb')); }); it('should match path segments:', function() { - mm.any('aaa', 'aaa').should.be.true(); - mm.any('aaa', 'aa').should.be.false(); - mm.any('aaa/bbb', 'aaa/bbb').should.be.true(); - mm.any('aaa/bbb', 'aaa/*').should.be.true(); - mm.any('aaa/bba/ccc', 'aaa/*').should.be.false(); - mm.any('aaa/bba/ccc', 'aaa/**').should.be.true(); - mm.any('aaa/bba/ccc', 'aaa*').should.be.false(); - mm.any('aaa/bba/ccc', 'aaa**').should.be.false(); - mm.any('aaa/bba/ccc', 'aaa/*ccc').should.be.false(); - mm.any('aaa/bba/ccc', 'aaa/**ccc').should.be.true(); - mm.any('aaa/bba/ccc', 'aaa/*z').should.be.false(); - mm.any('aaa/bba/ccc', 'aaa/**z').should.be.false(); - mm.any('aaa/bbb', 'aaa[/]bbb').should.be.true(); - mm.any('aaa', '*/*/*').should.be.false(); - mm.any('aaa/bbb', '*/*/*').should.be.false(); - mm.any('aaa/bba/ccc', '*/*/*').should.be.true(); - mm.any('aaa/bb/aa/rr', '*/*/*').should.be.false(); - mm.any('abzzzejklhi', '*j*i').should.be.true(); - mm.any('ab/zzz/ejkl/hi', '*/*z*/*/*i').should.be.true(); - mm.any('ab/zzz/ejkl/hi', '*/*jk*/*i').should.be.false(); + assert(nm.any('aaa', 'aaa')); + assert(!nm.any('aaa', 'aa')); + assert(nm.any('aaa/bbb', 'aaa/bbb')); + assert(nm.any('aaa/bbb', 'aaa/*')); + assert(!nm.any('aaa/bba/ccc', 'aaa/*')); + assert(nm.any('aaa/bba/ccc', 'aaa/**')); + assert(!nm.any('aaa/bba/ccc', 'aaa*')); + assert(!nm.any('aaa/bba/ccc', 'aaa**')); + assert(!nm.any('aaa/bba/ccc', 'aaa/*ccc')); + assert(nm.any('aaa/bba/ccc', 'aaa/**ccc')); + assert(!nm.any('aaa/bba/ccc', 'aaa/*z')); + assert(!nm.any('aaa/bba/ccc', 'aaa/**z')); + assert(nm.any('aaa/bbb', 'aaa[/]bbb')); + assert(!nm.any('aaa', '*/*/*')); + assert(!nm.any('aaa/bbb', '*/*/*')); + assert(nm.any('aaa/bba/ccc', '*/*/*')); + assert(!nm.any('aaa/bb/aa/rr', '*/*/*')); + assert(nm.any('abzzzejklhi', '*j*i')); + assert(nm.any('ab/zzz/ejkl/hi', '*/*z*/*/*i')); + assert(!nm.any('ab/zzz/ejkl/hi', '*/*jk*/*i')); }); it('should return false when full file paths are not matched:', function() { - mm.any('a/b/z/.a', 'b/a').should.be.false(); - mm.any('a/.b', 'a/**/z/*.md').should.be.false(); - mm.any('a/b/z/.a', 'a/**/z/*.a').should.be.false(); - mm.any('a/b/z/.a', 'a/*/z/*.a').should.be.false(); - mm.any('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md').should.be.false(); - mm.any('a/b/d/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.any('a/b/c/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.false(); + assert(!nm.any('a/b/z/.a', 'b/a')); + assert(!nm.any('a/.b', 'a/**/z/*.md')); + assert(!nm.any('a/b/z/.a', 'a/**/z/*.a')); + assert(!nm.any('a/b/z/.a', 'a/*/z/*.a')); + assert(!nm.any('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md')); }); it('should match paths with leading `./`:', function() { - mm.any('./.a', 'a/**/z/*.md').should.be.false(); - mm.any('./a/b/z/.a', 'a/**/z/.a').should.be.false(); - mm.any('./a/b/z/.a', './a/**/z/.a').should.be.true(); - mm.any('./a/b/c/d/e/z/c.md', 'a/**/z/*.md').should.be.false(); - mm.any('./a/b/c/d/e/z/c.md', './a/**/z/*.md').should.be.true(); - mm.any('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md').should.be.false(); - mm.any('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md').should.be.true(); - mm.any('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md').should.be.false(); - mm.any('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md').should.be.true(); - mm.any('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md').should.be.false(); - mm.any('./a/b/d/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.any('./a/b/c/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.any('./a/b/c/cd/bbb/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.true(); - mm.any('./a/b/baz/ce/fez/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.true(); + assert(!nm.any('./.a', 'a/**/z/*.md')); + assert(!nm.any('./a/b/z/.a', 'a/**/z/.a')); + assert(nm.any('./a/b/z/.a', './a/**/z/.a')); + assert(!nm.any('./a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(nm.any('./a/b/c/d/e/z/c.md', './a/**/z/*.md')); + assert(!nm.any('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md')); + assert(nm.any('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md')); + assert(!nm.any('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md')); + assert(nm.any('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md')); + assert(!nm.any('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md')); }); }); diff --git a/test/bash-extglob.js b/test/bash-extglob.js deleted file mode 100644 index 01a78216..00000000 --- a/test/bash-extglob.js +++ /dev/null @@ -1,96 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('mocha'); -var path = require('path'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); -require('should'); - -if ('minimatch' in argv) { - mm = ref.minimatch; -} - -var i = 0; -function match(a, pattern, b) { - mm(a.sort(), pattern).should.eql(b.sort()); - console.log(' ' + i++); -} - -describe('bash', function() { - it('should match extended globs:', function() { - match(['aaac', 'foo'], '*(@(a))a@(c)', ['aaac']); - match(['aaac'], '*(@(a))a@(c)', ['aaac']); - match(['aac'], '*(@(a))a@(c)', ['aac']); - match(['aac'], '*(@(a))b@(c)', []); - match(['abbcd'], '@(ab|a*(b))*(c)d', ['abbcd']); - match(['abcd'], '?@(a|b)*@(c)d', ['abcd']); - match(['abcd'], '@(ab|a*@(b))*(c)d', ['abcd']); - match(['ac'], '*(@(a))a@(c)', ['ac']); - match(['acd'], '@(ab|a*(b))*(c)d', ['acd']); - match(['baaac'], '*(@(a))a@(c)', []); - match(['c'], '*(@(a))a@(c)', []); - match(['effgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['effgz']); - match(['efgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['efgz']); - match(['egz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['egz']); - match(['egz'], '@(b+(c)d|e+(f)g?|?(h)i@(j|k))', []); - match(['egzefffgzbcdij'], '*(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['egzefffgzbcdij']); - match(['f'], '!(f)', []); - match(['f'], '*(!(f))', []); - match(['f'], '+(!(f))', []); - match(['fa', 'fb', 'f', 'fo'], '!(f!(o))', ['fo']); - match(['fa', 'fb', 'f', 'fo'], '!(f(o))', ['f', 'fb', 'fa']); - match(['fffooofoooooffoofffooofff'], '*(*(f)*(o))', ['fffooofoooooffoofffooofff']); - match(['ffo'], '*(f*(o))', ['ffo']); - match(['fofo'], '*(f*(o))', ['fofo']); - match(['fofoofoofofoo'], '*(fo|foo)', ['fofoofoofofoo']); - match(['foo', 'bar'], '!(foo)', ['bar']); - match(['foo', 'bar'], '!(foo)*', ['bar']); - match(['foo'], '!(foo)', []); - match(['foo'], '!(x)', ['foo']); - match(['foo'], '!(x)*', ['foo']); - match(['foo/bar'], 'foo/!(foo)', ['foo/bar']); - match(['foob'], '!(foo)b*', []); - match(['foobar', 'baz'], '!(foo)*', ['baz']); - match(['foofoofo'], '@(foo|f|fo)*(f|of+(o))', ['foofoofo']); - match(['fooofoofofooo'], '*(f*(o))', ['fooofoofofooo']); - match(['foooofo'], '*(f*(o))', ['foooofo']); - match(['foooofof'], '*(f*(o))', ['foooofof']); - match(['foooofof'], '*(f+(o))', []); - match(['foooofofx'], '*(f*(o))', []); - match(['foooxfooxfoxfooox'], '*(f*(o)x)', ['foooxfooxfoxfooox']); - match(['foooxfooxfxfooox'], '*(f*(o)x)', ['foooxfooxfxfooox']); - match(['foooxfooxofoxfooox'], '*(f*(o)x)', []); - match(['foot'], '@(!(z*)|*x)', ['foot']); - match(['foox'], '@(!(z*)|*x)', ['foox']); - match(['moo.cow', 'a.b'], '!(*.*).!(*.*)', ['a.b', 'moo.cow']); - match(['moo.cow', 'a.b'], '!(*\\.*).!(*\\.*)', ['a.b', 'moo.cow']); - match(['moo.cow'], '!(*.*).!(*.*)', ['moo.cow']); - match(['mucca.pazza'], 'mu!(*(c))?.pa!(*(z))?', []); - match(['ofoofo'], '*(of+(o))', ['ofoofo']); - match(['ofoofo'], '*(of+(o)|f)', ['ofoofo']); - match(['ofooofoofofooo'], '*(f*(o))', []); - match(['ofoooxoofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxo']); - match(['ofoooxoofxoofoooxoofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxo']); - match(['ofoooxoofxoofoooxoofxofo'], '*(*(of*(o)x)o)', []); - match(['ofoooxoofxoofoooxoofxoo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxoo']); - match(['ofoooxoofxoofoooxoofxooofxofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxooofxofxo']); - match(['ofxoofxo'], '*(*(of*(o)x)o)', ['ofxoofxo']); - match(['oofooofo'], '*(of|oof+(o))', ['oofooofo']); - match(['ooo'], '!(f)', ['ooo']); - match(['ooo'], '*(!(f))', ['ooo']); - match(['ooo'], '+(!(f))', ['ooo']); - match(['oxfoxfox'], '*(oxf+(ox))', []); - match(['oxfoxoxfox'], '*(oxf+(ox))', ['oxfoxoxfox']); - match(['xfoooofof'], '*(f*(o))', []); - match(['zoot'], '@(!(z*)|*x)', []); - match(['zoox'], '@(!(z*)|*x)', ['zoox']); - }); -}); diff --git a/test/bash.js b/test/bash.js deleted file mode 100644 index 0fe18d3d..00000000 --- a/test/bash.js +++ /dev/null @@ -1,122 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -var path = require('path'); -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = ref; -} - -// from the Bash 4.3 specification/unit tests -var arr = ['a','b','c','d','abc','abd','abe','bb','bcd','ca','cb','dd','de','Beware','bdir/', '*']; - -describe('bash options and features:', function() { - describe('failglob:', function() { - it('should throw an error when no matches are found:', function() { - (function() { - mm.match(arr, '\\^', {failglob: true}) - }).should.throw('micromatch.match() found no matches for: "\\^".'); - }); - }); - - // $echo a/{1..3}/b - describe('bash', function() { - it('should handle "regular globbing":', function() { - mm.match(arr, 'a*').should.eql(['a','abc','abd','abe']); - mm.match(arr, '\\a*').should.eql(['a','abc','abd','abe']); - }); - - it('should match directories:', function() { - mm.match(arr, 'b*/').should.eql(['bdir/']); - }); - - it('should use quoted characters as literals:', function() { - mm.match(arr, '\\*', {nonull: true}).should.eql(['*']); - mm.match(arr, '\\^', {nonull: true}).should.eql(['^']); - mm.match(arr, '\\^').should.eql([]); - - mm.match(arr, 'a\\*', {nonull: true}).should.eql(['a*']); - mm.match(arr, 'a\\*').should.eql([]); - - mm(arr, ['a\\*', '\\*'], {nonull: true}).should.eql(['a*', '*']); - mm(arr, ['a\\*', '\\*']).should.eql(['*']); - - mm(arr, ['a\\*'], {nonull: true}).should.eql(['a*']); - mm(arr, ['a\\*']).should.eql([]); - - mm(arr, ['c*','a\\*','*q*'], {nonull: true}).should.eql(['c','ca','cb','a*','*q*']); - mm(arr, ['c*','a\\*','*q*']).should.eql(['c','ca','cb']); - - mm.match(arr, '"*"*', {nonull: true}).should.eql(['**']); - mm.match(arr, '"*"*').should.eql([]); - - mm.match(arr, '\\**').should.eql(['*']); // `*` is in the fixtures array - }); - - it('should work for escaped paths/dots:', function() { - mm.match(arr, '"\\.\\./*/"', {nonull: true}).should.eql(['../*/']); - mm.match(arr, 's/\\..*//', {nonull: true}).should.eql(['s/..*//']); - }); - - it('Pattern from Larry Wall\'s Configure that caused bash to blow up:', function() { - mm.match(arr, '"/^root:/{s/^[^:]*:[^:]*:\\([^:]*\\).*"\'$\'"/\\1/"', {nonull: true}).should.eql(['/^root:/{s/^[^:]*:[^:]*:([^:]*).*$/1/']); - mm.match(arr, '[a-c]b*').should.eql(['abc','abd','abe','bb','cb']); - }); - - it('Make sure character classes work properly:', function() { - mm.match(arr, '[a-y]*[^c]').should.eql(['abd','abe','bb','bcd','ca','cb','dd','de']); - mm.match(arr, 'a*[^c]').should.eql(['abd','abe']); - - mm.match(['a-b','aXb'], 'a[X-]b').should.eql(['a-b','aXb']); - mm.match(arr, '[^a-c]*').should.eql(['d','dd','de','Beware','*']); - mm.match(['a*b/ooo'], 'a\\*b/*').should.eql(['a*b/ooo']); - mm.match(['a*b/ooo'], 'a\\*?/*').should.eql(['a*b/ooo']); - mm.match(arr, 'a[b]c').should.eql(['abc']); - mm.match(arr, 'a["b"]c').should.eql(['abc']); - mm.match(arr, 'a[\\b]c').should.eql(['abc']); - mm.match(arr, 'a?c').should.eql(['abc']); - mm.match(['man/man1/bash.1'], '*/man*/bash.*').should.eql(['man/man1/bash.1']); - }); - - it('tests with multiple `*\'s:', function() { - mm.match(['bbc','abc', 'bbd'], 'a**c').should.eql(['abc']); - mm.match(['bbc','abc', 'bbd'], 'a***c').should.eql(['abc']); - mm.match(['bbc','abc', 'bbc'], 'a*****?c').should.eql(['abc']); - mm.match(['bbc','abc'], '?*****??').should.eql(['bbc', 'abc']); - mm.match(['bbc','abc'], '*****??').should.eql(['bbc', 'abc']); - mm.match(['bbc','abc'], '?*****?c').should.eql(['bbc', 'abc']); - mm.match(['bbc','abc', 'bbd'], '?***?****c').should.eql(['bbc', 'abc']); - mm.match(['bbc','abc'], '?***?****?').should.eql(['bbc', 'abc']); - mm.match(['bbc','abc'], '?***?****').should.eql(['bbc', 'abc']); - mm.match(['bbc','abc'], '*******c').should.eql(['bbc', 'abc']); - mm.match(['bbc','abc'], '*******?').should.eql(['bbc', 'abc']); - mm.match(['abcdecdhjk'], 'a*cd**?**??k').should.eql(['abcdecdhjk']); - mm.match(['abcdecdhjk'], 'a**?**cd**?**??k').should.eql(['abcdecdhjk']); - mm.match(['abcdecdhjk'], 'a**?**cd**?**??k***').should.eql(['abcdecdhjk']); - mm.match(['abcdecdhjk'], 'a**?**cd**?**??***k').should.eql(['abcdecdhjk']); - mm.match(['abcdecdhjk'], 'a**?**cd**?**??***k**').should.eql(['abcdecdhjk']); - mm.match(['abcdecdhjk'], 'a****c**?**??*****').should.eql(['abcdecdhjk']); - }); - - it('none of these should output anything:', function() { - mm.match(['abc'], '??**********?****?').should.eql([]); - mm.match(['abc'], '??**********?****c').should.eql([]); - mm.match(['abc'], '?************c****?****').should.eql([]); - mm.match(['abc'], '*c*?**').should.eql([]); - mm.match(['abc'], 'a*****c*?**').should.eql([]); - mm.match(['abc'], 'a********???*******').should.eql([]); - mm.match(['a'], '[]').should.eql([]); - mm.match(['['], '[abc').should.eql([]); - }); - }); -}); diff --git a/test/braces.js b/test/braces.js deleted file mode 100644 index 3a2e50ce..00000000 --- a/test/braces.js +++ /dev/null @@ -1,186 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -var path = require('path'); -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = ref.minimatch; -} - -// $echo a/{1..3}/b -describe('brace expansion', function() { - it('should create a regex for brace expansion:', function() { - mm.match(['iii.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm.match(['a/a', 'b/b', 'a/b', 'a/c'], '*/{a,c}').should.eql(['a/a', 'a/c']); - mm.match(['a/a/a', 'b/b/b', 'a/a/b', 'a/a/c'], '**/**/{a,c}').should.eql(['a/a/a', 'a/a/c']); - mm.match(['a/b/d/iii.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm.match(['a/b/c/iii.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm.match(['a/b/cd/iii.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/cd/iii.md']); - mm.match(['a/b/ce/iii.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/ce/iii.md']); - - mm.match(['xyz.md'], 'a/b/c{d,e}/xyz.md').should.eql([]); - mm.match(['a.md', 'b.md', 'c.md', 'd.md'], '{a,b,c}.md').should.eql(['a.md', 'b.md', 'c.md']); - mm.match(['a/b/d/xyz.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm.match(['a/b/c/xyz.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm.match(['a/b/cd/xyz.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/cd/xyz.md']); - mm.match(['a/b/ce/xyz.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/ce/xyz.md']); - mm.match(['a/b/cef/xyz.md', 'a/b/ceg/xyz.md'], 'a/b/c{d,e{f,g}}/*.md').should.eql(['a/b/cef/xyz.md', 'a/b/ceg/xyz.md']); - mm.match(['a/b/ceg/xyz.md'], 'a/b/c{d,e{f,g}}/*.md').should.eql(['a/b/ceg/xyz.md']); - mm.match(['a/b/cd/xyz.md'], 'a/b/c{d,e{f,g}}/*.md').should.eql(['a/b/cd/xyz.md']); - }); - - it('should match negation patterns:', function() { - mm.match(['iii.md'], '!a/b/c{d,e}/*.md').should.eql(['iii.md']); - }); - - it('should match character classes:', function() { - mm.match(['aa', 'ab', 'ac', 'ad', 'bad', 'baa', 'bbaa'], '(a|b*|c)').should.eql(['bad', 'baa', 'bbaa']); - mm.match(['aa', 'ab', 'ac', 'ad', 'bad', 'baa', 'bbaa'], '*(a|{b),c)}').should.eql(['aa', 'ab', 'ac', 'baa', 'bbaa']); - }); - - it('should handle range expansion:', function() { - mm.match(['aa', 'ab', 'ac', 'acc', 'ad', 'ae', 'af', 'ag'], '*{a..e}').should.eql(['aa', 'ab', 'ac', 'acc', 'ad', 'ae']); - }); - - it('should optimize regex when `optimize` is true:', function() { - mm.match(['aa', 'ab', 'ac', 'acc', 'ad', 'ae', 'af', 'ag'], '*{a..e}').should.eql(['aa', 'ab', 'ac', 'acc', 'ad', 'ae']); - mm.match(['./a/b/d/xyz.md'], './a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm.match(['./a/b/c/xyz.md'], './a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm.match(['./a/b/x/cd/bar/xyz.md'], './a/b/**/c{d,e}/**/xyz.md').should.eql(['./a/b/x/cd/bar/xyz.md']); - mm.match(['./a/b/baz/ce/fez/xyz.md'], './a/b/**/c{d,e}/**/xyz.md').should.eql(['./a/b/baz/ce/fez/xyz.md']); - }); -}); - -// tests based on https://github.com/vmeurisse/wildmatch -describe('braces sequences', function() { - it('normal sequence', function() { - mm.match(['1', '2', '3'], '{1..2}').should.eql(['1', '2']); - mm.match(['0', '3'], '{1..2}').should.eql([]); - }); - - it('backward counting', function() { - mm.match(['1023', '1022', '1021'], '{1023..1021}').should.eql(['1023', '1022', '1021']); - mm.match(['1024', '1020'], '{1023..1021}').should.eql([]); - }); - - it('forced step', function() { - mm.match(['1', '4', '10'], '{1..10..3}').should.eql(['1', '4', '10']); - mm.match(['0', '2', '3', '13'], '{1..10..3}').should.eql([]); - }); - - it('forced step, last number is not in the result', function() { - mm.match(['1', '5', '9'], '{1..10..4}').should.eql(['1', '5', '9']); - mm.match(['0', '4', '10', '13'], '{1..10..4}').should.eql([]); - }); - - it('negative start', function() { - mm.match(['-1', '0', '1', '2'], '{-1..2}').should.eql(['-1', '0', '1', '2']) - mm.match(['-2', '3', 'a'], '{-1..2}').should.eql([]); - }); - - it('negative steps', function() { - mm.match(['5', '2', '-1'], '{5..-2..-3}').should.eql(['5', '2', '-1']) - mm.match(['6', '4', '-2'], '{5..-2..-3}').should.eql([]); - }); - - it('start equal end', function() { - mm.match(['1'], '{1..1}').should.eql(['1']) - mm.match(['0', '2', '-1'], '{1..1}').should.eql([]); - }); - - it('invalid steps: wrong sign', function() { - //mm.match(['5', '6', '7'], '{5..7..-3}').should.eql(['5', '6', '7']) - mm.match(['2'], '{5..7..-3}').should.eql([]); - }); - - it('invalid steps: 0', function() { - mm.match(['5', '6', '7'], '{5..7..0}').should.eql(['5', '6', '7']) - mm.match(['4', '8'], '{5..7..0}').should.eql([]); - }); -}); - -describe('braces', function() { - it('Basic braces', function() { - mm.match(['abc', 'zbc'], '{a,z}bc').should.eql(['abc', 'zbc']); - mm.match('bbc', '{a,z}bc').should.eql([]); - mm.match(['bca', 'bcz'], 'bc{a,z}').should.eql(['bca', 'bcz']); - }); - - it('letter sequences', function() { - // normal sequence - mm.match(['a', 'b', 'c'], '{a..c}').should.eql(['a', 'b', 'c']) - mm.match(['d', 'a..c'], '{a..c}').should.eql([]); - - mm.match(['A', 'B', 'C'], '{C..A}').should.eql(['A', 'B', 'C']) - mm.match(['a', 'D'], '{C..A}').should.eql([]); - - mm.match(['a', 'c'], '{a..c..2}').should.eql(['a', 'c']) - mm.match(['b'], '{a..c..2}').should.eql([]); - }); - - it('nested', function() { - mm.match(['abc', '1bc', '2bc'], '{a,{1..2}}bc').should.eql(['abc', '1bc', '2bc']) - mm.match(['bc', '{1..2}bc', '{a,{1..2}}bc'], '{a,{1..2}}bc').should.eql([]); - - mm.match(['br1', 'br2', 'brab', 'bracd', 'brace'], 'br{{1..2},a{b,c{d,e}}}').should.eql(['br1', 'br2', 'brab', 'bracd', 'brace']) - mm.match(['brace1'], 'br{{1..2},a{b,c{d,e}}}').should.eql([]); - }); - - it('escape', function() { - mm.match(['a','b}'], '{a,b\\}}').should.eql([]) - mm.match(['b'], '{a,b\\}}').should.eql([]); - - mm.match(['a,b','c'], '{a\\,b,c}').should.eql(['a,b','c']) - mm.match(['a', 'b'], '{a\\,b,c}').should.eql([]); - - mm.match(['*','a'], '{\\*,a}').should.eql(['*','a']) - mm.match(['xx'], '{\\*,a}').should.eql([]); - }); - - it('invalid', function() { - mm.match(['a'], '{a}').should.eql(['a']) - mm.match(['{a}'], '{a}').should.eql([]) - mm.match(['a'], '{a}').should.eql(['a']); - - mm.match(['{a,b'], '{a,b').should.eql(['{a,b']); - mm.match(['a', 'b'], '{a,b').should.eql([]); - - mm.match(['{a,b}'], '{a,b\\}').should.eql(['{a,b}']) - mm.match(['a', 'b}', '{a,b\\}'], '{a,b\\}').should.eql([]); - - mm.match(['a', '{b}'], '{a,{b}}').should.eql(['a']) - mm.match(['a', '{b}'], '{a,\\{b\\}}').should.eql(['a', '{b}']) - mm.match(['{a,{b}}', 'b'], '{a,{b}}').should.eql(['b']); - - mm.match(['a}', '{b}'], '{a,\\{b}}').should.eql(['a}', '{b}']) - mm.match(['a'], '{a,\\{b}}').should.eql([]); - - mm.match(['{a,b', '{a,c'], '{a,{b,c}').should.eql(['{a,b', '{a,c']); - mm.match(['a', '{b', '{b,c'], '{a,{b,c}').should.eql([]); - - mm.match(['{a..C}'], '{a..C}').should.eql([]); - mm.match(['a', 'C'], '{a..C}').should.eql(['a', 'C']); - - mm.match(['{a..1}'], '{a..1}').should.eql(['{a..1}']); - mm.match(['a', '1'], '{a..1}').should.eql([]); - - mm.match(['{1.1..2.1}'], '{1.1..2.1}').should.eql(['{1.1..2.1}']); - mm.match(['1.1', '2.1'], '{1.1..2.1}').should.eql([]); - - mm.match(['{1..2..1..2}'], '{1..2..1..2}').should.eql([]); - mm.match(['1', '2'], '{1.1..2.1}').should.eql([]); - - mm.match(['{a..b..a}'], '{a..b..a}').should.eql([]); - mm.match(['a', 'b'], '{1.1..2.1}').should.eql([]); - }); -}); diff --git a/test/brackets.js b/test/brackets.js new file mode 100644 index 00000000..cba27362 --- /dev/null +++ b/test/brackets.js @@ -0,0 +1,242 @@ +'use strict'; + +require('mocha'); +var assert = require('assert'); +var argv = require('yargs-parser')(process.argv.slice(2)); +var minimatch = require('minimatch'); +var brackets = require('..'); + +var matcher = argv.mm ? minimatch : brackets; +var isMatch = argv.mm ? minimatch : brackets.isMatch.bind(matcher); + +function match(arr, pattern, expected, options) { + var actual = matcher.match(arr, pattern, options); + assert.deepEqual(actual.sort(), expected.sort()); +} + +describe('POSIX brackets', function() { + it('should support POSIX.2 character classes', function() { + assert(isMatch('e', '[[:xdigit:]]')); + assert(isMatch('a', '[[:alpha:]123]')); + assert(isMatch('1', '[[:alpha:]123]')); + assert(isMatch('9', '[![:alpha:]]')); + }); + + it('should create the equivalent regex character classes for POSIX expressions:', function() { + assert.equal(brackets('foo[[:lower:]]bar').output, 'foo[a-z]bar'); + assert.equal(brackets('foo[[:lower:][:upper:]]bar').output, 'foo[a-zA-Z]bar'); + assert.equal(brackets('[[:alpha:]123]').output, '[a-zA-Z123]'); + assert.equal(brackets('[[:lower:]]').output, '[a-z]'); + assert.equal(brackets('[![:lower:]]').output, '[^a-z]'); + assert.equal(brackets('[[:digit:][:upper:][:space:]]').output, '[0-9A-Z \\t\\r\\n\\v\\f]+'); + assert.equal(brackets('[[:xdigit:]]').output, '[A-Fa-f0-9]'); + assert.equal(brackets('[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]').output, '[a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9\\x21-\\x7Ea-z\\x20-\\x7E\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~ \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]+'); + assert.equal(brackets('[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]').output, '[^a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9a-z \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]+'); + assert.equal(brackets('[a-c[:digit:]x-z]').output, '[a-c0-9x-z]'); + }); + + it('should support regex character classes:', function() { + var arr = ['a c', 'a1c', 'a123c', 'a.c', 'a.xy.zc', 'a.zc', 'abbbbc', 'abbbc', 'abbc', 'abc', 'abq', 'axy zc', 'axy', 'axy.zc', 'axyzc']; + match(arr, 'a[a-z]+c', ['abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc'], 'Should match word characters'); + match(['abc', 'abd'], 'a[bc]d', ['abd'], 'Should match character classes'); + match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]e', ['ace'], 'Should match character class alphabetical ranges'); + match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]', ['ac'], 'Should match character class alphabetical ranges'); + match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[-c]', ['a-', 'ac'], 'Should match character classes with leading dashes'); + match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[c-]', ['a-', 'ac'], 'Should match character classes with trailing dashes'); + match(['a]c', 'abd', 'ace', 'ac', 'a-'], 'a[]]c', ['a]c'], 'Should match bracket literals in character classes'); + match(['a]', 'abd', 'ace', 'ac', 'a-'], 'a]', ['a]'], 'Should match bracket literals'); + match(['a]', 'acd', 'aed', 'ac', 'a-'], 'a[^bc]d', ['aed'], 'Should negation patterns in character classes'); + match(['adc', 'a-c'], 'a[^-b]c', ['adc'], 'Should match negated dashes in character classes'); + match(['adc', 'a]c'], 'a[^]b]c', ['adc'], 'Should match negated brackets in character classes'); + match(['01234', '0123e456', '0123e45g78'], '[\\de]+', ['01234', '0123e456'], 'Should match alpha-numeric characters in character classes'); + match(['01234', '0123e456', '0123e45g78'], '[\\de]*', ['01234', '0123e456'], 'Should match alpha-numeric characters in character classes'); + match(['01234', '0123e456', '0123e45g78'], '[e\\d]+', ['01234', '0123e456'], 'Should match alpha-numeric characters in character classes'); + }); + + it('should not create an invalid posix character class:', function() { + assert.equal(matcher('[:al:]').output, '[al]'); + assert.equal(matcher('[abc[:punct:][0-9]').output, '[abc\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~[0-9]'); + }); + + it('should return `true` when the pattern matches:', function() { + assert(isMatch('a', '[[:lower:]]')); + assert(isMatch('A', '[[:upper:]]')); + assert(isMatch('A', '[[:digit:][:upper:][:space:]]')); + assert(isMatch('1', '[[:digit:][:upper:][:space:]]')); + assert(isMatch(' ', '[[:digit:][:upper:][:space:]]')); + assert(isMatch('5', '[[:xdigit:]]')); + assert(isMatch('f', '[[:xdigit:]]')); + assert(isMatch('D', '[[:xdigit:]]')); + assert(isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); + assert(isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); + assert(isMatch('.', '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); + assert(isMatch('5', '[a-c[:digit:]x-z]')); + assert(isMatch('b', '[a-c[:digit:]x-z]')); + assert(isMatch('y', '[a-c[:digit:]x-z]')); + }); + + it('should return `false` when the pattern does not match:', function() { + assert(!isMatch('A', '[[:lower:]]')); + assert(isMatch('A', '[![:lower:]]')); + assert(!isMatch('a', '[[:upper:]]')); + assert(!isMatch('a', '[[:digit:][:upper:][:space:]]')); + assert(!isMatch('.', '[[:digit:][:upper:][:space:]]')); + assert(!isMatch('.', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); + assert(!isMatch('q', '[a-c[:digit:]x-z]')); + }); +}); + +describe('.makeRe()', function() { + it('should make a regular expression for the given pattern:', function() { + assert.deepEqual(matcher.makeRe('[[:alpha:]123]'), /^(?:[a-zA-Z123])$/); + assert.deepEqual(matcher.makeRe('[![:lower:]]'), /^(?:[^a-z])$/); + }); +}); + +describe('.match()', function() { + it('should return an array of matching strings:', function() { + assert.deepEqual(matcher.match(['a1B', 'a1b'], '[[:alpha:]][[:digit:]][[:upper:]]'), ['a1B']); + assert.deepEqual(matcher.match(['.', 'a', '!'], '[[:digit:][:punct:][:space:]]'), ['.', '!']); + }); +}); + +describe('POSIX: From the test suite for the POSIX.2 (BRE) pattern matching code:', function() { + it('First, test POSIX.2 character classes', function() { + assert(isMatch('e', '[[:xdigit:]]')); + assert(isMatch('1', '[[:xdigit:]]')); + assert(isMatch('a', '[[:alpha:]123]')); + assert(isMatch('1', '[[:alpha:]123]')); + }); + + it('should match using POSIX.2 negation patterns', function() { + assert(isMatch('9', '[![:alpha:]]')); + assert(isMatch('9', '[^[:alpha:]]')); + }); + + it('should match word characters', function() { + assert(isMatch('A', '[[:word:]]')); + assert(isMatch('B', '[[:word:]]')); + assert(isMatch('a', '[[:word:]]')); + assert(isMatch('b', '[[:word:]]')); + }); + + it('should match digits with word class', function() { + assert(isMatch('1', '[[:word:]]')); + assert(isMatch('2', '[[:word:]]')); + }); + + it('should not digits', function() { + assert(isMatch('1', '[[:digit:]]')); + assert(isMatch('2', '[[:digit:]]')); + }); + + it('should not match word characters with digit class', function() { + assert(!isMatch('a', '[[:digit:]]')); + assert(!isMatch('A', '[[:digit:]]')); + }); + + it('should match uppercase alpha characters', function() { + assert(isMatch('A', '[[:upper:]]')); + assert(isMatch('B', '[[:upper:]]')); + }); + + it('should not match lowercase alpha characters', function() { + assert(!isMatch('a', '[[:upper:]]')); + assert(!isMatch('b', '[[:upper:]]')); + }); + + it('should not match digits with upper class', function() { + assert(!isMatch('1', '[[:upper:]]')); + assert(!isMatch('2', '[[:upper:]]')); + }); + + it('should match lowercase alpha characters', function() { + assert(isMatch('a', '[[:lower:]]')); + assert(isMatch('b', '[[:lower:]]')); + }); + + it('should not match uppercase alpha characters', function() { + assert(!isMatch('A', '[[:lower:]]')); + assert(!isMatch('B', '[[:lower:]]')); + }); + + it('should match one lower and one upper character', function() { + assert(isMatch('aA', '[[:lower:]][[:upper:]]')); + assert(!isMatch('AA', '[[:lower:]][[:upper:]]')); + assert(!isMatch('Aa', '[[:lower:]][[:upper:]]')); + }); + + it('should match hexidecimal digits', function() { + assert(isMatch('ababab', '[[:xdigit:]]*')); + assert(isMatch('020202', '[[:xdigit:]]*')); + assert(isMatch('900', '[[:xdigit:]]*')); + }); + + it('should match punctuation characters (\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~)', function() { + assert(isMatch('!', '[[:punct:]]')); + assert(isMatch('?', '[[:punct:]]')); + assert(isMatch('#', '[[:punct:]]')); + assert(isMatch('&', '[[:punct:]]')); + assert(isMatch('@', '[[:punct:]]')); + assert(isMatch('+', '[[:punct:]]')); + assert(isMatch('*', '[[:punct:]]')); + assert(isMatch(':', '[[:punct:]]')); + assert(isMatch('=', '[[:punct:]]')); + assert(isMatch('|', '[[:punct:]]')); + assert(isMatch('|++', '[[:punct:]]*')); + }); + + it('should only match one character', function() { + assert(!isMatch('?*+', '[[:punct:]]')); + }); + + it('should only match zero or more characters', function() { + assert(isMatch('?*+', '[[:punct:]]*')); + assert(isMatch('', '[[:punct:]]*')); + }); + + it('invalid character class expressions are just characters to be matched', function() { + assert(isMatch('a', '[:al:]')); + assert(isMatch('a', '[[:al:]')); + assert(isMatch('!', '[abc[:punct:][0-9]')); + }); + + it('should match the start of a valid sh identifier', function() { + assert(isMatch('PATH', '[_[:alpha:]]*')); + }); + + it('should match the first two characters of a valid sh identifier', function() { + assert(isMatch('PATH', '[_[:alpha:]][_[:alnum:]]*')); + }); + + it('how about A?', function() { + assert(isMatch('9', '[[:digit:]]')); + assert(!isMatch('X', '[[:digit:]]')); + assert(isMatch('aB', '[[:lower:]][[:upper:]]')); + assert.equal(brackets('[_[:alpha:]][_[:alnum:]][_[:alnum:]]*').output, '[_a-zA-Z][_a-zA-Z0-9][_a-zA-Z0-9]*?'); + assert(isMatch('a3', '[[:alpha:][:digit:]]')); + assert(!isMatch('a', '[[:alpha:]\\]')); + }); + + it('OK, what\'s a tab? is it a blank? a space?', function() { + assert(isMatch('\t', '[[:blank:]]')); + assert(isMatch('\t', '[[:space:]]')); + assert(isMatch(' ', '[[:space:]]')); + }); + + it('let\'s check out characters in the ASCII range', function() { + assert(!isMatch('\\377', '[[:ascii:]]')); + assert(!isMatch('9', '[1[:alpha:]123]')); + }); + + it('punctuation', function() { + assert(!isMatch(' ', '[[:punct:]]')); + }); + + it('graph', function() { + assert(isMatch('A', '[[:graph:]]')); + assert(!isMatch('\b', '[[:graph:]]')); + assert(!isMatch('\n', '[[:graph:]]')); + assert(isMatch('\s', '[[:graph:]]')); + }); +}); diff --git a/test/character-classes.js b/test/character-classes.js deleted file mode 100644 index 2ed19298..00000000 --- a/test/character-classes.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -var path = require('path'); -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = ref.minimatch; -} - -describe('character classes', function() { - it('should match character classes:', function() { - mm.match(['ab', 'a', 'bb'], '[ab][ab]').should.eql(['ab', 'bb']); - mm.match(['abc', 'abd', 'abe', 'ab', 'ac'], '[a-c]b*').should.eql(['abc', 'abd', 'abe', 'ab']); - mm.match(['abc', 'abd', 'abe', 'aa', 'ab', 'ac'], '[a-j]*[^c]').should.eql(['abd', 'abe', 'aa', 'ab']); - mm.match(['abc', 'abd', 'abe'], 'a*[^c]').should.eql(['abd', 'abe']); - }); -}); diff --git a/test/contains.js b/test/contains.js index 62f09a57..03ec67a1 100644 --- a/test/contains.js +++ b/test/contains.js @@ -1,200 +1,194 @@ 'use strict'; -require('should'); +var assert = require('assert'); var mm = require('..'); describe('.contains()', function() { - describe('errors:', function() { - it('should throw on undefined args:', function() { - (function() { + describe('error handling', function() { + it('should throw on invalid filepath:', function() { + assert.throws(function() { mm.contains(); - }).should.throw('micromatch.contains(): pattern should be a string.'); + }, /expected filepath to be a string/); }); - it('should throw on bad args:', function() { - (function() { - mm.contains({}); - }).should.throw('micromatch.contains(): pattern should be a string.'); + it('should throw on invalid pattern:', function() { + assert.throws(function() { + mm.contains('', {}); + }, /expected pattern to be a string/); }); }); - it('should correctly deal with empty patterns', function() { - mm.contains('ab', '').should.be.false(); - mm.contains('a', '').should.be.false(); - mm.contains('.', '').should.be.false(); - }); + describe('patterns', function() { + it('should correctly deal with empty patterns', function() { + assert(!mm.contains('ab', '')); + assert(!mm.contains('a', '')); + assert(!mm.contains('.', '')); + }); - it('should return true when the path contains the pattern', function() { - mm.contains('ab', 'b').should.be.true(); - mm.contains('.', '.').should.be.true(); - mm.contains('a/b/c', 'a/b').should.be.true(); - mm.contains('/ab', '/a').should.be.true(); - mm.contains('a', 'a').should.be.true(); - mm.contains('ab', 'a').should.be.true(); - mm.contains('ab', 'ab').should.be.true(); - mm.contains('abcd', 'd').should.be.true(); - mm.contains('abcd', 'c').should.be.true(); - mm.contains('abcd', 'cd').should.be.true(); - mm.contains('abcd', 'bc').should.be.true(); - mm.contains('abcd', 'ab').should.be.true(); - }); + it('should return true when the path contains the pattern', function() { + assert(mm.contains('ab', 'b')); + assert(mm.contains('.', '.')); + assert(mm.contains('a/b/c', 'a/b')); + assert(mm.contains('/ab', '/a')); + assert(mm.contains('a', 'a')); + assert(mm.contains('ab', 'a')); + assert(mm.contains('ab', 'ab')); + assert(mm.contains('abcd', 'd')); + assert(mm.contains('abcd', 'c')); + assert(mm.contains('abcd', 'cd')); + assert(mm.contains('abcd', 'bc')); + assert(mm.contains('abcd', 'ab')); + }); - it('should match with common glob patterns', function() { - mm.contains('a/b/c', 'a/*').should.be.true(); - mm.contains('/ab', '/a').should.be.true(); - mm.contains('/ab', '/*').should.be.true(); - mm.contains('/cd', '/*').should.be.true(); - mm.contains('ab', '*').should.be.true(); - mm.contains('ab', 'ab').should.be.true(); - mm.contains('/ab', '*/a').should.be.true(); - mm.contains('/ab', '*/').should.be.true(); - mm.contains('/ab', '*/*').should.be.true(); - mm.contains('/ab', '/').should.be.true(); - mm.contains('/ab', '/??').should.be.true(); - mm.contains('/ab', '/?b').should.be.true(); - mm.contains('/ab', '/?').should.be.true(); - mm.contains('a/b', '?/?').should.be.true(); - }); + it('should match with common glob patterns', function() { + assert(mm.contains('a/b/c', 'a/*')); + assert(mm.contains('/ab', '/a')); + assert(mm.contains('/ab', '/*')); + assert(mm.contains('/cd', '/*')); + assert(mm.contains('ab', '*')); + assert(mm.contains('ab', 'ab')); + assert(mm.contains('/ab', '*/a')); + assert(mm.contains('/ab', '*/')); + assert(mm.contains('/ab', '*/*')); + assert(mm.contains('/ab', '/')); + assert(mm.contains('/ab', '/??')); + assert(mm.contains('/ab', '/?b')); + assert(mm.contains('/ab', '/?')); + assert(mm.contains('a/b', '?/?')); + }); - it('should return false when the path does not contain the pattern', function() { - mm.contains('/ab', '?/?').should.be.false(); - mm.contains('ab', '*/*').should.be.false(); - mm.contains('abcd', 'f').should.be.false(); - mm.contains('ab', 'c').should.be.false(); - mm.contains('ab', '/a').should.be.false(); - mm.contains('/ab', 'a/*').should.be.false(); - mm.contains('ef', '/*').should.be.false(); - mm.contains('ab', './*').should.be.false(); - }); + it('should return false when the path does not contain the pattern', function() { + assert(!mm.contains('/ab', '?/?')); + assert(!mm.contains('ab', '*/*')); + assert(!mm.contains('abcd', 'f')); + assert(!mm.contains('ab', 'c')); + assert(!mm.contains('ab', '/a')); + assert(!mm.contains('/ab', 'a/*')); + assert(!mm.contains('ef', '/*')); + assert(!mm.contains('ab', './*')); + }); - it('should match files that contain the given extension:', function() { - mm.contains('.md', '.m').should.be.true(); - mm.contains('.c.md', '.*.md').should.be.true(); - mm.contains('c.md', '*.md').should.be.true(); - mm.contains('a/b/c.md', '.md').should.be.true(); - mm.contains('a/b/c.md', 'a/*/*.md').should.be.true(); - mm.contains('a/b/c.md', '**/*.md').should.be.true(); - mm.contains('c.md', '*.md').should.be.true(); - mm.contains('.c.md', '.md').should.be.true(); - mm.contains('.c.md', '.c.').should.be.true(); - mm.contains('a/b/c.md', '*.md').should.be.true(); - mm.contains('a/b/c/c.md', '*.md').should.be.true(); - mm.contains('.c.md', '*.md').should.be.true(); - }); + it('should match files that contain the given extension:', function() { + assert(mm.contains('.md', '.m')); + assert(mm.contains('.c.md', '.*.md')); + assert(mm.contains('c.md', '*.md')); + assert(mm.contains('a/b/c.md', '.md')); + assert(mm.contains('a/b/c.md', 'a/*/*.md')); + assert(mm.contains('a/b/c.md', '**/*.md')); + assert(mm.contains('c.md', '*.md')); + assert(mm.contains('.c.md', '.md')); + assert(mm.contains('.c.md', '.c.')); + assert(mm.contains('a/b/c.md', '*.md')); + assert(mm.contains('a/b/c/c.md', '*.md')); + assert(mm.contains('.c.md', '*.md')); + }); - it('should not match files that do not contain the given extension:', function() { - mm.contains('.md', '*.md').should.be.false(); - mm.contains('a/b/c/c.md', 'c.js').should.be.false(); - mm.contains('a/b/c.md', 'a/*.md').should.be.false(); - }); + it('should not match files that do not contain the given extension:', function() { + assert(!mm.contains('.md', '*.md')); + assert(!mm.contains('a/b/c/c.md', 'c.js')); + assert(!mm.contains('a/b/c.md', 'a/*.md')); + }); - it('should match dotfiles when a dot is explicitly defined in the pattern:', function() { - mm.contains('.a', '.a').should.be.true(); - mm.contains('.ab', '.*').should.be.true(); - mm.contains('.ab', '.a*').should.be.true(); - mm.contains('.abc', '.a').should.be.true(); - mm.contains('.b', '.b*').should.be.true(); - mm.contains('.md', '.md').should.be.true(); - mm.contains('.c.md', '*.md').should.be.true(); - mm.contains('a/.c.md', 'a/.c.md').should.be.true(); - mm.contains('a/b/c/.xyz.md', 'a/b/c/.*.md').should.be.true(); - mm.contains('a/.c.md', '*.md').should.be.true(); - mm.contains('a/b/c/d.a.md', 'a/b/c/*.md').should.be.true(); - }); + it('should match dotfiles when a dot is explicitly defined in the pattern:', function() { + assert(mm.contains('.a', '.a')); + assert(mm.contains('.ab', '.*')); + assert(mm.contains('.ab', '.a*')); + assert(mm.contains('.abc', '.a')); + assert(mm.contains('.b', '.b*')); + assert(mm.contains('.md', '.md')); + assert(mm.contains('.c.md', '*.md')); + assert(mm.contains('a/.c.md', 'a/.c.md')); + assert(mm.contains('a/b/c/.xyz.md', 'a/b/c/.*.md')); + assert(mm.contains('a/.c.md', '*.md')); + assert(mm.contains('a/b/c/d.a.md', 'a/b/c/*.md')); + }); - it('should match dotfiles when `dot` or `dotfiles` is set:', function() { - mm.contains('a/b/c/.xyz.md', '.*.md', {dot: true}).should.be.true(); - mm.contains('.c.md', '*.md', {dot: true}).should.be.true(); - mm.contains('.c.md', '.*', {dot: true}).should.be.true(); - mm.contains('a/b/c/.xyz.md', '**/*.md', {dot: true}).should.be.true(); - mm.contains('a/b/c/.xyz.md', '**/.*.md', {dot: true}).should.be.true(); - mm.contains('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true}).should.be.true(); - mm.contains('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true}).should.be.true(); - }); + it('should match dotfiles when `dot` or `dotfiles` is set:', function() { + assert(mm.contains('a/b/c/.xyz.md', '.*.md', {dot: true})); + assert(mm.contains('.c.md', '*.md', {dot: true})); + assert(mm.contains('.c.md', '.*', {dot: true})); + assert(mm.contains('a/b/c/.xyz.md', '**/*.md', {dot: true})); + assert(mm.contains('a/b/c/.xyz.md', '**/.*.md', {dot: true})); + assert(mm.contains('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true})); + assert(mm.contains('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true})); + }); - it('should not match dotfiles when `dot` or `dotfiles` is not set:', function() { - mm.contains('.a', '*.md').should.be.false(); - mm.contains('.ba', '.a').should.be.false(); - mm.contains('.a.md', 'a/b/c/*.md').should.be.false(); - mm.contains('.ab', '*.*').should.be.false(); - mm.contains('.md', 'a/b/c/*.md').should.be.false(); - mm.contains('.txt', '.md').should.be.false(); - mm.contains('.verb.txt', '*.md').should.be.false(); - mm.contains('a/b/d/.md', 'a/b/c/*.md').should.be.false(); - }); + it('should not match dotfiles when `dot` or `dotfiles` is not set:', function() { + assert(!mm.contains('.a', '*.md')); + assert(!mm.contains('.ba', '.a')); + assert(!mm.contains('.a.md', 'a/b/c/*.md')); + assert(!mm.contains('.ab', '*.*')); + assert(!mm.contains('.md', 'a/b/c/*.md')); + assert(!mm.contains('.txt', '.md')); + assert(!mm.contains('.verb.txt', '*.md')); + assert(!mm.contains('a/b/d/.md', 'a/b/c/*.md')); + }); - it('should match file paths:', function() { - mm.contains('a/b/c/xyz.md', 'a/b/c/*.md').should.be.true(); - mm.contains('a/bb/c/xyz.md', 'a/*/c/*.md').should.be.true(); - mm.contains('a/bbbb/c/xyz.md', 'a/*/c/*.md').should.be.true(); - mm.contains('a/bb.bb/c/xyz.md', 'a/*/c/*.md').should.be.true(); - mm.contains('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md').should.be.true(); - mm.contains('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md').should.be.true(); - }); + it('should match file paths:', function() { + assert(mm.contains('a/b/c/xyz.md', 'a/b/c/*.md')); + assert(mm.contains('a/bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.contains('a/bbbb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.contains('a/bb.bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.contains('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md')); + assert(mm.contains('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md')); + }); - it('should return true when full file paths are matched:', function() { - mm.contains('a/.b', 'a/.*').should.be.true(); - mm.contains('a/.b', 'a/').should.be.true(); - mm.contains('a/b/z/.a', 'b/z').should.be.true(); - mm.contains('a/b/z/.a', 'a/*/z/.a').should.be.true(); - mm.contains('a/b/c/d/e/z/c.md', 'a/**/z/*.md').should.be.true(); - mm.contains('a/b/c/d/e/z/c.md', 'b/c/d/e').should.be.true(); - mm.contains('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md').should.be.true(); - mm.contains('a/b/c/cd/bbb/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.true(); - mm.contains('a/b/baz/ce/fez/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.true(); - }); + it('should return true when full file paths are matched:', function() { + assert(mm.contains('a/.b', 'a/.*')); + assert(mm.contains('a/.b', 'a/')); + assert(mm.contains('a/b/z/.a', 'b/z')); + assert(mm.contains('a/b/z/.a', 'a/*/z/.a')); + assert(mm.contains('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.contains('a/b/c/d/e/z/c.md', 'b/c/d/e')); + assert(mm.contains('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); + }); - it('question marks should not match slashes:', function() { - mm.contains('aaa/bbb', 'aaa?bbb').should.be.false(); - }); + it('question marks should not match slashes:', function() { + assert(!mm.contains('aaa/bbb', 'aaa?bbb')); + }); - it('should match path segments:', function() { - mm.contains('aaa', 'aaa').should.be.true(); - mm.contains('aaa', 'aa').should.be.true(); - mm.contains('aaa/bbb', 'aaa/bbb').should.be.true(); - mm.contains('aaa/bbb', 'aaa/*').should.be.true(); - mm.contains('aaa/bba/ccc', 'aaa/*').should.be.true(); - mm.contains('aaa/bba/ccc', 'aaa/**').should.be.true(); - mm.contains('aaa/bba/ccc', 'aaa*').should.be.true(); - mm.contains('aaa/bba/ccc', 'aaa**').should.be.true(); - mm.contains('aaa/bba/ccc', 'aaa/*ccc').should.be.false(); - mm.contains('aaa/bba/ccc', 'aaa/**ccc').should.be.true(); - mm.contains('aaa/bba/ccc', 'aaa/*z').should.be.false(); - mm.contains('aaa/bba/ccc', 'aaa/**z').should.be.false(); - mm.contains('aaa/bbb', 'aaa[/]bbb').should.be.true(); - mm.contains('aaa', '*/*/*').should.be.false(); - mm.contains('aaa/bbb', '*/*/*').should.be.false(); - mm.contains('aaa/bba/ccc', '*/*/*').should.be.true(); - mm.contains('aaa/bb/aa/rr', '*/*/*').should.be.true(); - mm.contains('abzzzejklhi', '*j*i').should.be.true(); - mm.contains('ab/zzz/ejkl/hi', '*/*z*/*/*i').should.be.true(); - mm.contains('ab/zzz/ejkl/hi', '*/*jk*/*i').should.be.true(); - }); + it('should match path segments:', function() { + assert(mm.contains('aaa', 'aaa')); + assert(mm.contains('aaa', 'aa')); + assert(mm.contains('aaa/bbb', 'aaa/bbb')); + assert(mm.contains('aaa/bbb', 'aaa/*')); + assert(mm.contains('aaa/bba/ccc', 'aaa/*')); + assert(mm.contains('aaa/bba/ccc', 'aaa/**')); + assert(mm.contains('aaa/bba/ccc', 'aaa*')); + assert(mm.contains('aaa/bba/ccc', 'aaa**')); + assert(!mm.contains('aaa/bba/ccc', 'aaa/*ccc')); + assert(mm.contains('aaa/bba/ccc', 'aaa/**ccc')); + assert(!mm.contains('aaa/bba/ccc', 'aaa/*z')); + assert(!mm.contains('aaa/bba/ccc', 'aaa/**z')); + assert(mm.contains('aaa/bbb', 'aaa[/]bbb')); + assert(!mm.contains('aaa', '*/*/*')); + assert(!mm.contains('aaa/bbb', '*/*/*')); + assert(mm.contains('aaa/bba/ccc', '*/*/*')); + assert(mm.contains('aaa/bb/aa/rr', '*/*/*')); + assert(mm.contains('abzzzejklhi', '*j*i')); + assert(mm.contains('ab/zzz/ejkl/hi', '*/*z*/*/*i')); + assert(mm.contains('ab/zzz/ejkl/hi', '*/*jk*/*i')); + }); - it('should return false when full file paths are not matched:', function() { - mm.contains('a/b/z/.a', 'b/a').should.be.false(); - mm.contains('a/.b', 'a/**/z/*.md').should.be.false(); - mm.contains('a/b/z/.a', 'a/**/z/*.a').should.be.false(); - mm.contains('a/b/z/.a', 'a/*/z/*.a').should.be.false(); - mm.contains('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md').should.be.false(); - mm.contains('a/b/d/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.contains('a/b/c/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.false(); - }); + it('should return false when full file paths are not matched:', function() { + assert(!mm.contains('a/b/z/.a', 'b/a')); + assert(!mm.contains('a/.b', 'a/**/z/*.md')); + assert(!mm.contains('a/b/z/.a', 'a/**/z/*.a')); + assert(!mm.contains('a/b/z/.a', 'a/*/z/*.a')); + assert(!mm.contains('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md')); + }); - it('should match paths with leading `./`:', function() { - mm.contains('./.a', 'a/**/z/*.md').should.be.false(); - mm.contains('./a/b/z/.a', 'a/**/z/.a').should.be.true(); - mm.contains('./a/b/z/.a', './a/**/z/.a').should.be.true(); - mm.contains('./a/b/c/d/e/z/c.md', 'a/**/z/*.md').should.be.true(); - mm.contains('./a/b/c/d/e/z/c.md', './a/**/z/*.md').should.be.true(); - mm.contains('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md').should.be.false(); - mm.contains('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md').should.be.true(); - mm.contains('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md').should.be.true(); - mm.contains('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md').should.be.true(); - mm.contains('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md').should.be.false(); - mm.contains('./a/b/d/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.contains('./a/b/c/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.contains('./a/b/c/cd/bbb/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.true(); - mm.contains('./a/b/baz/ce/fez/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.true(); + it('should match paths with leading `./`:', function() { + assert(!mm.contains('./.a', 'a/**/z/*.md')); + assert(mm.contains('./a/b/z/.a', 'a/**/z/.a')); + assert(mm.contains('./a/b/z/.a', './a/**/z/.a')); + assert(mm.contains('./a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.contains('./a/b/c/d/e/z/c.md', './a/**/z/*.md')); + assert(!mm.contains('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.contains('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.contains('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md')); + assert(mm.contains('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md')); + assert(!mm.contains('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md')); + }); }); }); diff --git a/test/dotfiles.js b/test/dotfiles.js index abdebda6..4bd1ef21 100644 --- a/test/dotfiles.js +++ b/test/dotfiles.js @@ -1,149 +1,85 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License - */ - 'use strict'; -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); +var assert = require('assert'); var mm = require('..'); -if ('minimatch' in argv) { - mm = ref; -} - describe('dotfiles', function() { describe('file name', function() { it('should not match a dot when the dot is not explicitly defined', function() { - mm.isMatch('.bashrc', '*bashrc').should.be.false(); - mm.isMatch('.bashrc', '[.]bashrc').should.be.false(); - mm.isMatch('.bashrc', '?bashrc').should.be.false(); + assert(!mm.isMatch('.bashrc', '*bashrc')); + assert(!mm.isMatch('.bashrc', '?bashrc')); }); it('should match a dot when the dot is explicitly defined', function() { - mm.isMatch('.bashrc', '.[b]ashrc').should.be.true(); - mm.isMatch('.bashrc', '.ba?hrc').should.be.true(); - mm.isMatch('.bashrc', '.bashr*').should.be.true(); + assert(mm.isMatch('.bashrc', '[.]bashrc')); + assert(mm.isMatch('.bashrc', '.[b]ashrc')); + assert(mm.isMatch('.bashrc', '.bashr*')); + assert(!mm.isMatch('.bashrc', '.ba?hrc')); }); }); describe('multiple directories', function() { it('should not match a dot when the dot is not explicitly defined', function() { - mm.isMatch('/.bashrc', '/*bashrc').should.be.false(); - mm.isMatch('/.bashrc', '/?bashrc').should.be.false(); - mm.isMatch('/.bashrc', '/[.]bashrc').should.be.false(); - mm.isMatch('/.bashrc', '*/*bashrc').should.be.false(); - mm.isMatch('/.bashrc', '*/?bashrc').should.be.false(); - mm.isMatch('/.bashrc', '*/[.]bashrc').should.be.false(); - mm.isMatch('/.bashrc', '**/*bashrc').should.be.false(); - mm.isMatch('/.bashrc', '**/?bashrc').should.be.false(); - mm.isMatch('/.bashrc', '**/[.]bashrc').should.be.false(); - mm.isMatch('a/.bashrc', '*/*bashrc').should.be.false(); - mm.isMatch('a/.bashrc', '*/?bashrc').should.be.false(); - mm.isMatch('a/.bashrc', '*/[.]bashrc').should.be.false(); - mm.isMatch('a/b/.bashrc', '**/*bashrc').should.be.false(); - mm.isMatch('a/b/.bashrc', '**/?bashrc').should.be.false(); - mm.isMatch('a/b/.bashrc', '**/[.]bashrc').should.be.false(); + assert(!mm.isMatch('/.bashrc', '**/*bashrc')); + assert(!mm.isMatch('/.bashrc', '**/?bashrc')); + assert(!mm.isMatch('/.bashrc', '*/*bashrc')); + assert(!mm.isMatch('/.bashrc', '*/?bashrc')); + assert(!mm.isMatch('/.bashrc', '/*bashrc')); + assert(!mm.isMatch('/.bashrc', '/?bashrc')); + assert(!mm.isMatch('a/.bashrc', '*/*bashrc')); + assert(!mm.isMatch('a/.bashrc', '*/?bashrc')); + assert(!mm.isMatch('a/b/.bashrc', '**/*bashrc')); + assert(!mm.isMatch('a/b/.bashrc', '**/?bashrc')); + assert(mm.isMatch('/.bashrc', '**/[.]bashrc')); + assert(mm.isMatch('/.bashrc', '*/[.]bashrc')); + assert(mm.isMatch('/.bashrc', '/[.]bashrc')); + assert(mm.isMatch('a/.bashrc', '*/[.]bashrc')); + assert(mm.isMatch('a/b/.bashrc', '**/[.]bashrc')); }); it('should match a dot when the dot is explicitly defined', function() { - mm.isMatch('/.bashrc', '**/.[b]ashrc').should.be.true(); - mm.isMatch('/.bashrc', '**/.ba?hrc').should.be.true(); - mm.isMatch('/.bashrc', '**/.bashr*').should.be.true(); - mm.isMatch('a/.bashrc', '*/.[b]ashrc').should.be.true(); - mm.isMatch('a/.bashrc', '*/.ba?hrc').should.be.true(); - mm.isMatch('a/.bashrc', '*/.bashr*').should.be.true(); - mm.isMatch('a/b/.bashrc', '**/.[b]ashrc').should.be.true(); - mm.isMatch('a/b/.bashrc', '**/.ba?hrc').should.be.true(); - mm.isMatch('a/b/.bashrc', '**/.bashr*').should.be.true(); + assert(mm.isMatch('/.bashrc', '**/.[b]ashrc')); + assert(mm.isMatch('/.bashrc', '**/.bashr*')); + assert(mm.isMatch('a/.bashrc', '*/.[b]ashrc')); + assert(mm.isMatch('a/.bashrc', '*/.bashr*')); + assert(mm.isMatch('a/b/.bashrc', '**/.[b]ashrc')); + assert(mm.isMatch('a/b/.bashrc', '**/.bashr*')); }); }); describe('options.dot', function() { it('should match dotfiles when `options.dot` is true', function() { - mm.isMatch('.bashrc', '*bashrc', {dot: true}).should.be.true(); - mm.isMatch('.bashrc', '[.]bashrc', {dot: true}).should.be.true(); - mm.isMatch('.bashrc', '?bashrc', {dot: true}).should.be.true(); - - mm.isMatch('a/b/.bashrc', '*bashrc', {dot: true, matchBase: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '[.]bashrc', {dot: true, matchBase: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '?bashrc', {dot: true, matchBase: true}).should.be.true(); - - mm.isMatch('a/b/.bashrc', '**/*bashrc', {dot: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '**/.[b]ashrc', {dot: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '**/[.]bashrc', {dot: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '**/?bashrc', {dot: true}).should.be.true(); + assert(mm.isMatch('.bashrc', '*bashrc', {dot: true})); + assert(mm.isMatch('.bashrc', '[.]bashrc', {dot: true})); + assert(mm.isMatch('.bashrc', '?bashrc', {dot: true})); + + assert(mm.isMatch('a/b/.bashrc', '*bashrc', {dot: true, matchBase: true})); + assert(mm.isMatch('a/b/.bashrc', '[.]bashrc', {dot: true, matchBase: true})); + assert(mm.isMatch('a/b/.bashrc', '?bashrc', {dot: true, matchBase: true})); + + assert(mm.isMatch('a/b/.bashrc', '**/*bashrc', {dot: true})); + assert(mm.isMatch('a/b/.bashrc', '**/.[b]ashrc', {dot: true})); + assert(mm.isMatch('a/b/.bashrc', '**/[.]bashrc', {dot: true})); + assert(mm.isMatch('a/b/.bashrc', '**/?bashrc', {dot: true})); }); it('should not match dotfiles when `options.dot` is false', function() { - mm.isMatch('a/b/.bashrc', '*bashrc', {dot: false, matchBase: true}).should.be.false(); - mm.isMatch('a/b/.bashrc', '[.]bashrc', {dot: false, matchBase: true}).should.be.false(); - mm.isMatch('a/b/.bashrc', '?bashrc', {dot: false, matchBase: true}).should.be.false(); - - mm.isMatch('a/b/.bashrc', '**/*bashrc', {dot: false}).should.be.false(); - mm.isMatch('a/b/.bashrc', '**/[.]bashrc', {dot: false}).should.be.false(); - mm.isMatch('a/b/.bashrc', '**/?bashrc', {dot: false}).should.be.false(); - }); - }); - - describe('options.dotfiles', function() { - it('should match a dotfile when `options.dotfiles` is true', function() { - mm.isMatch('.bashrc', '*bashrc', {dotfiles: true}).should.be.true(); - mm.isMatch('.bashrc', '[.]bashrc', {dotfiles: true}).should.be.true(); - mm.isMatch('.bashrc', '?bashrc', {dotfiles: true}).should.be.true(); - - mm.isMatch('a/b/.bashrc', '*bashrc', {dotfiles: true, matchBase: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '[.]bashrc', {dotfiles: true, matchBase: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '?bashrc', {dotfiles: true, matchBase: true}).should.be.true(); + assert(mm.isMatch('a/b/.bashrc', '[.]bashrc', {dot: false, matchBase: true})); + assert(mm.isMatch('a/b/.bashrc', '**/[.]bashrc', {dot: false})); - mm.isMatch('a/b/.bashrc', '**/*bashrc', {dotfiles: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '**/.[b]ashrc', {dotfiles: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '**/[.]bashrc', {dotfiles: true}).should.be.true(); - mm.isMatch('a/b/.bashrc', '**/?bashrc', {dotfiles: true}).should.be.true(); - }); - - it('should not match a dotfile when `options.dotfiles` is false', function() { - mm.isMatch('.bashrc', '*bashrc', {dotfiles: false}).should.be.false(); - mm.isMatch('.bashrc', '[.]bashrc', {dotfiles: false}).should.be.false(); - mm.isMatch('.bashrc', '?bashrc', {dotfiles: false}).should.be.false(); - - mm.isMatch('a/b/.bashrc', '*bashrc', {dotfiles: false, matchBase: false}).should.be.false(); - mm.isMatch('a/b/.bashrc', '[.]bashrc', {dotfiles: false, matchBase: false}).should.be.false(); - mm.isMatch('a/b/.bashrc', '?bashrc', {dotfiles: false, matchBase: false}).should.be.false(); + assert(!mm.isMatch('a/b/.bashrc', '*bashrc', {dot: false, matchBase: true})); + assert(!mm.isMatch('a/b/.bashrc', '?bashrc', {dot: false, matchBase: true})); - mm.isMatch('a/b/.bashrc', '**/*bashrc', {dotfiles: false}).should.be.false(); - mm.isMatch('a/b/.bashrc', '**/[.]bashrc', {dotfiles: false}).should.be.false(); - mm.isMatch('a/b/.bashrc', '**/?bashrc', {dotfiles: false}).should.be.false(); - }); - - it('should not match a dotfile when `options.dotdirs` is true', function() { - // mm.isMatch('.bashrc', '*bashrc', {dotdirs: true}).should.be.false(); - mm.isMatch('.bashrc', '[.]bashrc', {dotdirs: true}).should.be.true(); - // mm.isMatch('.bashrc', '?bashrc', {dotdirs: true}).should.be.false(); - - mm.isMatch('a/b/.bashrc', '*bashrc', {dotdirs: true, matchBase: false}).should.be.false(); - mm.isMatch('a/b/.bashrc', '[.]bashrc', {dotdirs: true, matchBase: false}).should.be.false(); - mm.isMatch('a/b/.bashrc', '?bashrc', {dotdirs: true, matchBase: false}).should.be.false(); - - // mm.isMatch('a/b/.bashrc', '**/*bashrc', {dotdirs: true}).should.be.false(); - mm.isMatch('a/b/.bashrc', '**/[.]bashrc', {dotdirs: true}).should.be.true(); - // mm.isMatch('a/b/.bashrc', '**/?bashrc', {dotdirs: true}).should.be.false(); + assert(!mm.isMatch('a/b/.bashrc', '**/*bashrc', {dot: false})); + assert(!mm.isMatch('a/b/.bashrc', '**/?bashrc', {dot: false})); }); }); - describe('options.dot / options.dotfiles', function() { + describe('options.dot', function() { it('should match a dot `options.dot` is true', function() { - mm.isMatch('.bashrc', '*bashrc', {dot: true}).should.be.true(); - mm.isMatch('.bashrc', '[.]bashrc', {dot: true}).should.be.true(); - mm.isMatch('.bashrc', '?bashrc', {dot: true}).should.be.true(); - - mm.isMatch('.bashrc', '*bashrc', {dotfiles: true}).should.be.true(); - mm.isMatch('.bashrc', '[.]bashrc', {dotfiles: true}).should.be.true(); - mm.isMatch('.bashrc', '?bashrc', {dotfiles: true}).should.be.true(); + assert(mm.isMatch('.bashrc', '*bashrc', {dot: true})); + assert(mm.isMatch('.bashrc', '[.]bashrc', {dot: true})); + assert(mm.isMatch('.bashrc', '?bashrc', {dot: true})); }); }); }); diff --git a/test/expand.js b/test/expand.js deleted file mode 100644 index be68b8c2..00000000 --- a/test/expand.js +++ /dev/null @@ -1,59 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License - */ - -'use strict'; - -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = ref.minimatch; -} - -describe('expand()', function() { - describe('errors:', function() { - it('should throw on undefined args:', function() { - (function() { - mm.expand(); - }).should.throw('micromatch.expand(): argument should be a string.'); - }); - - it('should throw on bad args:', function() { - (function() { - mm.expand({}); - }).should.throw('micromatch.expand(): argument should be a string.'); - }); - }); - - it('should return an object with information about the glob pattern', function() { - mm.expand('*').should.be.an.Object(); - mm.expand('*').should.have.properties('options', 'pattern'); - }); - - it('should return a string on the `glob` property:', function() { - mm.expand('*').pattern.should.be.a.String(); - mm.expand('*').pattern.should.equal('(?!\\.)(?=.)[^/]*?'); - mm.expand('*.{js,md}').pattern.should.equal('(?!\\.)(?=.)[^/]*?\\.(js|md)'); - mm.expand('{a,b\\}').pattern.should.eql('{a,b}'); - }); - - it('should escape dots:', function() { - mm.expand('.').pattern.should.equal('\\.'); - }); - - it('should expand patterns for file names:', function() { - mm.expand('*.md').pattern.should.equal('(?!\\.)(?=.)[^/]*?\\.md'); - mm.expand('*.md', {dot: true}).pattern.should.equal('(?!(?:\\/|^)\\.{1,2}($|\\/))(?=.)[^/]*?\\.md'); - mm.expand('.*.md').pattern.should.equal('\\.(?!(?:\\/|^)\\.{1,2}($|\\/))(?=.)[^/]*?\\.md'); - }); - - it('should expand extglobs', function() { - mm.expand('?(a*|b)').pattern.should.equal('(?:a[^/]*?|b|)'); - }); -}); diff --git a/test/extglob-char-class.js b/test/extglob-char-class.js deleted file mode 100644 index a8150ddc..00000000 --- a/test/extglob-char-class.js +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('should'); -var assert = require('assert'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = ref.minimatch; -} - -/** - * minimatch and micromatch fail on all of these - */ - -describe.skip('character classes in extglobs', function() { - it('should match using POSIX character classes in extglobs:', function() { - assert.equal(mm.isMatch('a.c', '+([[:alpha:].])'), true); - assert.equal(mm.isMatch('a.c', '+([[:alpha:].])+([[:alpha:].])'), true); - assert.equal(mm.isMatch('a.c', '*([[:alpha:].])'), true); - assert.equal(mm.isMatch('a.c', '*([[:alpha:].])*([[:alpha:].])'), true); - - assert.equal(mm.isMatch('a.c', '?([[:alpha:].])?([[:alpha:].])?([[:alpha:].])'), true); - assert.equal(mm.isMatch('a.c', '@([[:alpha:].])@([[:alpha:].])@([[:alpha:].])'), true); - - assert.equal(mm.isMatch('.', '!([[:alpha:].])'), false); - assert.equal(mm.isMatch('.', '?([[:alpha:].])'), true); - assert.equal(mm.isMatch('.', '@([[:alpha:].])'), true); - }); -}); diff --git a/test/extglob.js b/test/extglob.js deleted file mode 100644 index d2b070e6..00000000 --- a/test/extglob.js +++ /dev/null @@ -1,68 +0,0 @@ -'use strict'; - -require('should'); -var assert = require('assert'); -var mm = require('..'); - -describe('basic extglobs', function() { - it('should NOT optimize extglobs if `options.noextglob` is `true`:', function() { - var opts = { noextglob: true }; - assert.equal(mm.expand('a?(b*)', opts).pattern, 'a[^/](b(?!(?:\\/|^)\\.{1,2}($|\\/))(?=.)[^/]*?)'); - assert.equal(mm.expand('?(a.*|b)', opts).pattern, '(?!\\.)(?=.)[^/](a.(?!(?:\\/|^)\\.{1,2}($|\\/))(?=.)[^/]*?|b)'); - assert.equal(mm.expand('a?(b*)', opts).pattern, 'a[^/](b(?!(?:\\/|^)\\.{1,2}($|\\/))(?=.)[^/]*?)'); - assert.equal(mm.expand('a?(b*)', opts).pattern, 'a[^/](b(?!(?:\\/|^)\\.{1,2}($|\\/))(?=.)[^/]*?)'); - assert.equal(mm.expand('?(a*|b)', opts).pattern, '(?!\\.)(?=.)[^/](a(?!(?:\\/|^)\\.{1,2}($|\\/))(?=.)[^/]*?|b)'); - assert.equal(mm.expand('?(a*|b)', opts).pattern, '(?!\\.)(?=.)[^/](a(?!(?:\\/|^)\\.{1,2}($|\\/))(?=.)[^/]*?|b)'); - }); - - it('should optimize extglobs if `options.noextglob` is `false`:', function() { - var opts = { noextglob: false }; - assert.equal(mm.expand('a?(b*)', opts).pattern, 'a(?:b[^/]*?|)'); - assert.equal(mm.expand('?(a.*|b)', opts).pattern, '(?:a\\.[^/]*?|b|)'); - assert.equal(mm.expand('a?(b*)', opts).pattern, 'a(?:b[^/]*?|)'); - assert.equal(mm.expand('a?(b*)', opts).pattern, 'a(?:b[^/]*?|)'); - assert.equal(mm.expand('?(a*|b)', opts).pattern, '(?:a[^/]*?|b|)'); - assert.equal(mm.expand('?(a*|b)', opts).pattern, '(?:a[^/]*?|b|)'); - }); - - it('should optimize extglobs if `options.noextglob` is undefined:', function() { - assert.equal(mm.expand('a?(b*)').pattern, 'a(?:b[^/]*?|)'); - assert.equal(mm.expand('?(a.*|b)').pattern, '(?:a\\.[^/]*?|b|)'); - assert.equal(mm.expand('a?(b*)').pattern, 'a(?:b[^/]*?|)'); - assert.equal(mm.expand('a?(b*)').pattern, 'a(?:b[^/]*?|)'); - assert.equal(mm.expand('?(a*|b)').pattern, '(?:a[^/]*?|b|)'); - assert.equal(mm.expand('?(a*|b)').pattern, '(?:a[^/]*?|b|)'); - }); - - it('should match extglobs:', function() { - mm.match(['a', 'b', 'c'], '(a|c)').should.eql(['a', 'c']); - mm.match(['axb'], 'a?(b*)').should.eql([]); - mm.match(['ax'], '?(a.*|b)').should.eql([]); - mm.match(['ax'], 'a?(b*)').should.eql([]); - mm.match(['ax'], 'a?(b*)').should.eql([]); - mm.match(['yax', 'b'], '?(a*|b)').should.eql(['b']); - mm.match(['ax'], '?(a*|b)').should.eql(['ax']); - }); - - it('should support matching with extglobs:', function() { - mm.isMatch('foo/abbbb', 'foo/a?(b*)').should.be.true(); - mm.isMatch('abbbb', 'a!(b*)').should.be.false(); - mm.isMatch('foo/abbbb', 'foo/a!(b*)').should.be.false(); - mm.isMatch('abbbb', 'a?(b*)').should.be.true(); - mm.isMatch('abbbb', 'a?(b*)').should.be.true(); - mm.isMatch('abx', 'a?(b*)').should.be.true(); - mm.isMatch('ax', '?(a*|b)').should.be.true(); - mm.isMatch('ax', 'a?(b*)').should.be.false(); - mm.isMatch('ax', 'a?(b*)').should.be.false(); - mm.isMatch('ax', 'a?(b+)').should.be.false(); - mm.isMatch('axb', 'a?(b*)').should.be.false(); - mm.isMatch('axb', 'a?(b*)').should.be.false(); - mm.isMatch('axbbbb', 'a?(b*)').should.be.false(); - mm.isMatch('axbx', 'a?(b*)').should.be.false(); - mm.isMatch('xabbbb', 'a?(b*)').should.be.false(); - mm.isMatch('xbbbb', 'a?(b*)').should.be.false(); - mm.isMatch('xbx', 'a?(b*)').should.be.false(); - mm.isMatch('yax', '?(a*|b)').should.be.false(); - }); -}); - diff --git a/test/extglob1a.js b/test/extglob1a.js deleted file mode 100644 index cf818474..00000000 --- a/test/extglob1a.js +++ /dev/null @@ -1,161 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -var path = require('path'); -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = ref.minimatch; -} - -describe('extglob1a', function() { - it('should match extglobs:', function() { - mm.match(['ba'], 'a!(x)').should.eql([]); - mm.match(['ba', 'ab'], 'a!(x)').should.eql(['ab']); - mm.match(['ba'], 'a*(?(x))').should.eql([]); - mm.match(['ba', 'ax', 'a'], 'a*(?(x))').should.eql(['ax', 'a']); - mm.match(['a', 'ab'], 'a*!(x)/b/?(y)/c').should.eql([]); - mm.match(['ab', 'ba'], 'a?(x)').should.eql([]); - mm.match(['ba'], 'a*!(x)').should.eql([]); - mm.match(['a', 'ab', 'x'], 'a!(x)').should.eql(['a', 'ab']); - mm.match(['a'], 'a?(x)').should.eql(['a']); - mm.match(['a.js', 'a.md', 'a.js.js', 'c.js', 'a.', 'd.js.d'], '*.!(js)').should.eql(['a.md', 'a.', 'd.js.d']); - // mm.match(['a', 'ab'], 'a*(?(x))').should.eql(['a', 'ab']); - mm.match(['a', 'ab'], 'a*(!(x))').should.eql(['a', 'ab']); - mm.match(['a', 'x'], 'a*(!(x))').should.eql(['a']); - mm.match(['a', 'x', 'ab', 'ax'], 'a*(!(x))').should.eql(['a', 'ab']); - }); -}) - -describe('extglobs', function() { - it('should match extended globs:', function() { - mm.match(['a/z', 'a/b'], 'a/!(z)').should.eql(['a/b']); - mm.match(['c/z/v'], 'c/z/v').should.eql(['c/z/v']); - mm.match(['c/a/v'], 'c/!(z)/v').should.eql(['c/a/v']); - mm.match(['c/z/v','c/a/v'], 'c/!(z)/v').should.eql(['c/a/v']); - mm.match(['c/z/v','c/a/v'], 'c/@(z)/v').should.eql(['c/z/v']); - mm.match(['c/z/v','c/a/v'], 'c/+(z)/v').should.eql(['c/z/v']); - mm.match(['c/z/v','c/a/v'], 'c/*(z)/v').should.eql(['c/z/v']); - mm.match(['c/z/v','z','zf','fz'], '?(z)').should.eql(['z']); - mm.match(['c/z/v','z','zf','fz'], '+(z)').should.eql(['z']); - mm.match(['c/z/v','z','zf','fz'], '*(z)').should.eql(['z']); - mm.match(['cz','abz','az'], 'a@(z)').should.eql(['az']); - mm.match(['cz','abz','az'], 'a*@(z)').should.eql(['abz', 'az']); - mm.match(['cz','abz','az'], 'a!(z)').should.eql(['abz']); - mm.match(['cz','abz','az'], 'a?(z)').should.eql(['az']); - mm.match(['cz','abz','az'], 'a+(z)').should.eql(['az']); - mm.match(['az','bz','axz'], 'a+(z)').should.eql(['az']); - mm.match(['cz','abz','az'], 'a*(z)').should.eql(['az']); - mm.match(['cz','abz','az'], 'a**(z)').should.eql(['abz', 'az']); - mm.match(['cz','abz','az'], 'a*!(z)').should.eql(['abz', 'az']); - }); - - it('should match extglobs in file paths:', function() { - mm.match(['a.js', 'a.md', 'a.js.js', 'c.js', 'a.', 'd.js.d'], '*.!(js)').should.eql(['a.md', 'a.', 'd.js.d']); - mm.match(['a.js', 'a.md', 'a.js.js', 'c.js', 'a.', 'd.js.d'], '*!(.js)').should.eql(['a.md', 'a.', 'd.js.d']); - }); - - it('should support exclusion patterns:', function() { - var arr = ['a.a', 'a.b', 'a.a.a', 'c.a', 'a.', 'd.a.d']; - mm.match(arr, '*.+(b|d)').should.eql(['a.b', 'd.a.d']); - mm.match(arr, '*.!(a)').should.eql(['a.b', 'a.', 'd.a.d']); - mm.match(arr, '*.!(*a)').should.eql(['a.b', 'a.', 'd.a.d']); - }); - - it('should match exactly one of the given pattern:', function() { - var arr = ['aa.aa', 'a.bb', 'a.aa.a', 'cc.a', 'a.a', 'c.a', 'dd.aa.d', 'b.a']; - mm.match(arr, '@(b|a)\.@(a)').should.eql(['a.a', 'b.a']); - }); - - it('should support multiple exclusion patterns in one extglob:', function() { - var arr = ['a.a', 'a.b', 'a.c.d', 'c.c', 'a.', 'd.d', 'e.e', 'f.f']; - mm.match(arr, '!(*.a|*.b|*.c)').should.eql(['a.c.d', 'a.', 'd.d', 'e.e', 'f.f']); - }); -}); - -describe('bash', function() { - it('should match extended globs from the bash spec:', function() { - mm.match(['fofo'], '*(f*(o))').should.eql(['fofo']); - mm.match(['ffo'], '*(f*(o))').should.eql(['ffo']); - mm.match(['foooofo'], '*(f*(o))').should.eql(['foooofo']); - mm.match(['foooofof'], '*(f*(o))').should.eql(['foooofof']); - mm.match(['fooofoofofooo'], '*(f*(o))').should.eql(['fooofoofofooo']); - mm.match(['foooofof'], '*(f+(o))').should.eql([]); - mm.match(['xfoooofof'], '*(f*(o))').should.eql([]); - mm.match(['foooofofx'], '*(f*(o))').should.eql([]); - mm.match(['ofxoofxo'], '*(*(of*(o)x)o)').should.eql(['ofxoofxo']); - mm.match(['ofooofoofofooo'], '*(f*(o))').should.eql([]); - mm.match(['foooxfooxfoxfooox'], '*(f*(o)x)').should.eql(['foooxfooxfoxfooox']); - mm.match(['foooxfooxofoxfooox'], '*(f*(o)x)').should.eql([]); - mm.match(['foooxfooxfxfooox'], '*(f*(o)x)').should.eql(['foooxfooxfxfooox']); - mm.match(['ofxoofxo'], '*(*(of*(o)x)o)').should.eql(['ofxoofxo']); - mm.match(['ofoooxoofxo'], '*(*(of*(o)x)o)').should.eql(['ofoooxoofxo']); - mm.match(['ofoooxoofxoofoooxoofxo'], '*(*(of*(o)x)o)').should.eql(['ofoooxoofxoofoooxoofxo']); - mm.match(['ofoooxoofxoofoooxoofxoo'], '*(*(of*(o)x)o)').should.eql(['ofoooxoofxoofoooxoofxoo']); - mm.match(['ofoooxoofxoofoooxoofxofo'], '*(*(of*(o)x)o)').should.eql([]); - mm.match(['ofoooxoofxoofoooxoofxooofxofxo'], '*(*(of*(o)x)o)').should.eql(['ofoooxoofxoofoooxoofxooofxofxo']); - mm.match(['aac'], '*(@(a))a@(c)').should.eql(['aac']); - mm.match(['aac'], '*(@(a))b@(c)').should.eql([]); - mm.match(['ac'], '*(@(a))a@(c)').should.eql(['ac']); - mm.match(['c'], '*(@(a))a@(c)').should.eql([]); - mm.match(['aaac', 'foo'], '*(@(a))a@(c)').should.eql(['aaac']); - mm.match(['baaac'], '*(@(a))a@(c)').should.eql([]); - mm.match(['abcd'], '?@(a|b)*@(c)d').should.eql(['abcd']); - mm.match(['abcd'], '@(ab|a*@(b))*(c)d').should.eql(['abcd']); - mm.match(['acd'], '@(ab|a*(b))*(c)d').should.eql(['acd']); - mm.match(['abbcd'], '@(ab|a*(b))*(c)d').should.eql(['abbcd']); - mm.match(['effgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))').should.eql(['effgz']); - mm.match(['efgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))').should.eql(['efgz']); - mm.match(['egz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))').should.eql(['egz']); - mm.match(['egzefffgzbcdij'], '*(b+(c)d|e*(f)g?|?(h)i@(j|k))').should.eql(['egzefffgzbcdij']); - mm.match(['egz'], '@(b+(c)d|e+(f)g?|?(h)i@(j|k))').should.eql([]); - mm.match(['ofoofo'], '*(of+(o))').should.eql(['ofoofo']); - mm.match(['oxfoxoxfox'], '*(oxf+(ox))').should.eql(['oxfoxoxfox']); - mm.match(['oxfoxfox'], '*(oxf+(ox))').should.eql([]); - mm.match(['ofoofo'], '*(of+(o)|f)').should.eql(['ofoofo']); - mm.match(['foofoofo'], '@(foo|f|fo)*(f|of+(o))').should.eql(['foofoofo']); - mm.match(['oofooofo'], '*(of|oof+(o))').should.eql(['oofooofo']); - mm.match(['fffooofoooooffoofffooofff'], '*(*(f)*(o))').should.eql(['fffooofoooooffoofffooofff']); - mm.match(['fofoofoofofoo'], '*(fo|foo)').should.eql(['fofoofoofofoo']); - mm.match(['foo'], '!(x)').should.eql(['foo']); - mm.match(['foo'], '!(x)*').should.eql(['foo']); - mm.match(['foo', 'bar'], '!(foo)').should.eql(['bar']); - mm.match(['foo', 'bar'], '!(foo)*').should.eql(['bar']); - mm.match(['foo/bar'], 'foo/!(foo)').should.eql(['foo/bar']); - mm.match(['foobar', 'baz'], '!(foo)*').should.eql(['baz']); - mm.match(['moo.cow', 'a.b'], '!(*\\.*).!(*\\.*)').should.eql(['moo.cow', 'a.b']); - mm.match(['moo.cow', 'a.b'], '!(*.*).!(*.*)').should.eql(['moo.cow', 'a.b']); - mm.match(['mad.moo.cow'], '^!(*.*).!(*.*)').should.eql([]); - mm.match(['mucca.pazza'], 'mu!(*(c))?.pa!(*(z))?').should.eql([]); - mm.match(['ooo'], '!(f)').should.eql(['ooo']); - mm.match(['ooo'], '*(!(f))').should.eql(['ooo']); - mm.match(['ooo'], '+(!(f))').should.eql(['ooo']); - mm.match(['f'], '!(f)').should.eql([]); - mm.match(['f'], '*(!(f))').should.eql([]); - mm.match(['f'], '+(!(f))').should.eql([]); - mm.match(['foot'], '@(!(z*)|*x)').should.eql(['foot']); - mm.match(['zoot'], '@(!(z*)|*x)').should.eql([]); - mm.match(['foox'], '@(!(z*)|*x)').should.eql(['foox']); - mm.match(['zoox'], '@(!(z*)|*x)').should.eql(['zoox']); - mm.match(['foob'], '!(foo)b*').should.eql([]); - mm.match(['fa', 'fb', 'f', 'fo'], '!(f(o))').should.eql(['fa', 'fb', 'f']); - mm.match(['fa', 'fb', 'f', 'fo'], '!(f!(o))').should.eql(['fo']); - mm.match(['fff'], '!(f)').should.eql(['fff']); - // mm.match(['foobb'], '!(foo)b*').should.eql(['foobb']); - // mm.match(['foo'], '*(!(foo))').should.eql(['foo']); - // mm.match(['foo'], '+(!(f))').should.eql(['foo']); - // mm.match(['foo'], '*(!(f))').should.eql(['foo']); - mm.match(['foo'], '!(f)').should.eql(['foo']); - // mm.match(['fff'], '+(!(f))').should.eql(['fff']); - // mm.match(['fff'], '*(!(f))').should.eql(['fff']); - }); -}); diff --git a/test/extglobs.js b/test/extglobs.js new file mode 100644 index 00000000..19c41c2a --- /dev/null +++ b/test/extglobs.js @@ -0,0 +1,332 @@ +'use strict'; + +var assert = require('assert'); +var argv = require('yargs-parser')(process.argv.slice(2)); +var minimatch = require('minimatch'); +var micromatch = require('..');; + +var matcher = argv.mm ? minimatch : micromatch; +var isMatch = argv.mm ? minimatch : micromatch.isMatch; + +function match(arr, pattern, expected, options) { + var actual = matcher.match(arr, pattern, options); + assert.deepEqual(actual.sort(), expected.sort(), micromatch.makeRe(pattern)); +} + +/** + * These tests were converted directly from bash 4.3 and 4.4 unit tests. + */ + +describe('extglobs', function() { + it('should export a function', function() { + assert.equal(typeof matcher, 'function'); + }); + + it('should throw on imbalanced sets when `options.strict` is true', function() { + assert.throws(function() { + isMatch('a((b', 'a(b', {strict: true}); + }, 'row:1 col:2 missing opening parens: "a(b"'); + + assert.throws(function() { + isMatch('a((b', 'a(*b', {strict: true}); + }, 'row:1 col:2 missing opening parens: "a(*b"'); + }); + + it.skip('Bash 4.3 disagrees!', function() { + match(['foo'], '*(!(foo))', ['foo']); + match(['foo', 'bar', 'baz', 'foobar'], '!(foo)*', ['foo', 'bar', 'baz', 'foobar']); + match(['moo.cow', 'mad.moo.cow'], '!(*.*).!(*.*)', ['moo.cow']); + }); + + it('should match extglobs ending with statechar', function() { + // from minimatch tests + assert(!isMatch('ax', 'a?(b*)')); + assert(isMatch('ax', '?(a*|b)')); + }); + + it('should match extended globs:', function() { + match(['a/z', 'a/b'], 'a/!(z)', ['a/b']); + match(['c/z/v'], 'c/z/v', ['c/z/v']); + match(['c/a/v'], 'c/!(z)/v', ['c/a/v']); + match(['c/z/v', 'c/a/v'], 'c/!(z)/v', ['c/a/v']); + match(['c/z/v', 'c/a/v'], 'c/@(z)/v', ['c/z/v']); + match(['c/z/v', 'c/a/v'], 'c/+(z)/v', ['c/z/v']); + match(['c/z/v', 'c/a/v'], 'c/*(z)/v', ['c/z/v']); + match(['c/z/v', 'z', 'zf', 'fz'], '?(z)', ['z']); + match(['c/z/v', 'z', 'zf', 'fz'], '+(z)', ['z']); + match(['c/z/v', 'z', 'zf', 'fz'], '*(z)', ['z']); + match(['cz', 'abz', 'az'], 'a@(z)', ['az']); + match(['cz', 'abz', 'az'], 'a*@(z)', ['az', 'abz']); + match(['cz', 'abz', 'az'], 'a!(z)', ['abz']); + match(['cz', 'abz', 'az'], 'a?(z)', ['az']); + match(['cz', 'abz', 'az'], 'a+(z)', ['az']); + match(['az', 'bz', 'axz'], 'a+(z)', ['az']); + match(['cz', 'abz', 'az'], 'a*(z)', ['az']); + match(['cz', 'abz', 'az'], 'a**(z)', ['az', 'abz']); + match(['cz', 'abz', 'az'], 'a*!(z)', ['az', 'abz']); + }); + + it('should support negation', function() { + var arr = ['a', 'b', 'aa', 'ab', 'bb', 'ac', 'aaa', 'aab', 'abb', 'ccc']; + match(arr, '!(a)*', ['b', 'bb', 'ccc']); + match(arr, 'a!(b)*', ['a', 'aa', 'aaa', 'aab', 'ac']); + }); + + it('should support qmark matching', function() { + var arr = ['a', 'aa', 'ab', 'aaa', 'abcdefg']; + match(arr, '?', ['a']); + match(arr, '??', ['aa', 'ab']); + match(arr, '???', ['aaa']); + }); + + it('should match exactly one of the given pattern:', function() { + var arr = ['aa.aa', 'a.bb', 'a.aa.a', 'cc.a', 'a.a', 'c.a', 'dd.aa.d', 'b.a']; + match(arr, '(b|a).(a)', ['a.a', 'b.a']); + match(arr, '@(b|a).@(a)', ['a.a', 'b.a']); + }); + + it('should work with globs', function() { + var arr = ['123abc', 'ab', 'abab', 'abcdef', 'accdef', 'abcfefg', 'abef', 'abcfef', 'abd', 'acd']; + match(arr, 'ab*(e|f)', ['ab', 'abef']); + match(arr, 'ab?*(e|f)', ['ab', 'abef']); + match(arr, 'ab*d+(e|f)', ['abcdef']); + match(arr, 'ab**(e|f)', ['ab', 'abab', 'abcdef', 'abcfefg', 'abcfef', 'abef', 'abd']); + match(arr, 'ab*+(e|f)', ['abcdef', 'abcfef', 'abef']); + match(arr, 'ab**(e|f)g', ['abcfefg']); + match(arr, 'ab***ef', ['abcdef', 'abcfef', 'abef']); + match(arr, 'ab**', ['ab', 'abab', 'abcdef', 'abcfef', 'abcfefg', 'abd', 'abef']); + match(arr, '*?(a)bc', ['123abc']); + match(arr, 'a(b*(foo|bar))d', ['abd']); + match(arr, '(a+|b)+', ['ab', 'abab']); + match(arr, '(a+|b)*', ['ab', 'abab', 'accdef', 'abcdef', 'abcfefg', 'abef', 'abcfef', 'abd', 'acd']); + match(['/dev/udp/129.22.8.102/45'], '/dev\\/@(tcp|udp)\\/*\\/*', ['/dev/udp/129.22.8.102/45']); + match(['12', '1', '12abc'], '0|[1-9]*([0-9])', ['1', '12'], 'Should match valid numbers'); + match(['07', '0377', '09'], '+([0-7])', ['0377', '07'], 'Should match octal numbers'); + }); + + it('stuff from korn\'s book', function() { + assert(isMatch('paragraph', 'para@(chute|graph)')); + assert(!isMatch('paramour', 'para@(chute|graph)')); + assert(isMatch('para991', 'para?([345]|99)1')); + assert(!isMatch('para381', 'para?([345]|99)1')); + assert(!isMatch('paragraph', 'para*([0-9])')); + assert(isMatch('para', 'para*([0-9])')); + assert(isMatch('para13829383746592', 'para*([0-9])')); + assert(!isMatch('paragraph', 'para*([0-9])')); + assert(!isMatch('para', 'para+([0-9])')); + assert(isMatch('para987346523', 'para+([0-9])')); + assert(isMatch('paragraph', 'para!(*.[0-9])')); + assert(isMatch('para.38', 'para!(*.[00-09])')); + assert(isMatch('para.graph', 'para!(*.[0-9])')); + assert(isMatch('para39', 'para!(*.[0-9])')); + }); + + it('tests derived from those in rosenblatt\'s korn shell book', function() { + match(['', '137577991', '2468'], '*(0|1|3|5|7|9)', ['', '137577991']); + match(['file.c', 'file.C', 'file.cc', 'file.ccc'], '*.c?(c)', ['file.c', 'file.cc']); + match(['parse.y', 'shell.c', 'Makefile', 'Makefile.in'], '!(*.c|*.h|Makefile.in|config*|README)', ['parse.y', 'Makefile']); + match(['VMS.FILE;', 'VMS.FILE;0', 'VMS.FILE;1', 'VMS.FILE;139', 'VMS.FILE;1N'], '*\\;[1-9]*([0-9])', ['VMS.FILE;1', 'VMS.FILE;139']); + }); + + it('tests derived from the pd-ksh test suite', function() { + match(['abcx', 'abcz', 'bbc'], '!([[*])*', ['abcx', 'abcz', 'bbc']); + match(['abcx', 'abcz', 'bbc'], '+(a|b\\[)*', ['abcx', 'abcz']); + match(['abd', 'acd'], 'a+(b|c)d', ['abd', 'acd']); + match(['abd', 'acd', 'ac', 'ab'], 'a!(@(b|B))', ['acd', 'abd', 'ac']); + match(['abd', 'acd'], 'a!(@(b|B))d', ['acd']); + match(['abd', 'acd'], 'a[b*(foo|bar)]d', ['abd']); + // match(['abcx', 'abcz', 'bbc'], '[a*(]*z', ['abcz']); + }); + + it('simple kleene star tests', function() { + assert(!isMatch('foo', '*(a|b\\[)')); + assert(isMatch('foo', '*(a|b\\[)|f*')); + }); + + it('this doesn\'t work in bash either (per bash extglob.tests notes)', function() { + assert(!isMatch('*(a|b[)', '*(a|b\\[)')); + assert(isMatch('*(a|b[)', '\\*\\(a\\|b\\[\\)')); + }); + + it('should support multiple exclusion patterns in one extglob:', function() { + var arr = ['a.a', 'a.b', 'a.c', 'a.c.d', 'c.c', 'a.', 'd.d', 'e.e', 'f.f', 'a.abcd']; + match(arr, '*.(a|b|@(ab|a*@(b))*(c)d)', ['a.a', 'a.b', 'a.abcd']); + match(arr, '!(*.a|*.b|*.c)', ['a.', 'd.d', 'e.e', 'f.f']); + match(arr, '*!(.a|.b|.c)', arr); + match(arr, '*.!(a|b|c)', ['a.c.d', 'a.', 'd.d', 'e.e', 'f.f']); + }); + + it('should correctly match empty parens', function() { + var arr = ['def', 'ef']; + match(arr, '()ef', ['ef']); + }); + + it('should match escaped parens', function() { + var arr = ['a(b', 'a\\(b', 'a((b', 'a((((b', 'ab']; + match(arr, 'a(b', ['a(b']); + match(arr, 'a\\(b', ['a(b']); + match(arr, 'a(*b', ['a(b', 'a((b', 'a((((b']); + }); + + it('should match escaped backslashes', function() { + match(['a(b', 'a\\(b', 'a((b', 'a((((b', 'ab'], 'a\\\\(b', ['a\\(b']); + match(['a\\b', 'a/b', 'ab'], 'a/b', ['a/b']); + match(['a\\b', 'a/b', 'ab'], 'a\\\\b', ['a\\b']); + }); + + // these are not extglobs, and do not need to pass. these tests will be moved to `expand-brackets` + it('should match common regex patterns', function() { + var arr = ['a c', 'a1c', 'a123c', 'a.c', 'a.xy.zc', 'a.zc', 'abbbbc', 'abbbc', 'abbc', 'abc', 'abq', 'axy zc', 'axy', 'axy.zc', 'axyzc']; + + match(arr, 'ab*c', ['abbbbc', 'abbbc', 'abbc', 'abc']); + match(arr, 'ab+bc', ['abbbbc', 'abbbc', 'abbc']); + match(arr, 'ab?bc', ['abbc', 'abc']); + match(arr, '^abc$', ['abc']); + match(arr, 'a.c', ['a.c']); + match(arr, 'a.*c', ['a.c', 'a.xy.zc', 'a.zc']); + match(arr, 'a*c', ['a c', 'a.c', 'a1c', 'a123c', 'abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc', 'axy zc', 'axy.zc', 'a.xy.zc', 'a.zc']); + match(arr, 'a\\w+c', ['a1c', 'a123c', 'abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc'], 'Should match word characters'); + match(arr, 'a\\W+c', ['a.c', 'a c'], 'Should match non-word characters'); + match(arr, 'a\\d+c', ['a1c', 'a123c'], 'Should match numbers'); + match(['foo@#$%123ASD #$$%^&', 'foo!@#$asdfl;', '123'], '\\d+', ['123']); + match(['a123c', 'abbbc'], 'a\\D+c', ['abbbc'], 'Should match non-numbers'); + match(['foo', ' foo '], '(f|o)+\\b', ['foo'], 'Should match word boundaries'); + }); +}); + +describe('bash', function() { + it('should match extended globs from the bash spec:', function() { + assert(isMatch('fofo', '*(f*(o))')); + assert(isMatch('ffo', '*(f*(o))')); + assert(isMatch('foooofo', '*(f*(o))')); + assert(isMatch('foooofof', '*(f*(o))')); + assert(isMatch('fooofoofofooo', '*(f*(o))')); + assert(!isMatch('foooofof', '*(f+(o))')); + assert(!isMatch('xfoooofof', '*(f*(o))')); + assert(!isMatch('foooofofx', '*(f*(o))')); + assert(isMatch('ofxoofxo', '*(*(of*(o)x)o)')); + assert(!isMatch('ofooofoofofooo', '*(f*(o))')); + assert(isMatch('foooxfooxfoxfooox', '*(f*(o)x)')); + assert(!isMatch('foooxfooxofoxfooox', '*(f*(o)x)')); + assert(isMatch('foooxfooxfxfooox', '*(f*(o)x)')); + assert(isMatch('ofxoofxo', '*(*(of*(o)x)o)')); + assert(isMatch('ofoooxoofxo', '*(*(of*(o)x)o)')); + assert(isMatch('ofoooxoofxoofoooxoofxo', '*(*(of*(o)x)o)')); + assert(isMatch('ofoooxoofxoofoooxoofxoo', '*(*(of*(o)x)o)')); + assert(!isMatch('ofoooxoofxoofoooxoofxofo', '*(*(of*(o)x)o)')); + assert(isMatch('ofoooxoofxoofoooxoofxooofxofxo', '*(*(of*(o)x)o)')); + assert(isMatch('aac', '*(@(a))a@(c)')); + assert(isMatch('ac', '*(@(a))a@(c)')); + assert(!isMatch('c', '*(@(a))a@(c)')); + assert(isMatch('aaac', '*(@(a))a@(c)')); + assert(!isMatch('baaac', '*(@(a))a@(c)')); + assert(isMatch('abcd', '?@(a|b)*@(c)d')); + assert(isMatch('abcd', '@(ab|a*@(b))*(c)d')); + assert(isMatch('acd', '@(ab|a*(b))*(c)d')); + assert(isMatch('abbcd', '@(ab|a*(b))*(c)d')); + assert(isMatch('effgz', '@(b+(c)d|e*(f)g?|?(h)i@(j|k))')); + assert(isMatch('efgz', '@(b+(c)d|e*(f)g?|?(h)i@(j|k))')); + assert(isMatch('egz', '@(b+(c)d|e*(f)g?|?(h)i@(j|k))')); + assert(isMatch('egzefffgzbcdij', '*(b+(c)d|e*(f)g?|?(h)i@(j|k))')); + assert(!isMatch('egz', '@(b+(c)d|e+(f)g?|?(h)i@(j|k))')); + assert(isMatch('ofoofo', '*(of+(o))')); + assert(isMatch('oxfoxoxfox', '*(oxf+(ox))')); + assert(!isMatch('oxfoxfox', '*(oxf+(ox))')); + assert(isMatch('ofoofo', '*(of+(o)|f)')); + assert(isMatch('foofoofo', '@(foo|f|fo)*(f|of+(o))'), 'Should match as fo+ofo+ofo'); + assert(isMatch('oofooofo', '*(of|oof+(o))')); + assert(isMatch('fffooofoooooffoofffooofff', '*(*(f)*(o))')); + assert(isMatch('fofoofoofofoo', '*(fo|foo)'), 'Should backtrack in alternation matches'); + }); + + it('should support exclusions', function() { + match(['moo.cow', 'moo', 'cow'], '!(*.*)', ['moo', 'cow']); + match(['moo.cow', 'moo', 'cow'], '!(*.*).', []); + match(['foob', 'foobb'], '!(foo)b*', []); + assert(!isMatch('f', '!(f)')); + assert(!isMatch('f', '+(!(f))')); + assert(!isMatch('f', '*(!(f))')); + assert(!isMatch('mad.moo.cow', '!(*.*).!(*.*)')); + assert(!isMatch('mucca.pazza', 'mu!(*(c))?.pa!(*(z))?')); + assert(!isMatch('zoot', '@(!(z*)|*x)')); + assert(isMatch('foo', '!(x)')); + assert(isMatch('foo', '!(x)*')); + assert(isMatch('foot', '@(!(z*)|*x)')); + assert(isMatch('foox', '@(!(z*)|*x)')); + assert(isMatch('ooo', '!(f)')); + assert(isMatch('ooo', '*(!(f))')); + assert(isMatch('ooo', '+(!(f))')); + assert(isMatch('zoox', '@(!(z*)|*x)')); + match(['aaac', 'foo'], '*(@(a))a@(c)', ['aaac']); + match(['aaac'], '*(@(a))a@(c)', ['aaac']); + match(['aac'], '*(@(a))a@(c)', ['aac']); + match(['aac'], '*(@(a))b@(c)', []); + match(['abbcd'], '@(ab|a*(b))*(c)d', ['abbcd']); + match(['abcd'], '?@(a|b)*@(c)d', ['abcd']); + match(['abcd'], '@(ab|a*@(b))*(c)d', ['abcd']); + match(['ac'], '*(@(a))a@(c)', ['ac']); + match(['acd'], '@(ab|a*(b))*(c)d', ['acd']); + match(['baaac'], '*(@(a))a@(c)', []); + match(['c'], '*(@(a))a@(c)', []); + match(['effgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['effgz']); + match(['efgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['efgz']); + match(['egz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['egz']); + match(['egz'], '@(b+(c)d|e+(f)g?|?(h)i@(j|k))', []); + match(['egzefffgzbcdij'], '*(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['egzefffgzbcdij']); + match(['f'], '!(f)', []); + match(['f'], '*(!(f))', []); + match(['f'], '+(!(f))', []); + match(['fa', 'fb', 'f', 'fo'], '!(f!(o))', ['fo']); + match(['fa', 'fb', 'f', 'fo'], '!(f(o))', ['f', 'fb', 'fa']); + match(['fff', 'foo', 'ooo', 'f'], '*(!(f))', ['fff', 'ooo', 'foo']); + match(['fff'], '!(f)', ['fff']); + match(['fff'], '*(!(f))', ['fff']); + match(['fff'], '+(!(f))', ['fff']); + match(['fffooofoooooffoofffooofff'], '*(*(f)*(o))', ['fffooofoooooffoofffooofff']); + match(['ffo'], '*(f*(o))', ['ffo']); + match(['fofo'], '*(f*(o))', ['fofo']); + match(['fofoofoofofoo'], '*(fo|foo)', ['fofoofoofofoo']); + match(['foo', 'bar'], '!(foo)', ['bar']); + match(['foo'], '!(!(foo))', ['foo']); + match(['foo'], '!(f)', ['foo']); + match(['foo'], '!(x)', ['foo']); + match(['foo'], '!(x)*', ['foo']); + match(['foo'], '*(!(f))', ['foo']); + match(['foo'], '*((foo))', ['foo']); + match(['foo'], '+(!(f))', ['foo']); + match(['foo/bar'], 'foo/!(foo)', ['foo/bar']); + match(['foob', 'foobb'], '(foo)bb', ['foobb']); + match(['foobar'], '!(foo)', ['foobar']); + match(['foofoofo'], '@(foo|f|fo)*(f|of+(o))', ['foofoofo']); + match(['fooofoofofooo'], '*(f*(o))', ['fooofoofofooo']); + match(['foooofo'], '*(f*(o))', ['foooofo']); + match(['foooofof'], '*(f*(o))', ['foooofof']); + match(['foooofof'], '*(f+(o))', []); + match(['foooofofx'], '*(f*(o))', []); + match(['foooxfooxfoxfooox'], '*(f*(o)x)', ['foooxfooxfoxfooox']); + match(['foooxfooxfxfooox'], '*(f*(o)x)', ['foooxfooxfxfooox']); + match(['foooxfooxofoxfooox'], '*(f*(o)x)', []); + match(['foot'], '@(!(z*)|*x)', ['foot']); + match(['foox'], '@(!(z*)|*x)', ['foox']); + match(['mad.moo.cow'], '!(*.*).!(*.*)', []); + match(['moo.cow', 'moo', 'cow'], '.!(*.*)', []); + match(['ofoofo'], '*(of+(o))', ['ofoofo']); + match(['ofoofo'], '*(of+(o)|f)', ['ofoofo']); + match(['ofooofoofofooo'], '*(f*(o))', []); + match(['ofoooxoofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxo']); + match(['ofoooxoofxoofoooxoofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxo']); + match(['ofoooxoofxoofoooxoofxofo'], '*(*(of*(o)x)o)', []); + match(['ofoooxoofxoofoooxoofxoo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxoo']); + match(['ofoooxoofxoofoooxoofxooofxofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxooofxofxo']); + match(['ofxoofxo'], '*(*(of*(o)x)o)', ['ofxoofxo']); + match(['oofooofo'], '*(of|oof+(o))', ['oofooofo']); + match(['ooo'], '!(f)', ['ooo']); + match(['ooo'], '*(!(f))', ['ooo']); + match(['ooo'], '+(!(f))', ['ooo']); + match(['oxfoxfox'], '*(oxf+(ox))', []); + match(['oxfoxoxfox'], '*(oxf+(ox))', ['oxfoxoxfox']); + match(['xfoooofof'], '*(f*(o))', []); + match(['zoot'], '@(!(z*)|*x)', []); + match(['zoox'], '@(!(z*)|*x)', ['zoox']); + }); +}); diff --git a/test/filter.js b/test/filter.js deleted file mode 100644 index a57a1f3c..00000000 --- a/test/filter.js +++ /dev/null @@ -1,64 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = ref.minimatch; -} - -var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]; - -describe('.filter()', function() { - it('should throw on undefined args:', function() { - (function() { - mm.filter(); - }).should.throw('micromatch.filter(): patterns should be a string or array.'); - }); - - it('should throw on bad args:', function() { - (function() { - mm.filter({}); - }).should.throw('micromatch.filter(): patterns should be a string or array.'); - }); - - it('should create a filter function to filter files', function() { - mm.filter('*').should.be.a.Function(); - }); - - it('should return an empty array when no pattern is passed:', function() { - mm.filter('*')().should.eql([]); - }); - - it('should filter files', function() { - ['a', 'b', 'c'].filter(mm.filter('*')).should.eql(['a', 'b', 'c']); - ['a/a', 'b/a', 'a/c'].filter(mm.filter('a/*')).should.eql(['a/a', 'a/c']); - }); - - it('should filter using multiple patterns', function() { - var actual_A = arr.filter(mm.filter(['{1..10}', '![7-9]', '!{3..4}'])); - actual_A.should.eql([1, 2, 5, 6, 10]); - actual_A.should.not.eql([1, 2, 3, 4, 5, 6, 10]); - - // see https://github.com/jonschlinkert/micromatch/issues/7 - var actual_B = [ - 'fs-readdir-callback-api.js', - 'fs-readdir-stream-api.js', - 'glob-stream.js', - 'readdirp-callback-api.js', - 'readdirp-stream-api.js', - 'recursive-readdir.js' - ].filter(mm.filter(['*', '!*api*'])); - actual_B.should.eql(['glob-stream.js', 'recursive-readdir.js']); - }); -}); - diff --git a/test/glob.js b/test/glob.js deleted file mode 100644 index 6599185b..00000000 --- a/test/glob.js +++ /dev/null @@ -1,120 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var Glob = require('../lib/glob'); -var mm = require('..'); - -describe('Glob class', function() { - describe('constructor', function() { - it('should return an instance of Glob', function() { - var glob = new Glob('foo'); - assert(glob instanceof Glob); - }); - - it('should instantiate without new', function() { - var glob = Glob('foo'); - assert(glob instanceof Glob); - }); - }); - - describe('instance', function() { - it('should expose `orig`', function() { - var glob = new Glob('!foo'); - assert.equal(glob.orig, '!foo'); - }); - - it('should expose `pattern`', function() { - var glob = new Glob('!foo'); - assert.equal(glob.pattern, 'foo'); - }); - - it('should expose `options`', function() { - var glob = new Glob('!foo'); - assert(glob.options); - assert(typeof glob.options === 'object'); - }); - }); - - describe('tokens', function() { - it('should parse a glob pattern and expose a tokens object', function() { - var glob = new Glob('!foo'); - glob.parse(); - assert(glob.hasOwnProperty('tokens')); - assert(glob.tokens.hasOwnProperty('is')); - }); - - it('should recognize extglob patterns', function() { - var glob = new Glob('@(a|b)'); - glob.parse(); - assert(glob.tokens.is.extglob === true); - }); - }); - - describe('.extglob()', function() { - it('should parse extglob patterns', function() { - var glob = new Glob('@(a|b)'); - glob.parse(); - glob.extglob(); - assert.equal(glob.pattern, '(?:a|b)'); - }); - - it('should ignore non-extglobs', function() { - var glob = new Glob('foo/*.js'); - glob.parse(); - glob.extglob(); - assert.equal(glob.pattern, 'foo/*.js'); - }); - - it('should parse extglob patterns', function() { - var glob = new Glob('@(a|b)', {noextglob: true}); - glob.parse(); - glob.extglob(); - assert.equal(glob.pattern, '@(a|b)'); - }); - }); - - describe('patterns', function() { - it('should escape dots', function() { - var actual = mm.expand('.'); - assert.deepEqual(actual.pattern, '\\.'); - }); - - it('should strip leading !', function() { - var glob = new Glob('!foo'); - assert.deepEqual(glob.pattern, 'foo'); - }); - }); - - describe('options', function() { - describe('options.track', function() { - it('should track history for debugging:', function() { - var actual = mm.expand('**/*.js', {track: true}); - assert(actual.hasOwnProperty('history')); - assert(Array.isArray(actual.history)); - assert(actual.history.length > 1); - }); - }); - - describe('options.nonegate', function() { - it('should ignore negation patterns when `nonegate` is true:', function() { - var array = ['a.js', 'b.js', 'c.js']; - var actual = mm(array, '!*.js', {nonegate: true}); - assert.deepEqual(array, actual); - }); - }); - }); - - describe('leading slash', function() { - it('should match paths with leading slashes:', function() { - var array = ['/a.js', '/b.js', '/c.js']; - var actual = mm(array, '/*.js'); - assert.deepEqual(array, actual); - }); - - it('should match dotfiles with leading slashes:', function() { - var array = ['/.a.js', '/.b.js', '/.c.js']; - var actual = mm(array, '/.*.js'); - assert.deepEqual(array, actual); - }); - }); -}); diff --git a/test/globstars.js b/test/globstars.js new file mode 100644 index 00000000..b7a6726f --- /dev/null +++ b/test/globstars.js @@ -0,0 +1,20 @@ +'use strict'; + +var assert = require('assert'); +var mm = require('..'); + +describe('globstars', function() { + it('should match double star patterns', function() { + assert(!mm.isMatch('.gitignore', 'a/**/z/*.md')); + assert(!mm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/j/**/z/*.md')); + assert(!mm.isMatch('a/b/c/j/e/z/foo.txt', 'a/**/j/**/z/*.md')); + assert(!mm.isMatch('a/b/z/.dotfile', 'a/**/z/*.md')); + assert(!mm.isMatch('a/b/z/.dotfile.md', '**/c/.*.md')); + + assert(mm.isMatch('a/b/c/d/e/j/n/p/o/z/foo.md', 'a/**/j/**/z/*.md')); + assert(mm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/z/*.md')); + assert(mm.isMatch('a/b/c/j/e/z/foo.md', 'a/**/j/**/z/*.md')); + assert(mm.isMatch('a/b/z/.dotfile.md', '**/.*.md')); + assert(mm.isMatch('a/b/z/.dotfile.md', 'a/**/z/.*.md')); + }); +}); diff --git a/test/isMatch.js b/test/isMatch.js index 50689365..8655d42a 100644 --- a/test/isMatch.js +++ b/test/isMatch.js @@ -1,35 +1,23 @@ 'use strict'; -require('should'); var assert = require('assert'); -var argv = require('minimist')(process.argv.slice(2)); -var minimatch = require('./support/reference'); var mm = require('..'); -if ('minimatch' in argv) { - mm = minimatch; -} - describe('.isMatch()', function() { describe('errors:', function() { it('should throw on undefined args:', function() { - (function() { + assert.throws(function() { mm.isMatch(); - }).should.throw('micromatch.isMatch(): filepath should be a string.'); + }, /expected pattern to be a string/); }); it('should throw on bad args:', function() { - (function() { + assert.throws(function() { mm.isMatch({}); - }).should.throw('micromatch.isMatch(): filepath should be a string.'); + }, /expected pattern to be a string/); }); }); - it('should work like `matcher` when a pattern and opts is passed', function() { - assert(typeof mm.isMatch('*', {}), 'function'); - assert(mm.isMatch('*', {})('abc'), true); - }); - it('should escape plus signs to match string literals', function() { assert(mm.isMatch('a+b/src/glimini.js', 'a+b/src/*.js')); assert(mm.isMatch('+b/src/glimini.js', '+b/src/*.js')); @@ -39,123 +27,125 @@ describe('.isMatch()', function() { }); it('should correctly deal with empty globs', function() { - mm.isMatch('ab', '').should.be.false(); - mm.isMatch('a', '').should.be.false(); - mm.isMatch('.', '').should.be.false(); + assert(!mm.isMatch('ab', '')); + assert(!mm.isMatch('a', '')); + assert(!mm.isMatch('.', '')); }); it('should match with non-glob patterns', function() { - mm.isMatch('.', '.').should.be.true(); - mm.isMatch('/a', '/a').should.be.true(); - mm.isMatch('/ab', '/a').should.be.false(); - mm.isMatch('a', 'a').should.be.true(); - mm.isMatch('ab', '/a').should.be.false(); - mm.isMatch('ab', 'a').should.be.false(); - mm.isMatch('ab', 'ab').should.be.true(); - mm.isMatch('abcd', 'cd').should.be.false(); - mm.isMatch('abcd', 'bc').should.be.false(); - mm.isMatch('abcd', 'ab').should.be.false(); + assert(mm.isMatch('.', '.')); + assert(mm.isMatch('/a', '/a')); + assert(!mm.isMatch('/ab', '/a')); + assert(mm.isMatch('a', 'a')); + assert(!mm.isMatch('ab', '/a')); + assert(!mm.isMatch('ab', 'a')); + assert(mm.isMatch('ab', 'ab')); + assert(!mm.isMatch('abcd', 'cd')); + assert(!mm.isMatch('abcd', 'bc')); + assert(!mm.isMatch('abcd', 'ab')); }); it('should match file names:', function() { - mm.isMatch('a.b', 'a.b').should.be.true(); - mm.isMatch('a.b', '*.b').should.be.true(); - mm.isMatch('a.b', 'a.*').should.be.true(); - mm.isMatch('a.b', '*.*').should.be.true(); - mm.isMatch('a-b.c-d', 'a*.c*').should.be.true(); - mm.isMatch('a-b.c-d', '*b.*d').should.be.true(); - mm.isMatch('a-b.c-d', '*.*').should.be.true(); - mm.isMatch('a-b.c-d', '*.*-*').should.be.true(); - mm.isMatch('a-b.c-d', '*-*.*-*').should.be.true(); - mm.isMatch('a-b.c-d', '*.c-*').should.be.true(); - mm.isMatch('a-b.c-d', '*.*-d').should.be.true(); - mm.isMatch('a-b.c-d', 'a-*.*-d').should.be.true(); - mm.isMatch('a-b.c-d', '*-b.c-*').should.be.true(); - mm.isMatch('a-b.c-d', '*-b*c-*').should.be.true(); + assert(mm.isMatch('a.b', 'a.b')); + assert(mm.isMatch('a.b', '*.b')); + assert(mm.isMatch('a.b', 'a.*')); + assert(mm.isMatch('a.b', '*.*')); + assert(mm.isMatch('a-b.c-d', 'a*.c*')); + assert(mm.isMatch('a-b.c-d', '*b.*d')); + assert(mm.isMatch('a-b.c-d', '*.*')); + assert(mm.isMatch('a-b.c-d', '*.*-*')); + assert(mm.isMatch('a-b.c-d', '*-*.*-*')); + assert(mm.isMatch('a-b.c-d', '*.c-*')); + assert(mm.isMatch('a-b.c-d', '*.*-d')); + assert(mm.isMatch('a-b.c-d', 'a-*.*-d')); + assert(mm.isMatch('a-b.c-d', '*-b.c-*')); + assert(mm.isMatch('a-b.c-d', '*-b*c-*')); // false - mm.isMatch('a-b.c-d', '*-bc-*').should.be.false(); + assert(!mm.isMatch('a-b.c-d', '*-bc-*')); }); it('should match with common glob patterns', function() { - mm.isMatch('/ab', '/*').should.be.true(); - mm.isMatch('/cd', '/*').should.be.true(); - mm.isMatch('ef', '/*').should.be.false(); - mm.isMatch('ab', './*').should.be.false(); - mm.isMatch('ab', '*').should.be.true(); - mm.isMatch('ab', 'ab').should.be.true(); + assert(mm.isMatch('/ab', '/*')); + assert(mm.isMatch('/cd', '/*')); + assert(!mm.isMatch('ef', '/*')); + assert(!mm.isMatch('ab', './*')); + assert(mm.isMatch('ab', '*')); + assert(mm.isMatch('ab', 'ab')); }); it('should match files with the given extension:', function() { - mm.isMatch('.md', '*.md').should.be.false(); - mm.isMatch('.md', '.md').should.be.true(); - mm.isMatch('.c.md', '*.md').should.be.false(); - mm.isMatch('.c.md', '.*.md').should.be.true(); - mm.isMatch('c.md', '*.md').should.be.true(); - mm.isMatch('c.md', '*.md').should.be.true(); - mm.isMatch('a/b/c/c.md', '*.md').should.be.false(); - mm.isMatch('a/b/c.md', 'a/*.md').should.be.false(); - mm.isMatch('a/b/c.md', 'a/*/*.md').should.be.true(); - mm.isMatch('a/b/c.md', '**/*.md').should.be.true(); - mm.isMatch('a/b/c.js', 'a/**/*.*').should.be.true(); + assert(!mm.isMatch('.md', '*.md')); + assert(mm.isMatch('.md', '.md')); + assert(!mm.isMatch('.c.md', '*.md')); + assert(mm.isMatch('.c.md', '.*.md')); + assert(mm.isMatch('c.md', '*.md')); + assert(mm.isMatch('c.md', '*.md')); + assert(!mm.isMatch('a/b/c/c.md', '*.md')); + assert(!mm.isMatch('a/b/c.md', 'a/*.md')); + assert(mm.isMatch('a/b/c.md', 'a/*/*.md')); + assert(mm.isMatch('a/b/c.md', '**/*.md')); + assert(mm.isMatch('a/b/c.js', 'a/**/*.*')); }); it('should match wildcards:', function() { - mm.isMatch('a/b/c/z.js', '*.js').should.be.false(); - mm.isMatch('a/b/z.js', '*.js').should.be.false(); - mm.isMatch('a/z.js', '*.js').should.be.false(); - mm.isMatch('z.js', '*.js').should.be.true(); + assert(!mm.isMatch('a/b/c/z.js', '*.js')); + assert(!mm.isMatch('a/b/z.js', '*.js')); + assert(!mm.isMatch('a/z.js', '*.js')); + assert(mm.isMatch('z.js', '*.js')); - mm.isMatch('z.js', 'z*.js').should.be.true(); - mm.isMatch('a/z.js', 'a/z*.js').should.be.true(); - mm.isMatch('a/z.js', '*/z*.js').should.be.true(); + assert(mm.isMatch('z.js', 'z*.js')); + assert(mm.isMatch('a/z.js', 'a/z*.js')); + assert(mm.isMatch('a/z.js', '*/z*.js')); }); it('should match globstars:', function() { - mm.isMatch('a/b/c/z.js', '**/*.js').should.be.true(); - mm.isMatch('a/b/z.js', '**/*.js').should.be.true(); - mm.isMatch('a/z.js', '**/*.js').should.be.true(); - mm.isMatch('z.js', '**/*.js').should.be.true(); - mm.isMatch('z.js', '**/z*').should.be.true(); - - mm.isMatch('a/b/c/d/e/z.js', 'a/b/**/*.js').should.be.true(); - mm.isMatch('a/b/c/d/z.js', 'a/b/**/*.js').should.be.true(); - mm.isMatch('a/b/c/z.js', 'a/b/c/**/*.js').should.be.true(); - mm.isMatch('a/b/c/z.js', 'a/b/c**/*.js').should.be.true(); - mm.isMatch('a/b/c/z.js', 'a/b/**/*.js').should.be.true(); - mm.isMatch('a/b/z.js', 'a/b/**/*.js').should.be.true(); - - mm.isMatch('a/z.js', 'a/b/**/*.js').should.be.false(); - mm.isMatch('z.js', 'a/b/**/*.js').should.be.false(); + assert(mm.isMatch('a/b/c/z.js', '**/*.js')); + assert(mm.isMatch('a/b/z.js', '**/*.js')); + assert(mm.isMatch('a/z.js', '**/*.js')); + assert(mm.isMatch('a/b/c/d/e/z.js', 'a/b/**/*.js')); + assert(mm.isMatch('a/b/c/d/z.js', 'a/b/**/*.js')); + assert(mm.isMatch('a/b/c/z.js', 'a/b/c/**/*.js')); + assert(mm.isMatch('a/b/c/z.js', 'a/b/c**/*.js')); + assert(mm.isMatch('a/b/c/z.js', 'a/b/**/*.js')); + assert(mm.isMatch('a/b/z.js', 'a/b/**/*.js')); + + assert(!mm.isMatch('a/z.js', 'a/b/**/*.js')); + assert(!mm.isMatch('z.js', 'a/b/**/*.js')); // issue #23 - mm.isMatch('zzjs', 'z*.js').should.be.false(); - mm.isMatch('zzjs', '*z.js').should.be.false(); + assert(!mm.isMatch('zzjs', 'z*.js')); + assert(!mm.isMatch('zzjs', '*z.js')); // issue #24 - mm.isMatch('a', '**').should.be.true(); - mm.isMatch('a', 'a/**').should.be.false(); - mm.isMatch('a/', '**').should.be.true(); - mm.isMatch('a/b/c/d', '**').should.be.true(); - mm.isMatch('a/b/c/d/', '**').should.be.true(); - mm.isMatch('a/b/c/d/', '**/**').should.be.true(); - mm.isMatch('a/b/c/d/', '**/b/**').should.be.true(); - mm.isMatch('a/b/c/d/', 'a/b/**').should.be.true(); - mm.isMatch('a/b/c/d/', 'a/b/**/').should.be.true(); - mm.isMatch('a/b/c/d/', 'a/b/**/c/**/').should.be.true(); - mm.isMatch('a/b/c/d/', 'a/b/**/c/**/d/').should.be.true(); - mm.isMatch('a/b/c/d/', 'a/b/**/f').should.be.false(); - mm.isMatch('a/b/c/d/e.f', 'a/b/**/**/*.*').should.be.true(); - mm.isMatch('a/b/c/d/e.f', 'a/b/**/*.*').should.be.true(); - mm.isMatch('a/b/c/d/e.f', 'a/b/**/c/**/d/*.*').should.be.true(); - mm.isMatch('a/b/c/d/e.f', 'a/b/**/d/**/*.*').should.be.true(); - mm.isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*').should.be.true(); - mm.isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*').should.be.true(); + assert(mm.isMatch('a', '**')); + assert(!mm.isMatch('a', 'a/**')); + assert(mm.isMatch('a/', '**')); + assert(mm.isMatch('a/b/c/d', '**')); + assert(mm.isMatch('a/b/c/d/', '**')); + assert(mm.isMatch('a/b/c/d/', '**/**')); + assert(mm.isMatch('a/b/c/d/', '**/b/**')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**/')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**/c/**/')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**/c/**/d/')); + assert(!mm.isMatch('a/b/c/d/', 'a/b/**/f')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/**/*.*')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/*.*')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/c/**/d/*.*')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/d/**/*.*')); + assert(mm.isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*')); + assert(mm.isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*')); // issue #15 - mm.isMatch('z.js', '**/z*.js').should.be.true(); - mm.isMatch('a/b-c/z.js', 'a/b-*/**/z.js').should.be.true(); - mm.isMatch('a/b-c/d/e/z.js', 'a/b-*/**/z.js').should.be.true(); + assert(mm.isMatch('z.js', 'z*')); + assert(mm.isMatch('z.js', '**/z*')); + assert(mm.isMatch('z.js', '**/z*.js')); + assert(mm.isMatch('z.js', '**/*.js')); + assert(mm.isMatch('foo', '**/foo')); + + assert(mm.isMatch('a/b-c/z.js', 'a/b-*/**/z.js')); + assert(mm.isMatch('a/b-c/d/e/z.js', 'a/b-*/**/z.js')); }); /** @@ -165,108 +155,97 @@ describe('.isMatch()', function() { */ it('Extended slash-matching features', function() { - mm.isMatch('foo/baz/bar', 'foo*bar').should.be.false(); - mm.isMatch('foo/baz/bar', 'foo**bar').should.be.false(); - mm.isMatch('foobazbar', 'foo**bar').should.be.true(); // 3 - mm.isMatch('foo/baz/bar', 'foo/**/bar').should.be.true(); - mm.isMatch('foo/baz/bar', 'foo/**/**/bar').should.be.true(); - mm.isMatch('foo/b/a/z/bar', 'foo/**/bar').should.be.true(); - mm.isMatch('foo/b/a/z/bar', 'foo/**/**/bar').should.be.true(); - mm.isMatch('foo/bar', 'foo/**/bar').should.be.true(); - mm.isMatch('foo/bar', 'foo/**/**/bar').should.be.true(); - mm.isMatch('foo/bar', 'foo?bar').should.be.false(); - mm.isMatch('foo/bar', 'foo[/]bar').should.be.true(); // 2 - mm.isMatch('foo/bar', 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r').should.be.false(); - mm.isMatch('foo-bar', 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r').should.be.true(); - mm.isMatch('foo', '**/foo').should.be.true(); - mm.isMatch('foo', 'foo/**').should.be.false(); - mm.isMatch('XXX/foo', '**/foo').should.be.true(); - mm.isMatch('bar/baz/foo', '**/foo').should.be.true(); - mm.isMatch('bar/baz/foo', '*/foo').should.be.false(); - mm.isMatch('foo/bar/baz', '**/bar*').should.be.false(); - mm.isMatch('deep/foo/bar/baz', '**/bar/*').should.be.true(); - mm.isMatch('deep/foo/bar/baz/', '**/bar/*').should.be.false(); - mm.isMatch('deep/foo/bar/baz/', '**/bar/**').should.be.true(); - mm.isMatch('deep/foo/bar', '**/bar/*').should.be.false(); - mm.isMatch('deep/foo/bar/', '**/bar/**').should.be.true(); - mm.isMatch('foo/bar/baz', '**/bar**').should.be.false(); - mm.isMatch('foo/bar/baz/x', '*/bar/**').should.be.true(); - mm.isMatch('deep/foo/bar/baz/x', '*/bar/**').should.be.false(); - mm.isMatch('deep/foo/bar/baz/x', '**/bar/*/*').should.be.true(); - mm.isMatch('a/j/z/x.md', 'a/**/j/**/z/*.md').should.be.true(); - mm.isMatch('a/b/j/c/z/x.md', 'a/**/j/**/z/*.md').should.be.true(); + assert(!mm.isMatch('foo/baz/bar', 'foo*bar')); + assert(!mm.isMatch('foo/baz/bar', 'foo**bar')); + assert(mm.isMatch('foobazbar', 'foo**bar')); // 3 + assert(mm.isMatch('foo/baz/bar', 'foo/**/bar')); + assert(mm.isMatch('foo/baz/bar', 'foo/**/**/bar')); + assert(mm.isMatch('foo/b/a/z/bar', 'foo/**/bar')); + assert(mm.isMatch('foo/b/a/z/bar', 'foo/**/**/bar')); + assert(mm.isMatch('foo/bar', 'foo/**/bar')); + assert(mm.isMatch('foo/bar', 'foo/**/**/bar')); + assert(!mm.isMatch('foo/bar', 'foo?bar')); + assert(mm.isMatch('foo/bar', 'foo[/]bar')); // 2 + assert(!mm.isMatch('foo', 'foo/**')); + assert(mm.isMatch('XXX/foo', '**/foo')); + assert(mm.isMatch('bar/baz/foo', '**/foo')); + assert(!mm.isMatch('bar/baz/foo', '*/foo')); + assert(!mm.isMatch('foo/bar/baz', '**/bar*')); + assert(mm.isMatch('deep/foo/bar/baz', '**/bar/*')); + assert(!mm.isMatch('deep/foo/bar/baz/', '**/bar/*')); + assert(mm.isMatch('deep/foo/bar/baz/', '**/bar/**')); + assert(!mm.isMatch('deep/foo/bar', '**/bar/*')); + assert(mm.isMatch('deep/foo/bar/', '**/bar/**')); + assert(!mm.isMatch('foo/bar/baz', '**/bar**')); + assert(mm.isMatch('foo/bar/baz/x', '*/bar/**')); + assert(!mm.isMatch('deep/foo/bar/baz/x', '*/bar/**')); + assert(mm.isMatch('deep/foo/bar/baz/x', '**/bar/*/*')); + assert(mm.isMatch('a/j/z/x.md', 'a/**/j/**/z/*.md')); + assert(mm.isMatch('a/b/j/c/z/x.md', 'a/**/j/**/z/*.md')); }); it('question marks should not match slashes:', function() { - mm.isMatch('aaa/bbb', 'aaa?bbb').should.be.false(); + assert(!mm.isMatch('aaa/bbb', 'aaa?bbb')); }); it('should not match dotfiles when `dot` or `dotfiles` are not set:', function() { - mm.isMatch('.c.md', '*.md').should.be.false(); - mm.isMatch('a/.c.md', '*.md').should.be.false(); - mm.isMatch('a/.c.md', 'a/.c.md').should.be.true(); - mm.isMatch('.a', '*.md').should.be.false(); - mm.isMatch('.verb.txt', '*.md').should.be.false(); - mm.isMatch('a/b/c/.xyz.md', 'a/b/c/.*.md').should.be.true(); - mm.isMatch('.md', '.md').should.be.true(); - mm.isMatch('.txt', '.md').should.be.false(); - mm.isMatch('.md', '.md').should.be.true(); - mm.isMatch('.a', '.a').should.be.true(); - mm.isMatch('.b', '.b*').should.be.true(); - mm.isMatch('.ab', '.a*').should.be.true(); - mm.isMatch('.ab', '.*').should.be.true(); - mm.isMatch('.ab', '*.*').should.be.false(); - mm.isMatch('.md', 'a/b/c/*.md').should.be.false(); - mm.isMatch('.a.md', 'a/b/c/*.md').should.be.false(); - mm.isMatch('a/b/c/d.a.md', 'a/b/c/*.md').should.be.true(); - mm.isMatch('a/b/d/.md', 'a/b/c/*.md').should.be.false(); + assert(!mm.isMatch('.c.md', '*.md')); + assert(!mm.isMatch('a/.c.md', '*.md')); + assert(mm.isMatch('a/.c.md', 'a/.c.md')); + assert(!mm.isMatch('.a', '*.md')); + assert(!mm.isMatch('.verb.txt', '*.md')); + assert(mm.isMatch('a/b/c/.xyz.md', 'a/b/c/.*.md')); + assert(mm.isMatch('.md', '.md')); + assert(!mm.isMatch('.txt', '.md')); + assert(mm.isMatch('.md', '.md')); + assert(mm.isMatch('.a', '.a')); + assert(mm.isMatch('.b', '.b*')); + assert(mm.isMatch('.ab', '.a*')); + assert(mm.isMatch('.ab', '.*')); + assert(!mm.isMatch('.ab', '*.*')); + assert(!mm.isMatch('.md', 'a/b/c/*.md')); + assert(!mm.isMatch('.a.md', 'a/b/c/*.md')); + assert(mm.isMatch('a/b/c/d.a.md', 'a/b/c/*.md')); + assert(!mm.isMatch('a/b/d/.md', 'a/b/c/*.md')); }); it('should match dotfiles when `dot` or `dotfiles` is set:', function() { - mm.isMatch('.c.md', '*.md', {dot: true}).should.be.true(); - mm.isMatch('.c.md', '.*', {dot: true}).should.be.true(); - mm.isMatch('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true}).should.be.true(); - mm.isMatch('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true}).should.be.true(); + assert(mm.isMatch('.c.md', '*.md', {dot: true})); + assert(mm.isMatch('.c.md', '.*', {dot: true})); + assert(mm.isMatch('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true})); + assert(mm.isMatch('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true})); }); it('should match file paths:', function() { - mm.isMatch('a/b/c/xyz.md', 'a/b/c/*.md').should.be.true(); - mm.isMatch('a/bb/c/xyz.md', 'a/*/c/*.md').should.be.true(); - mm.isMatch('a/bbbb/c/xyz.md', 'a/*/c/*.md').should.be.true(); - mm.isMatch('a/bb.bb/c/xyz.md', 'a/*/c/*.md').should.be.true(); - mm.isMatch('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md').should.be.true(); - mm.isMatch('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md').should.be.true(); + assert(mm.isMatch('a/b/c/xyz.md', 'a/b/c/*.md')); + assert(mm.isMatch('a/bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.isMatch('a/bbbb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.isMatch('a/bb.bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.isMatch('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md')); + assert(mm.isMatch('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md')); }); it('should match full file paths:', function() { - mm.isMatch('a/.b', 'a/**/z/*.md').should.be.false(); - mm.isMatch('a/.b', 'a/.*').should.be.true(); - mm.isMatch('a/b/z/.a', 'a/**/z/*.a').should.be.false(); - mm.isMatch('a/b/z/.a', 'a/*/z/*.a').should.be.false(); - mm.isMatch('a/b/z/.a', 'a/*/z/.a').should.be.true(); - mm.isMatch('a/b/c/d/e/z/c.md', 'a/**/z/*.md').should.be.true(); - mm.isMatch('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md').should.be.true(); - mm.isMatch('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md').should.be.false(); - mm.isMatch('a/b/d/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.isMatch('a/b/c/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.isMatch('a/b/c/cd/bar/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.true(); - mm.isMatch('a/b/baz/ce/fez/xyz.md', 'a/b/**/c{d,e}/**/xyz.md').should.be.true(); + assert(!mm.isMatch('a/.b', 'a/**/z/*.md')); + assert(mm.isMatch('a/.b', 'a/.*')); + assert(!mm.isMatch('a/b/z/.a', 'a/**/z/*.a')); + assert(!mm.isMatch('a/b/z/.a', 'a/*/z/*.a')); + assert(mm.isMatch('a/b/z/.a', 'a/*/z/.a')); + assert(mm.isMatch('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.isMatch('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); + assert(!mm.isMatch('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md')); }); it('should match paths with leading `./`:', function() { - mm.isMatch('./.a', 'a/**/z/*.md').should.be.false(); - mm.isMatch('./a/b/z/.a', 'a/**/z/.a').should.be.false(); - mm.isMatch('./a/b/z/.a', './a/**/z/.a').should.be.true(); - mm.isMatch('./a/b/c/d/e/z/c.md', 'a/**/z/*.md').should.be.false(); - mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/z/*.md').should.be.true(); - mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md').should.be.false(); - mm.isMatch('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md').should.be.true(); - mm.isMatch('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md').should.be.false(); - mm.isMatch('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md').should.be.true(); - mm.isMatch('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md').should.be.false(); - mm.isMatch('./a/b/d/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.isMatch('./a/b/c/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.false(); - mm.isMatch('./a/b/c/cd/bar/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.true(); - mm.isMatch('./a/b/baz/ce/fez/xyz.md', './a/b/**/c{d,e}/**/xyz.md').should.be.true(); + assert(!mm.isMatch('./.a', 'a/**/z/*.md')); + assert(!mm.isMatch('./a/b/z/.a', 'a/**/z/.a')); + assert(mm.isMatch('./a/b/z/.a', './a/**/z/.a')); + assert(!mm.isMatch('./a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/z/*.md')); + assert(!mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.isMatch('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md')); + assert(!mm.isMatch('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md')); + assert(mm.isMatch('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md')); + assert(!mm.isMatch('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md')); }); }); diff --git a/test/issue-related.js b/test/issue-related.js new file mode 100644 index 00000000..7bfc47bd --- /dev/null +++ b/test/issue-related.js @@ -0,0 +1,34 @@ +'use strict'; + +var assert = require('assert'); +var argv = require('yargs-parser')(process.argv.slice(2)); +var matcher = argv.mm ? require('minimatch') : require('..'); +var isMatch = argv.mm ? matcher : matcher.isMatch; + +describe('issue-related tests', function() { + it('issue #23', function() { + assert(!isMatch('zzjs', 'z*.js')); + assert(!isMatch('zzjs', '*z.js')); + }); + + it('issue #24', function() { + assert(!isMatch('a', 'a/**')); + assert(!isMatch('a/b/c/d/', 'a/b/**/f')); + assert(isMatch('a', '**')); + assert(isMatch('a/', '**')); + assert(isMatch('a/b/c/d', '**')); + assert(isMatch('a/b/c/d/', '**')); + assert(isMatch('a/b/c/d/', '**/**')); + assert(isMatch('a/b/c/d/', '**/b/**')); + assert(isMatch('a/b/c/d/', 'a/b/**')); + assert(isMatch('a/b/c/d/', 'a/b/**/')); + assert(isMatch('a/b/c/d/e.f', 'a/b/**/**/*.*')); + assert(isMatch('a/b/c/d/e.f', 'a/b/**/*.*')); + assert(isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*')); + assert(isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*')); + }); + + it('issue #15', function() { + assert(isMatch('a/b-c/d/e/z.js', 'a/b-*/**/z.js')); + }); +}); diff --git a/test/makeRe.js b/test/makeRe.js deleted file mode 100644 index c5508550..00000000 --- a/test/makeRe.js +++ /dev/null @@ -1,247 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = require('minimatch'); -} - -describe('.makeRe()', function() { - describe('errors:', function() { - it('should throw when undefined:', function() { - (function() { - mm.makeRe(); - }).should.throw('micromatch.makeRe(): glob should be a string.'); - }); - - it('should throw when not a string:', function() { - (function() { - mm.makeRe({}); - }).should.throw('micromatch.makeRe(): glob should be a string.'); - }); - - it('should throw on bad regex in strict mode:', function() { - (function() { - mm.makeRe('(foo', {strict: true}); - }).should.throw('SyntaxError: Invalid regular expression: /^(?:(foo)$/: Unterminated group'); - }); - }); - - describe('file extensions:', function() { - it('should create a regular expression for matching extensions:', function() { - mm.makeRe('.md').should.eql(/^(?:\.md)$/); - mm.makeRe('.txt').should.eql(/^(?:\.txt)$/); - mm.makeRe('.md').test('.md').should.be.true(); - mm.makeRe('.md').test('.txt').should.be.false(); - mm.makeRe('.md').test('.gitignore').should.be.false(); - }); - }); - - describe('braces:', function() { - it('should create a regular expression for matching extensions:', function() { - mm.makeRe('a/b/c/{d,e}/f.js').should.eql(/^(?:a\/b\/c\/(d|e)\/f\.js)$/); - }); - }); - - describe('file names:', function() { - it('should match files with the given extension:', function() { - mm.makeRe('*.md').test('foo.md').should.be.true(); - mm.makeRe('*.md').test('a/b/c/foo.md').should.be.false(); - }); - - it('should create a regex for matching dotfiles:', function() { - mm.makeRe('*.md').test('a.md').should.be.true(); - mm.makeRe('*.*.md').test('.foo.md').should.be.false(); - mm.makeRe('!*.*.md').test('.foo.md').should.be.true(); - mm.makeRe('*.*.md').test('a.foo.md').should.be.true(); - mm.makeRe('*.md').test('.gitignore').should.be.false(); - mm.makeRe('.gitignore').test('.gitignore').should.be.true(); - mm.makeRe('!.gitignore').test('.gitignore').should.be.false(); - mm.makeRe('*.md').test('.verb.txt').should.be.false(); - mm.makeRe('a/b/c/.*.md').test('a/b/c/.xyz.md').should.be.true(); - }); - }); - - describe('file paths:', function() { - it('should create a regular expression for file paths:', function() { - mm.makeRe('**/*.js').test('a/b.js').should.be.true(); - mm.makeRe('**/*.js').test('b.js').should.be.true(); - mm.makeRe('*.js').test('a/b.js').should.be.false(); - mm.makeRe('*.js').test('a.js').should.be.true(); - mm.makeRe('a/b/c/*.md').test('.gitignore').should.be.false(); - mm.makeRe('a/b/c/*.md').test('.gitignore.md').should.be.false(); - mm.makeRe('a/b/c/*.md').test('a/b/c/d.gitignore.md').should.be.true(); - mm.makeRe('a/b/c/*.md').test('a/b/d/.gitignore').should.be.false(); - mm.makeRe('a/b/c/*.md').test('a/b/c/xyz.md').should.be.true(); - mm.makeRe('a/*/c/*.md').test('a/bb/c/xyz.md').should.be.true(); - mm.makeRe('a/*/c/*.md').test('a/bbbb/c/xyz.md').should.be.true(); - mm.makeRe('a/*/c/*.md').test('a/bb.bb/c/xyz.md').should.be.true(); - mm.makeRe('a/**/c/*.md').test('a/bb.bb/aa/bb/aa/c/xyz.md').should.be.true(); - mm.makeRe('a/**/c/*.md').test('a/bb.bb/aa/b.b/aa/c/xyz.md').should.be.true(); - }); - }); - - describe('special characters:', function() { - it('should match one character per question mark:', function() { - mm.makeRe('a/?/c.md').test('a/b/c.md').should.be.true(); - mm.makeRe('a/?/c.md').test('a/bb/c.md').should.be.false(); - mm.makeRe('a/??/c.md').test('a/bb/c.md').should.be.true(); - mm.makeRe('a/??/c.md').test('a/bbb/c.md').should.be.false(); - mm.makeRe('a/???/c.md').test('a/bbb/c.md').should.be.true(); - mm.makeRe('a/????/c.md').test('a/bbbb/c.md').should.be.true(); - }); - - it('should match multiple groups of question marks:', function() { - mm.makeRe('a/?/c/?/e.md').test('a/bb/c/dd/e.md').should.be.false(); - mm.makeRe('a/?/c/?/e.md').test('a/b/c/d/e.md').should.be.true(); - mm.makeRe('a/?/c/???/e.md').test('a/b/c/d/e.md').should.be.false(); - mm.makeRe('a/?/c/???/e.md').test('a/b/c/zzz/e.md').should.be.true(); - }); - - it('should use special characters and glob stars together:', function() { - mm.makeRe('a/?/c/?/*/e.md').test('a/b/c/d/e.md').should.be.false(); - mm.makeRe('a/?/c/?/*/e.md').test('a/b/c/d/e/e.md').should.be.true(); - mm.makeRe('a/?/c/?/*/e.md').test('a/b/c/d/efghijk/e.md').should.be.true(); - mm.makeRe('a/?/**/e.md').test('a/b/c/d/efghijk/e.md').should.be.true(); - mm.makeRe('a/?/**/e.md').test('a/bb/c/d/efghijk/e.md').should.be.false(); - mm.makeRe('a/*/?/**/e.md').test('a/b/c/d/efghijk/e.md').should.be.true(); - mm.makeRe('a/*/?/**/e.md').test('a/b/c/d/efgh.ijk/e.md').should.be.true(); - mm.makeRe('a/*/?/**/e.md').test('a/b.bb/c/d/efgh.ijk/e.md').should.be.true(); - mm.makeRe('a/*/?/**/e.md').test('a/bbb/c/d/efgh.ijk/e.md').should.be.true(); - }); - }); - - describe('brace expansion:', function() { - it('should create a regular brace expansion:', function() { - mm.makeRe('a/b/c{d,e}/*.md').test('iii.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/d/iii.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/c/iii.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/cd/iii.md').should.be.true(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/ce/iii.md').should.be.true(); - - mm.makeRe('a/b/c{d,e}/xyz.md').test('xyz.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/d/xyz.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/c/xyz.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/cd/xyz.md').should.be.true(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/ce/xyz.md').should.be.true(); - }); - }); - - describe('double stars:', function() { - it('should create a regular expression for double stars:', function() { - mm.makeRe('a/**/z/*.md').test('.gitignore').should.be.false(); - mm.makeRe('a/**/z/*.md').test('a/b/z/.gitignore').should.be.false(); - mm.makeRe('a/**/z/*.md').test('a/b/c/d/e/z/foo.md').should.be.true(); - - mm.makeRe('a/**/j/**/z/*.md').test('a/b/c/d/e/z/foo.md').should.be.false(); - mm.makeRe('a/**/j/**/z/*.md').test('a/b/c/j/e/z/foo.md').should.be.true(); - mm.makeRe('a/**/j/**/z/*.md').test('a/b/c/d/e/j/n/p/o/z/foo.md').should.be.true(); - mm.makeRe('a/**/j/**/z/*.md').test('a/b/c/j/e/z/foo.txt').should.be.false(); - - mm.makeRe('a/b/**/c{d,e}/**/xyz.md').test('a/b/d/xyz.md').should.be.false(); - mm.makeRe('a/b/**/c{d,e}/**/xyz.md').test('a/b/c/xyz.md').should.be.false(); - mm.makeRe('a/b/**/c{d,e}/**/xyz.md').test('a/b/foo/cd/bar/xyz.md').should.be.true(); - mm.makeRe('a/b/**/c{d,e}/**/xyz.md').test('a/b/baz/ce/fez/xyz.md').should.be.true(); - }); - }); - - describe('negation', function() { - it('should create a regular expression for negating extensions:', function() { - mm.makeRe('!.md').test('.md').should.be.false(); - mm.makeRe('!.md').test('foo.md').should.be.true(); - mm.makeRe('!*.md').test('foo.md').should.be.false(); - }); - - it('should create a regular expression for negating files with extensions:', function() { - mm.makeRe('!*.md').test('abc.md').should.be.false(); - mm.makeRe('!*.md').test('abc.txt').should.be.true(); - mm.makeRe('!*.md').test('.dotfile.md').should.be.true(); - mm.makeRe('!*.md').test('.dotfile.txt').should.be.true(); - }); - - it('should create a regular expression for slashes:', function() { - mm.makeRe('a/b/c/*.md').test('.gitignore').should.be.false(); - mm.makeRe('a/b/c/*.md').test('a/b/c/.gitignore').should.be.false(); - mm.makeRe('a/b/c/*.md').test('a/b/c/foo.md').should.be.true(); - mm.makeRe('a/b/c/*.md').test('a/b/c/bar.md').should.be.true(); - }); - - it('should create a regular brace expansion:', function() { - mm.makeRe('a/b/c{d,e}/*.md').test('iii.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/d/iii.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/c/iii.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/cd/iii.md').should.be.true(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/ce/iii.md').should.be.true(); - - mm.makeRe('a/b/c{d,e}/xyz.md').test('xyz.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/d/xyz.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/c/xyz.md').should.be.false(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/cd/xyz.md').should.be.true(); - mm.makeRe('a/b/c{d,e}/*.md').test('a/b/ce/xyz.md').should.be.true(); - mm.makeRe('a/b/c{d,e{f,g}}/*.md').test('a/b/cef/xyz.md').should.be.true(); - mm.makeRe('a/b/c{d,e{f,g}}/*.md').test('a/b/ceg/xyz.md').should.be.true(); - mm.makeRe('a/b/c{d,e{f,g}}/*.md').test('a/b/cd/xyz.md').should.be.true(); - }); - - it('should match dotfiles:', function() { - mm.makeRe('a/**/z/.*.md').test('a/b/z/.dotfile.md').should.be.true(); - mm.makeRe('a/**/z/*.md').test('a/b/z/.dotfile').should.be.false(); - }); - - it('should create a regular expression for double stars:', function() { - mm.makeRe('a/**/z/*.md').test('.gitignore').should.be.false(); - mm.makeRe('a/**/z/*.md').test('a/b/c/d/e/z/foo.md').should.be.true(); - - mm.makeRe('a/**/j/**/z/*.md').test('a/b/c/d/e/z/foo.md').should.be.false(); - mm.makeRe('a/**/j/**/z/*.md').test('a/b/c/j/e/z/foo.md').should.be.true(); - mm.makeRe('a/**/j/**/z/*.md').test('a/b/c/d/e/j/n/p/o/z/foo.md').should.be.true(); - mm.makeRe('a/**/j/**/z/*.md').test('a/b/c/j/e/z/foo.txt').should.be.false(); - mm.makeRe('a/b/**/c{d,e}/**/xyz.md').test('a/b/d/xyz.md').should.be.false(); - mm.makeRe('a/b/**/c{d,e}/**/xyz.md').test('a/b/c/xyz.md').should.be.false(); - mm.makeRe('a/b/**/c{d,e}/**/xyz.md').test('a/b/foo/cd/bar/xyz.md').should.be.true(); - mm.makeRe('a/b/**/c{d,e}/**/xyz.md').test('a/b/baz/ce/fez/xyz.md').should.be.true(); - }); - }); - - describe('options', function() { - it('should support the `matchBase` option:', function() { - mm.makeRe('*.md').test('a/b/c/foo.md').should.be.false(); - }); - - it('should support the `nocase` option:', function() { - mm.makeRe('a/b/c/*.md').test('a/b/d/e.md').should.be.false(); - mm.makeRe('A/b/C/*.md').test('a/b/c/e.md').should.be.false(); - mm.makeRe('A/b/C/*.md', {nocase: true}).test('a/b/c/e.md').should.be.true(); - mm.makeRe('A/b/C/*.MD', {nocase: true}).test('a/b/c/e.md').should.be.true(); - }); - - it('should match dotfiles when `dotfile` is true:', function() { - var opts = {dot: true}; - - mm.makeRe('.gitignore', opts).test('.gitignore').should.be.true(); - mm.makeRe('*.md', opts).test('foo.md').should.be.true(); - mm.makeRe('*.md', opts).test('.verb.txt').should.be.false(); - mm.makeRe('*.md', opts).test('a/b/c/.gitignore').should.be.false(); - mm.makeRe('*.md', opts).test('a/b/c/.gitignore.md').should.be.false(); - mm.makeRe('**/*.md', opts).test('a/b/c/.gitignore.md').should.be.true(); - mm.makeRe('*.md', opts).test('.verb.txt').should.be.false(); - mm.makeRe('*.md', opts).test('.gitignore').should.be.false(); - mm.makeRe('*.*', opts).test('.gitignore').should.be.true(); - mm.makeRe('*.md', opts).test('.gitignore.md').should.be.true(); - mm.makeRe('**/*.md', opts).test('a/b/c/.verb.md').should.be.true(); - - mm.makeRe('*.md').test('a/b/c/.gitignore.md').should.be.false(); - mm.makeRe('**/.*.md').test('a/b/c/.gitignore.md').should.be.true(); - mm.makeRe('**/.*').test('a/b/c/.gitignore.md').should.be.true(); - }); - }); -}); diff --git a/test/match.js b/test/match.js deleted file mode 100644 index f8cdd55b..00000000 --- a/test/match.js +++ /dev/null @@ -1,222 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -var argv = require('minimist')(process.argv.slice(2)); -var minimatch = require('./support/reference'); -var mm = require('..'); -require('should'); - -if ('minimatch' in argv) { - mm = minimatch; -} - -describe('.match()', function() { - describe('errors:', function() { - it('should throw on undefined args:', function() { - (function() { - mm.match(); - }).should.throw('micromatch.match(): files should be a string or array.'); - }); - - it('should throw on bad args:', function() { - (function() { - mm.match({}); - }).should.throw('micromatch.match(): files should be a string or array.'); - }); - }); - - describe('basic patterns:', function() { - it('should correctly deal with empty globs', function() { - mm.match(['ab'], '').should.eql([]); - mm.match(['a'], '').should.eql([]); - mm.match(['.'], '').should.eql([]); - }); - - it('should support matching with non-glob patterns', function() { - mm.match(['.'], '.').should.eql(['.']); - mm.match(['ab'], 'ab').should.eql(['ab']); - mm.match(['ab', 'a'], 'a').should.eql(['a']); - mm.match(['ab', 'a'], '/a').should.eql([]); - mm.match(['ab', 'a'], 'aa').should.eql([]); - mm.match(['/ab', '/a'], '/a').should.eql(['/a']); - }); - - it('should support matching with glob patterns', function() { - mm.match(['.'], '{.,*}').should.eql(['.']); - mm.match(['ab'], '*').should.eql(['ab']); - mm.match(['ab', 'a'], '?').should.eql(['a']); - mm.match(['ab', 'a'], '*b').should.eql(['ab']); - mm.match(['ab', 'a', 'bb'], '[ab][ab]').should.eql(['ab', 'bb']); - mm.match(['/ab', '/a'], '/*').should.eql(['/ab', '/a']); - }); - - it('should support matching with regex', function() { - mm.match(['.'], /\./).should.eql(['.']); - mm.match(['ab'], /ab/).should.eql(['ab']); - mm.match(['ab', 'a'], /a$/).should.eql(['a']); - mm.match(['ab', 'a'], /\/a/).should.eql([]); - mm.match(['ab', 'a'], /aa/).should.eql([]); - mm.match(['/ab', '/a'], /\/a$/).should.eql(['/a']); - }); - - it('should support matching with a function:', function() { - var matches = mm.match(['a', 'aa', 'aaa', 'aaaa'], function(fp) { - return fp.length >= 3; - }) - matches.should.eql(['aaa', 'aaaa']); - }); - }); - - describe('characters:', function() { - it('should match question marks', function() { - mm.match(['ab', 'a/b', 'bb', 'b/c'], '?a').should.eql([]); - mm.match(['ab', 'a/b', 'bb', 'b/c'], '?/?').should.eql(['a/b', 'b/c']); - mm.match(['ab', 'a/b', 'bb', 'b/c'], 'a?b').should.eql([]); - mm.match(['ab', 'a/b', 'bb', 'b/c'], '?b').should.eql(['ab', 'bb']); - }); - - it('should match one character per question mark', function() { - var files = ['ab', 'a/bc', 'bb', 'bbc', 'b/c', 'a/b/c.js', 'a/b/c.md', 'a/bb/c.js', 'a/bb/c.md', 'a/bbb/c.js', 'a/bbb/c.md', 'a/bbbb/c.js', 'a/bbbb/c.md', 'a/b/c/d/eeeeeee/f.js', 'a/b/c/d/eeeeeee/f.md', 'a/b/c/d/e.js', 'a/b/c/d/e.md', 'a/b/c/ddd/e.js', 'a/b/c/ddd/e.md']; - mm.match(files, '?').should.eql([]); - mm.match(files, '??').should.eql(['ab', 'bb']); - mm.match(files, '???').should.eql(['bbc']); - mm.match(files, 'a/?/c.js').should.eql(['a/b/c.js']); - mm.match(files, 'a/?/c.md').should.eql(['a/b/c.md']); - mm.match(files, 'a/?/c/?/*/f.js').should.eql(['a/b/c/d/eeeeeee/f.js']); - mm.match(files, 'a/?/c/?/*/f.md').should.eql(['a/b/c/d/eeeeeee/f.md']); - mm.match(files, 'a/?/c/?/e.js').should.eql(['a/b/c/d/e.js']); - mm.match(files, 'a/?/c/?/e.md').should.eql(['a/b/c/d/e.md']); - mm.match(files, 'a/?/c/???/e.js').should.eql(['a/b/c/ddd/e.js']); - mm.match(files, 'a/?/c/???/e.md').should.eql(['a/b/c/ddd/e.md']); - mm.match(files, 'a/??/c.js').should.eql(['a/bb/c.js']); - mm.match(files, 'a/??/c.md').should.eql(['a/bb/c.md']); - mm.match(files, 'a/???/c.js').should.eql(['a/bbb/c.js']); - mm.match(files, 'a/???/c.md').should.eql(['a/bbb/c.md']); - mm.match(files, 'a/????/c.js').should.eql(['a/bbbb/c.js']); - mm.match(files, 'a/????/c.md').should.eql(['a/bbbb/c.md']); - }); - }); - - describe('paths/extensions', function() { - it('should match with common glob patterns', function() { - mm.match(['/ab', '/cd', 'ef'], '/*').should.eql(['/ab', '/cd']); - mm.match(['a/b/c/d', 'a/c/d', 'a/f/jjj/acd'], '**/d').should.eql(['a/b/c/d', 'a/c/d']); - mm.match(['ab'], './*').should.eql([]); - mm.match(['./ab'], './*').should.eql(['./ab']); - mm.match(['ab'], '*').should.eql(['ab']); - mm.match(['ab'], 'ab').should.eql(['ab']); - }); - - it('should match one directory level:', function() { - var dirs = ['a/b/c/e', 'a/b/c/d/e']; - mm.match(dirs, 'a/b/c/*').should.eql(['a/b/c/e']); - mm.match(dirs, 'a/b/*/e').should.eql(['a/b/c/e']); - mm.match(dirs, 'a/*/*/e').should.eql(['a/b/c/e']); - mm.match(dirs, '*/*/*/e').should.eql(['a/b/c/e']); - mm.match(dirs, '*/*/*/*').should.eql(['a/b/c/e']); - mm.match(dirs, 'b/*/*/*').should.eql([]); - mm.match(['a/b/c/e', 'b/b/c/e', 'a/b/c/d/e'], '*/b/*/e').should.eql(['a/b/c/e', 'b/b/c/e']); - }); - - it('should match multiple directory levels:', function() { - var dirs = ['a/b/c/e', 'a/b/c/d/e']; - mm.match(dirs, 'a/***').should.eql(dirs); - mm.match(dirs, 'a/**c*').should.eql([]); - mm.match(dirs, 'a/**c/*').should.eql(['a/b/c/e']); - mm.match(dirs, 'a/**/c/*').should.eql(['a/b/c/e']); - mm.match(dirs, 'a/**/e').should.eql(dirs); - mm.match(dirs, 'a/b/**/e').should.eql(dirs); - mm.match(['a/x.js', 'a/z.js', 'z.js'], '*/z*.js').should.eql(['a/z.js']); - mm.match([ 'z.js', 'a/z.js', 'a/b/c/z.js' ], '**z*.js').should.eql(['z.js']); - }); - }); - - describe('paths/filenames:', function() { - it('should match files with the given extension:', function() { - mm.match(['.md', '.txt'], '*.md').should.eql([]); - mm.match(['.md', '.txt'], '.md').should.eql(['.md']); - mm.match(['x.md'], '*.md').should.eql(['x.md']); - mm.match(['x.js.min'], '*.js').should.eql([]); - mm.match(['a/b/c/x.md'], '*.md').should.eql([]); - }); - - it('should not match dotfiles when `dot` or `dotfiles` are not set:', function() { - mm.match(['.a'], '*.md').should.eql([]); - mm.match(['.a'], 'a/b/c/*.md').should.eql([]); - mm.match(['.a.md'], 'a/b/c/*.md').should.eql([]); - mm.match(['.x.md'], '*.md').should.eql([]); - mm.match(['.y.txt'], '*.md').should.eql([]); - mm.match(['a/.x.md'], '*.md').should.eql([]); - mm.match(['a/.x.md'], 'a/.x.md').should.eql(['a/.x.md']); - mm.match(['a/b/c/.xyz.md'], 'a/b/c/.*.md').should.eql(['a/b/c/.xyz.md']); - mm.match(['a/b/c/d.a.md'], 'a/b/c/*.md').should.eql(['a/b/c/d.a.md']); - mm.match(['a/b/d/.a'], 'a/b/c/*.md').should.eql([]); - }); - - it('should match dotfiles when the filename pattern begins with a dot:', function() { - mm.match(['.b'], '.b*').should.eql(['.b']); - mm.match(['.md', '.txt'], '.md').should.eql(['.md']); - mm.match(['.a', 'a'], '.a').should.eql(['.a']); - mm.match(['.ab', '.a', '.b', 'a', 'b'], '.*').should.eql(['.ab', '.a', '.b']); - mm.match(['.ab', '.a', '.b'], '.a*').should.eql(['.ab', '.a']); - }); - - it('should match dotfiles when `dot` or `dotfiles` is set:', function() { - mm.match(['.ab', '.a', '.b'], '*.*', {dot: true}).should.eql(['.ab', '.a', '.b']); - mm.match(['.x.md'], '*.md', {dot: true}).should.eql(['.x.md']); - mm.match(['.x.md'], '.*', {dot: true}).should.eql(['.x.md']); - mm.match(['a/b/c/.xyz.md'], 'a/b/c/*.md', {dot: true}).should.eql(['a/b/c/.xyz.md']); - mm.match(['c/.dotfile', 'c/a', 'c/b'], '**/.*', {dot: true}).should.eql(['c/.dotfile']); - }); - }); - - describe('paths/filepaths:', function() { - it('should match file paths:', function() { - mm.match(['a/b/c/xyz.md'], '**/*.md').should.eql(['a/b/c/xyz.md']); - mm.match(['c/.dotfile', 'c/a', 'c/b'], '**/.*').should.eql(['c/.dotfile']); - mm.match(['a/b/c/xyz.min.md'], '**/*.md').should.eql(['a/b/c/xyz.min.md']); - mm.match(['a/b/c/xyz.md'], 'a/b/c/*.md').should.eql(['a/b/c/xyz.md']); - mm.match(['a/bb/c/xyz.md'], 'a/*/c/*.md').should.eql(['a/bb/c/xyz.md']); - mm.match(['a/bbbb/c/xyz.md'], 'a/*/c/*.md').should.eql(['a/bbbb/c/xyz.md']); - mm.match(['a/bb.bb/c/xyz.md'], 'a/*/c/*.md').should.eql(['a/bb.bb/c/xyz.md']); - mm.match(['a/bb.bb/aa/bb/aa/c/xyz.md'], 'a/**/c/*.md').should.eql(['a/bb.bb/aa/bb/aa/c/xyz.md']); - mm.match(['a/bb.bb/aa/b.b/aa/c/xyz.md'], 'a/**/c/*.md').should.eql(['a/bb.bb/aa/b.b/aa/c/xyz.md']); - }); - }); - - describe('double stars:', function() { - it('should match full file paths:', function() { - mm.match(['.a'], 'a/**/z/*.md').should.eql([]); - mm.match(['a/b/z/.a'], 'a/**/z/*.md').should.eql([]); - mm.match(['a/b/c/d/e/z/x.md'], 'a/**/z/*.md').should.eql(['a/b/c/d/e/z/x.md']); - - mm.match(['a/b/c/d/e/z/x.md'], 'a/**/j/**/z/*.md').should.eql([]); - mm.match(['a/b/c/j/e/z/x.md'], 'a/**/j/**/z/*.md').should.eql(['a/b/c/j/e/z/x.md']); - mm.match(['a/b/c/d/e/j/n/p/o/z/x.md'], 'a/**/j/**/z/*.md').should.eql(['a/b/c/d/e/j/n/p/o/z/x.md']); - mm.match(['a/b/c/j/e/z/x.txt'], 'a/**/j/**/z/*.md').should.eql([]); - - mm.match(['a/b/d/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm.match(['a/b/c/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm.match(['a/b/x/cd/bar/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql(['a/b/x/cd/bar/xyz.md']); - mm.match(['a/b/baz/ce/fez/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql(['a/b/baz/ce/fez/xyz.md']); - }); - - it('should match paths with leading `./`:', function() { - mm.match(['./.a'], 'a/**/z/*.md').should.eql([]); - mm.match(['./a/b/z/.a'], 'a/**/z/*.md').should.eql([]); - mm.match(['./a/b/c/d/e/z/x.md'], 'a/**/z/*.md').should.eql([]); - mm.match(['./a/b/c/d/e/z/x.md'], './a/**/z/*.md').should.eql(['./a/b/c/d/e/z/x.md']); - - mm.match(['./a/b/c/d/e/z/x.md'], './a/**/j/**/z/*.md').should.eql([]); - mm.match(['./a/b/c/j/e/z/x.md'], './a/**/j/**/z/*.md').should.eql(['./a/b/c/j/e/z/x.md']); - mm.match(['./a/b/c/d/e/j/n/p/o/z/x.md'], './a/**/j/**/z/*.md').should.eql(['./a/b/c/d/e/j/n/p/o/z/x.md']); - mm.match(['./a/b/c/j/e/z/x.txt'], './a/**/j/**/z/*.md').should.eql([]); - }); - }); -}); diff --git a/test/matchKeys.js b/test/matchKeys.js deleted file mode 100644 index fff29f50..00000000 --- a/test/matchKeys.js +++ /dev/null @@ -1,45 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('should'); -var mm = require('..'); - -describe('.matchKeys()', function() { - describe('errors:', function() { - it('should throw on undefined args:', function() { - (function() { - mm.matchKeys(); - }).should.throw('micromatch.matchKeys(): first argument should be an object.'); - }); - - it('should throw on bad args:', function() { - (function() { - mm.matchKeys('foo'); - }).should.throw('micromatch.matchKeys(): first argument should be an object.'); - }); - }); - - describe('match object keys:', function() { - it('should return a new object with only keys that match a glob pattern:', function() { - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, '*').should.eql({a: 'a', b: 'b', c: 'c'}); - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, 'a').should.eql({a: 'a'}); - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, 'a').should.not.eql({b: 'b'}); - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, '[a-b]').should.eql({a: 'a', b: 'b'}); - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, '(a|c)').should.eql({a: 'a', c: 'c'}); - }); - - it('should return a new object with only keys that match a regex:', function() { - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /.*/).should.eql({a: 'a', b: 'b', c: 'c'}); - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /a/).should.eql({a: 'a'}); - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /a/).should.not.eql({b: 'b'}); - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /[a-b]/).should.eql({a: 'a', b: 'b'}); - mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /(a|c)/).should.eql({a: 'a', c: 'c'}); - }); - }); -}); diff --git a/test/matcher.js b/test/matcher.js deleted file mode 100644 index 19053052..00000000 --- a/test/matcher.js +++ /dev/null @@ -1,90 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -var argv = require('minimist')(process.argv.slice(2)); -var minimatch = require('./support/reference'); -var mm = require('..'); -require('should'); - -if ('minimatch' in argv) { - mm = minimatch; -} - -describe('matcher', function() { - describe('errors:', function() { - it('should throw on undefined args:', function() { - (function() { - mm.matcher(); - }).should.throw('micromatch.matcher(): pattern should be a string, regex, or function.'); - }); - - it('should throw on bad args:', function() { - (function() { - mm.matcher({}); - }).should.throw('micromatch.matcher(): pattern should be a string, regex, or function.'); - }); - }); - - describe('should return matcher functions', function() { - it('when the pattern is regex:', function() { - var isMatch = mm.matcher(/[a-c]\.md$/); - isMatch('a.md').should.be.true(); - isMatch('b.md').should.be.true(); - isMatch('c.md').should.be.true(); - isMatch('e.md').should.be.false(); - isMatch('d.md').should.be.false(); - isMatch('a.js').should.be.false(); - isMatch('c.js').should.be.false(); - }); - - it('when the pattern is a glob string:', function() { - var isMatch = mm.matcher('**/*.js'); - isMatch('a/a.md').should.be.false(); - isMatch('a/b.md').should.be.false(); - isMatch('a/c.md').should.be.false(); - isMatch('a/e.md').should.be.false(); - isMatch('a/d.md').should.be.false(); - isMatch('a/a.js').should.be.true(); - isMatch('a/c.js').should.be.true(); - }); - - it('when the pattern is a glob it should support `matchBase`:', function() { - var matcherA = mm.matcher('*.js', {matchBase: false}); - matcherA('a/a.js').should.be.false(); - matcherA('a/c.js').should.be.false(); - - var matcherB = mm.matcher('*.js', {matchBase: true}); - matcherB('a/a.js').should.be.true(); - matcherB('a/c.js').should.be.true(); - }); - - it('when the pattern is a non-glob string:', function() { - var isMatch = mm.matcher('b.md'); - isMatch('a.md').should.be.false(); - isMatch('b.md').should.be.true(); - isMatch('c.md').should.be.false(); - isMatch('e.md').should.be.false(); - isMatch('d.md').should.be.false(); - isMatch('a.js').should.be.false(); - isMatch('c.js').should.be.false(); - }); - - it('when the pattern is a function:', function() { - var isMatch = mm.matcher(function(fp) { - return fp === 'a.md'; - }); - - isMatch('a.md').should.be.true(); - isMatch('b.md').should.be.false(); - isMatch('c.md').should.be.false(); - isMatch('d.md').should.be.false(); - isMatch('e.md').should.be.false(); - }); - }); -}); diff --git a/test/micromatch.js b/test/micromatch.js deleted file mode 100644 index 871d960f..00000000 --- a/test/micromatch.js +++ /dev/null @@ -1,255 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('should'); -var path = require('path'); -var assert = require('assert'); -var argv = require('minimist')(process.argv.slice(2)); -var mm = require('..'); - -if ('multimatch' in argv) { - mm = require('multimatch'); -} - -describe('micromatch', function() { - it('should return an empty array when no pattern is passed:', function() { - mm(['.md']).should.eql([]); - }); -}); - -describe('micromatch array patterns', function() { - it('should match file extensions:', function() { - mm(['.md'], ['.md']).should.eql(['.md']); - mm(['.txt'], ['.md']).should.eql([]); - mm(['.gitignore'], ['.md']).should.eql([]); - }); - - it('should match files with the given extension:', function() { - mm(['a.md', 'a.txt'], ['*.md']).should.eql(['a.md']); - mm(['.d.md'], ['.*.md']).should.eql(['.d.md']); - mm(['d.md'], ['*.md']).should.eql(['d.md']); - mm(['a/b/c/d.md'], ['*.md']).should.eql([]); - }); - it('should not match dotfiles by default:', function() { - mm(['.gitignore'], ['*.md']).should.eql([]); - mm(['.verb.txt'], ['*.md']).should.eql([]); - }); - - describe('file paths:', function() { - it('should match full file paths using an array of patterns:', function() { - mm(['a/b/c.md', 'a/b/c.txt'], '!**/*.txt').should.eql(['a/b/c.md']); - mm(['.gitignore'], ['a/b/c/*.md']).should.eql([]); - mm(['.gitignore.md'], ['a/b/c/*.md']).should.eql([]); - mm(['a.js'], ['*.js']).should.eql(['a.js']); - mm(['a.js', 'b.js', 'a/b.js'], ['**/*.js']).should.eql(['a.js', 'b.js', 'a/b.js']); - mm(['a/b/c/d.gitignore.md'], ['a/b/c/*.md']).should.eql(['a/b/c/d.gitignore.md']); - mm(['a/b/d/.gitignore'], ['a/b/c/*.md']).should.eql([]); - mm(['a/b/c/xyz.md'], ['a/*/c/*.md']).should.eql(['a/b/c/xyz.md']); - mm(['a/b/c/xyz.md'], ['a/**/*.md']).should.eql(['a/b/c/xyz.md']); - mm(['a/b/c/d/e/f/xyz.md'], ['a/**/*.md']).should.eql(['a/b/c/d/e/f/xyz.md']); - mm(['a/b/c/.xyz.md'], ['a/b/c/.*.md']).should.eql(['a/b/c/.xyz.md']); - mm(['a/bb/c/xyz.md'], ['a/*/c/*.md']).should.eql(['a/bb/c/xyz.md']); - mm(['a/bbbb/c/xyz.md'], ['a/*/c/*.md']).should.eql(['a/bbbb/c/xyz.md']); - mm(['a/bb.bb/c/xyz.md'], ['a/*/c/*.md']).should.eql(['a/bb.bb/c/xyz.md']); - mm(['a/bb.bb/aa/bb/aa/c/xyz.md'], ['a/**/c/*.md']).should.eql(['a/bb.bb/aa/bb/aa/c/xyz.md']); - mm(['a/bb.bb/aa/b.b/aa/c/xyz.md'], ['a/**/c/*.md']).should.eql(['a/bb.bb/aa/b.b/aa/c/xyz.md']); - }); - - it('matchBase / negation:', function() { - mm(['a/b/c.md', 'a/b/c.txt'], ['*', '!*.md'], {matchBase: true}).should.eql(['a/b/c.txt']); - }); - }); - - describe('special characters:', function() { - it('should match one character per question mark:', function() { - mm(['a/b/c.md'], ['a/?/c.md']).should.eql(['a/b/c.md']); - mm(['a/bb/c.md'], ['a/?/c.md']).should.eql([]); - mm(['a/bb/c.md'], ['a/??/c.md']).should.eql(['a/bb/c.md']); - mm(['a/bbb/c.md'], ['a/??/c.md']).should.eql([]); - mm(['a/bbb/c.md'], ['a/???/c.md']).should.eql(['a/bbb/c.md']); - mm(['a/bbbb/c.md'], ['a/????/c.md']).should.eql(['a/bbbb/c.md']); - }); - - it('should match multiple groups of question marks:', function() { - mm(['a/bb/c/dd/e.md'], ['a/?/c/?/e.md']).should.eql([]); - mm(['a/b/c/d/e.md'], ['a/?/c/?/e.md']).should.eql(['a/b/c/d/e.md']); - mm(['a/b/c/d/e.md'], ['a/?/c/???/e.md']).should.eql([]); - mm(['a/b/c/zzz/e.md'], ['a/?/c/???/e.md']).should.eql(['a/b/c/zzz/e.md']); - }); - - it('should use special characters and glob stars together:', function() { - mm(['a/b/c/d/e.md'], ['a/?/c/?/*/e.md']).should.eql([]); - mm(['a/b/c/d/e/e.md'], ['a/?/c/?/*/e.md']).should.eql(['a/b/c/d/e/e.md']); - mm(['a/b/c/d/efghijk/e.md'], ['a/?/c/?/*/e.md']).should.eql(['a/b/c/d/efghijk/e.md']); - mm(['a/b/c/d/efghijk/e.md'], ['a/?/**/e.md']).should.eql(['a/b/c/d/efghijk/e.md']); - mm(['a/bb/c/d/efghijk/e.md'], ['a/?/**/e.md']).should.eql([]); - mm(['a/b/c/d/efghijk/e.md'], ['a/*/?/**/e.md']).should.eql(['a/b/c/d/efghijk/e.md']); - mm(['a/b/c/d/efgh.ijk/e.md'], ['a/*/?/**/e.md']).should.eql(['a/b/c/d/efgh.ijk/e.md']); - mm(['a/b.bb/c/d/efgh.ijk/e.md'], ['a/*/?/**/e.md']).should.eql(['a/b.bb/c/d/efgh.ijk/e.md']); - mm(['a/bbb/c/d/efgh.ijk/e.md'], ['a/*/?/**/e.md']).should.eql(['a/bbb/c/d/efgh.ijk/e.md']); - }); - }); - - describe('brace expansion:', function() { - it('should expand braces:', function() { - mm(['iii.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/d/iii.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/c/iii.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/cd/iii.md'], ['a/b/c{d,e}/*.md']).should.eql(['a/b/cd/iii.md']); - mm(['a/b/ce/iii.md'], ['a/b/c{d,e}/*.md']).should.eql(['a/b/ce/iii.md']); - - mm(['xyz.md'], ['a/b/c{d,e}/xyz.md']).should.eql([]); - mm(['a/b/d/xyz.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/c/xyz.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/cd/xyz.md'], ['a/b/c{d,e}/*.md']).should.eql(['a/b/cd/xyz.md']); - mm(['a/b/ce/xyz.md'], ['a/b/c{d,e}/*.md']).should.eql(['a/b/ce/xyz.md']); - }); - }); - - describe('directories:', function() { - it('should match a single directory deep:', function() { - assert.deepEqual(mm(['a/b/c/d/e', 'a/b/c/d', 'a/b/c', 'a/b', 'a'], ['*']), ['a']); - }); - - it('should match a directory for each `*/`', function() { - var fixture = ['a/b/c/d/e', 'a/b/c/d', 'a/b/c', 'a/b', 'a']; - assert.deepEqual(mm(fixture, ['*/*']), ['a/b']); - assert.deepEqual(mm(fixture, ['*/*/*']), ['a/b/c']); - assert.deepEqual(mm(fixture, ['*/*/*/*']), ['a/b/c/d']); - assert.deepEqual(mm(fixture, ['*/*/*/*/*']), ['a/b/c/d/e']); - }); - - it('should match no less than the numbe of `*/` patterns when a globstar is passed', function() { - var fixture = ['a/b/c/d/e', 'a/b/c/d', 'a/b/c', 'a/b', 'a']; - assert.deepEqual(mm(fixture, ['*/*/**']), ['a/b/c/d/e', 'a/b/c/d', 'a/b/c']); - assert.deepEqual(mm(fixture, ['*/*/*/**']), ['a/b/c/d/e', 'a/b/c/d']); - assert.deepEqual(mm(fixture, ['*/*/*/*/**']), ['a/b/c/d/e']); - assert.deepEqual(mm(fixture, ['*/*/*/*/*/**']), []); - }); - }); - - describe('double stars:', function() { - it('should match path segments:', function() { - mm(['.gitignore'], ['a/**/z/*.md']).should.eql([]); - mm(['a/b/z/.gitignore'], ['a/**/z/*.md']).should.eql([]); - mm(['a/b/c/d/e/z/d.md'], ['a/**/z/*.md']).should.eql(['a/b/c/d/e/z/d.md']); - - mm(['a/b/c/d/e/z/d.md'], ['a/**/j/**/z/*.md']).should.eql([]); - mm(['a/b/c/j/e/z/d.md'], ['a/**/j/**/z/*.md']).should.eql(['a/b/c/j/e/z/d.md']); - mm(['a/b/c/d/e/j/n/p/o/z/d.md'], ['a/**/j/**/z/*.md']).should.eql(['a/b/c/d/e/j/n/p/o/z/d.md']); - mm(['a/b/c/j/e/z/d.txt'], ['a/**/j/**/z/*.md']).should.eql([]); - - mm(['a/b/d/xyz.md'], ['a/b/**/c{d,e}/**/xyz.md']).should.eql([]); - mm(['a/b/c/xyz.md'], ['a/b/**/c{d,e}/**/xyz.md']).should.eql([]); - mm(['a/b/c/xyz.md'], ['a/b/**/c{d,e}/**/*.md']) - mm(['a/b/c/xyz.md'], ['a/b/**/c{d,e}/**/xyz.md']) - mm(['a/b/c/xyz.md'], ['a/b/**/c{d,e}/**/.*.md']) - mm(['a/b/d/cd/e/xyz.md'], ['a/b/**/c{d,e}/**/xyz.md']).should.eql(['a/b/d/cd/e/xyz.md']); - mm(['a/b/baz/ce/fez/xyz.md'], ['a/b/**/c{d,e}/**/xyz.md']).should.eql(['a/b/baz/ce/fez/xyz.md']); - }); - }); - - describe('negation', function() { - it('should create a regular expression for negating extensions:', function() { - mm(['.md'], ['!.md']).should.eql([]); - mm(['d.md'], ['!.md']).should.eql([]); - mm(['d.md'], ['*', '!.md']).should.eql(['d.md']); - mm(['d.md', 'c.txt'], ['*', '!.md']).should.eql(['d.md', 'c.txt']); - mm(['d.md', 'c.txt'], ['*', '!*.md']).should.eql(['c.txt']); - }); - - it('should negate files:', function() { - mm(['abc.md'], ['!*.md']).should.eql([]); - mm(['abc.md'], ['!**/*.md']).should.eql([]); - mm(['abc.txt'], ['*', '!*.md']).should.eql(['abc.txt']); - mm(['.dotfile.md'], ['!*.md']).should.eql([]); - mm(['.dotfile.txt'], ['.*', '!*.md']).should.eql(['.dotfile.txt']); - }); - - it('should match on full paths:', function() { - mm(['.gitignore'], ['a/b/c/*.md']).should.eql([]); - mm(['a/b/c/.gitignore'], ['a/b/c/*.md']).should.eql([]); - mm(['a/b/c/d.md'], ['a/b/c/*.md']).should.eql(['a/b/c/d.md']); - mm(['a/b/c/e.md'], ['a/b/c/*.md']).should.eql(['a/b/c/e.md']); - }); - - it('should expand braces:', function() { - mm(['iii.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/d/iii.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/c/iii.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/cd/iii.md'], ['a/b/c{d,e}/*.md']).should.eql(['a/b/cd/iii.md']); - mm(['a/b/ce/iii.md'], ['a/b/c{d,e}/*.md']).should.eql(['a/b/ce/iii.md']); - - mm(['xyz.md'], ['a/b/c{d,e}/xyz.md']).should.eql([]); - mm(['a/b/d/xyz.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/c/xyz.md'], ['a/b/c{d,e}/*.md']).should.eql([]); - mm(['a/b/cd/xyz.md'], ['a/b/c{d,e}/*.md']).should.eql(['a/b/cd/xyz.md']); - mm(['a/b/ce/xyz.md'], ['a/b/c{d,e}/*.md']).should.eql(['a/b/ce/xyz.md']); - mm(['a/b/cef/xyz.md'], ['a/b/c{d,e{f,g}}/*.md']).should.eql(['a/b/cef/xyz.md']); - mm(['a/b/ceg/xyz.md'], ['a/b/c{d,e{f,g}}/*.md']).should.eql(['a/b/ceg/xyz.md']); - mm(['a/b/cd/xyz.md'], ['a/b/c{d,e{f,g}}/*.md']).should.eql(['a/b/cd/xyz.md']); - }); - - it('should create a regular expression for double stars:', function() { - mm(['.gitignore'], ['a/**/z/*.md']).should.eql([]); - - mm(['a/b/z/.dotfile.md'], ['a/**/z/.*.md']).should.eql(['a/b/z/.dotfile.md']); - mm(['a/b/z/.dotfile'], ['a/**/z/*.md']).should.eql([]); - mm(['a/b/c/d/e/z/d.md'], ['a/**/z/*.md']).should.eql(['a/b/c/d/e/z/d.md']); - - mm(['a/b/c/d/e/z/d.md'], ['a/**/j/**/z/*.md']).should.eql([]); - mm(['a/b/c/j/e/z/d.md'], ['a/**/j/**/z/*.md']).should.eql(['a/b/c/j/e/z/d.md']); - mm(['a/b/c/d/e/j/n/p/o/z/d.md'], ['a/**/j/**/z/*.md']).should.eql(['a/b/c/d/e/j/n/p/o/z/d.md']); - mm(['a/b/c/j/e/z/d.txt'], ['a/**/j/**/z/*.md']).should.eql([]); - - mm(['a/b/d/xyz.md'], ['a/b/**/c{d,e}/**/xyz.md']).should.eql([]); - mm(['a/b/c/xyz.md'], ['a/b/**/c{d,e}/**/xyz.md']).should.eql([]); - mm(['a/b/d/cd/e/xyz.md'], ['a/b/**/c{d,e}/**/xyz.md']).should.eql(['a/b/d/cd/e/xyz.md']); - mm(['a/b/baz/ce/fez/xyz.md'], ['a/b/**/c{d,e}/**/xyz.md']).should.eql(['a/b/baz/ce/fez/xyz.md']); - }); - }); - - describe('options', function() { - it('should support the `matchBase` option:', function() { - mm(['a/b/c.md'], ['*.md']).should.eql([]); - mm(['a/b/c.md'], ['*.md'], {matchBase: true}).should.eql(['a/b/c.md']); - mm(['a/b.md', 'a/b.txt'], ['*.txt'], {matchBase: true}).should.eql(['a/b.txt']); - }); - - it('should support the `nocase` option:', function() { - mm(['a/b/d/e.md'], ['a/b/c/*.md']).should.eql([]); - mm(['a/b/c/e.md'], ['A/b/C/*.md']).should.eql([]); - mm(['a/b/c/e.md'], ['A/b/C/*.md'], {nocase: true}).should.eql(['a/b/c/e.md']); - mm(['a/b/c/e.md'], ['A/b/C/*.MD'], {nocase: true}).should.eql(['a/b/c/e.md']); - mm(['a/b/c.d/e.md'], ['A/b/C.d/*.MD'], {nocase: true}).should.eql(['a/b/c.d/e.md']); - }); - - it('should match dotfiles when `dotfile` is true:', function() { - var opts = { dot: true }; - - mm(['.gitignore'], ['.gitignore'], opts).should.eql(['.gitignore']); - mm(['d.md'], ['*.md'], opts).should.eql(['d.md']); - mm(['.verb.txt'], ['*.md'], opts).should.eql([]); - mm(['a/b/c/.gitignore'], ['*.md'], opts).should.eql([]); - mm(['a/b/c/.gitignore.md'], ['*.md'], opts).should.eql([]); - mm(['a/b/c/.gitignore.md'], ['**/*.md'], opts).should.eql(['a/b/c/.gitignore.md']); - mm(['.verb.txt'], ['*.md'], opts).should.eql([]); - mm(['.gitignore'], ['*.md'], opts).should.eql([]); - mm(['.gitignore'], ['*.*'], opts).should.eql(['.gitignore']); - mm(['.gitignore.md'], ['.*.md'], opts).should.eql(['.gitignore.md']); - mm(['.gitignore.md'], ['*.md'], opts).should.eql(['.gitignore.md']); - mm(['a/b/c/.verb.md'], ['**/*.md'], opts).should.eql(['a/b/c/.verb.md']); - - mm(['a/b/c/.gitignore.md'], ['*.md']).should.eql([]); - mm(['a/b/c/.gitignore.md'], ['**/.*.md']).should.eql(['a/b/c/.gitignore.md']); - mm(['a/b/c/.gitignore.md'], ['**/.*']).should.eql(['a/b/c/.gitignore.md']); - }); - }); -}); - diff --git a/test/minimatch/basic.js b/test/minimatch/basic.js index cdf15bff..b6a61f63 100644 --- a/test/minimatch/basic.js +++ b/test/minimatch/basic.js @@ -1,6 +1,6 @@ var path = require('path'); var should = require('should'); -var argv = require('minimist')(process.argv.slice(2)); +var argv = require('yargs-parser')(process.argv.slice(2)); var mm = require('../..'); if ('minimatch' in argv) { diff --git a/test/minimatch/defaults.js b/test/minimatch/defaults.js index 5faebf57..8c1a3f67 100644 --- a/test/minimatch/defaults.js +++ b/test/minimatch/defaults.js @@ -1,6 +1,6 @@ var path = require('path'); var should = require('should'); -var argv = require('minimist')(process.argv.slice(2)); +var argv = require('yargs-parser')(process.argv.slice(2)); var mm = require('../..'); if ('minimatch' in argv) { diff --git a/test/minimatch/temp.js b/test/minimatch/temp.js index 0a51e5be..407b8aef 100644 --- a/test/minimatch/temp.js +++ b/test/minimatch/temp.js @@ -1,6 +1,6 @@ var path = require('path'); var should = require('should'); -var argv = require('minimist')(process.argv.slice(2)); +var argv = require('yargs-parser')(process.argv.slice(2)); var mm = require('../..'); if ('minimatch' in argv) { diff --git a/test/negation.js b/test/negation.js index a9396c17..b2f9c1a0 100644 --- a/test/negation.js +++ b/test/negation.js @@ -1,66 +1,35 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - 'use strict'; -var path = require('path'); -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); +var assert = require('assert'); +var argv = require('yargs-parser')(process.argv.slice(2)); +var matcher = argv.mm ? require('minimatch') : require('..'); -if ('minimatch' in argv) { - mm = ref; +function match(arr, pattern, expected, options) { + var actual = matcher.match(arr, pattern, options); + assert.deepEqual(actual.sort(), expected.sort()); } -describe('negation patterns', function() { - describe('.match()', function() { - it('should create a regular expression for negating extensions:', function() { - mm.match(['.md'], '!.md').should.eql([]); - mm.match(['foo.md'], '!.md').should.eql(['foo.md']); - mm.match(['foo.md'], '!*.md').should.eql([]); - }); - - it('should negate files with extensions:', function() { - mm.match(['abc.md'], '!*.md').should.eql([]); - mm.match(['abc.txt'], '!*.md').should.eql(['abc.txt']); - mm.match(['a.js', 'b.md', 'c.txt'], '!**/*.md').should.eql(['a.js', 'c.txt']); - }); - - it('should negate dotfiles:', function() { - mm.match(['.dotfile.md'], '!*.md').should.eql(['.dotfile.md']); - mm.match(['.dotfile.txt'], '!*.md').should.eql(['.dotfile.txt']); - mm.match(['.gitignore', 'a', 'b'], '!.gitignore').should.eql(['a', 'b']); - }); - - it('should negate files in the immediate directory:', function() { - mm.match(['a/b.js', 'a.js', 'a/b.md', 'a.md'], '!*.md').should.eql(['a/b.js', 'a.js', 'a/b.md']); - }); - - it('should negate files in any directory:', function() { - mm.match(['a/b.js', 'a.js', 'a/b.md', 'a.md'], '!**/*.md').should.eql(['a/b.js', 'a.js']); - }); - - it('should create a regular expression for double stars:', function() { - mm.match(['.gitignore'], 'a/**/z/*.md').should.eql([]); +describe('negation', function() { + it('should negate files with extensions:', function() { + match(['.md'], '!.md', []); + match(['a.js', 'b.md', 'c.txt'], '!**/*.md', ['a.js', 'b.md', 'c.txt']); + match(['a.js', 'b.md', 'c.txt'], '!*.md', ['a.js', 'c.txt']); + match(['abc.md', 'abc.txt'], '!*.md', ['abc.txt']); + match(['foo.md'], '!*.md', []); + match(['foo.md'], '!.md', ['foo.md']); + }); - mm.match(['a/b/z/.dotfile.md'], 'a/**/z/.*.md').should.eql(['a/b/z/.dotfile.md']); - mm.match(['a/b/z/.dotfile'], 'a/**/z/*.md').should.eql([]); - mm.match(['a/b/c/d/e/z/foo.md'], 'a/**/z/*.md').should.eql(['a/b/c/d/e/z/foo.md']); + it('should negate dotfiles:', function() { + match(['.dotfile.md'], '!*.md', ['.dotfile.md']); + match(['.dotfile.txt'], '!*.md', ['.dotfile.txt']); + match(['.gitignore', 'a', 'b'], '!.gitignore', ['a', 'b']); + }); - mm.match(['a/b/c/d/e/z/foo.md'], 'a/**/j/**/z/*.md').should.eql([]); - mm.match(['a/b/c/j/e/z/foo.md'], 'a/**/j/**/z/*.md').should.eql(['a/b/c/j/e/z/foo.md']); - mm.match(['a/b/c/d/e/j/n/p/o/z/foo.md'], 'a/**/j/**/z/*.md').should.eql(['a/b/c/d/e/j/n/p/o/z/foo.md']); - mm.match(['a/b/c/j/e/z/foo.txt'], 'a/**/j/**/z/*.md').should.eql([]); + it('should negate files in the immediate directory:', function() { + match(['a/b.js', 'a.js', 'a/b.md', 'a.md'], '!*.md', ['a/b.js', 'a.js', 'a/b.md']); + }); - mm.match(['a/b/d/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm.match(['a/b/c/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm.match(['a/b/foo/cd/bar/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql(['a/b/foo/cd/bar/xyz.md']); - mm.match(['a/b/baz/ce/fez/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql(['a/b/baz/ce/fez/xyz.md']); - }); + it('should negate files in any directory:', function() { + match(['a/b.js', 'a.js', 'a/b.md', 'a.md'], '!**/*.md', ['a/b.js', 'a.md', 'a.js']); }); }); diff --git a/test/options.js b/test/options.js deleted file mode 100644 index 4a4b179c..00000000 --- a/test/options.js +++ /dev/null @@ -1,158 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -var path = require('path'); -require('should'); -var argv = require('minimist')(process.argv.slice(2)); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = require('minimatch'); -} - -describe('options.flags', function() { - it('should support the `flags` option:', function() { - mm.match(['a/b/d/e.md'], 'a/b/D/*.md').should.eql([], 'should not match a dirname'); - mm.match(['a/b/d/e.md'], 'a/b/D/*.md', {flags: 'i'}).should.eql(['a/b/d/e.md']); - mm.match(['a/b/c/e.md'], 'A/b/*/E.md').should.eql([], 'should not match a basename'); - mm.match(['a/b/c/e.md'], 'A/b/*/E.md', {flags: 'i'}).should.eql(['a/b/c/e.md']); - mm.match(['a/b/c/e.md'], 'A/b/C/*.MD').should.eql([], 'should not match a file extension'); - mm.match(['a/b/c/e.md'], 'A/b/C/*.MD', {flags: 'i'}).should.eql(['a/b/c/e.md']); - }); -}); - -describe('options.nocase', function() { - it('should support the `nocase` option:', function() { - mm.match(['a/b/d/e.md'], 'a/b/D/*.md').should.eql([], 'should not match a dirname'); - mm.match(['a/b/d/e.md'], 'a/b/D/*.md', {nocase: true}).should.eql(['a/b/d/e.md']); - mm.match(['a/b/c/e.md'], 'A/b/*/E.md').should.eql([], 'should not match a basename'); - mm.match(['a/b/c/e.md'], 'A/b/*/E.md', {nocase: true}).should.eql(['a/b/c/e.md']); - mm.match(['a/b/c/e.md'], 'A/b/C/*.MD').should.eql([], 'should not match a file extension'); - mm.match(['a/b/c/e.md'], 'A/b/C/*.MD', {nocase: true}).should.eql(['a/b/c/e.md']); - mm.match(['a/b/c/e.md'], 'A/b/C/E.MD').should.eql([], 'should not match a file extension'); - mm.match(['a/b/c/e.md'], 'A/b/C/E.MD', {nocase: true}).should.eql(['a/b/c/e.md']); - }); - - it('should use correct flags when `flags` and `nocase` are used (no double `i`):', function() { - var opts = {nocase: true, flags: 'i'}; - mm.match(['a/b/d/e.md'], 'a/b/D/*.md').should.eql([], 'should not match a dirname'); - mm.match(['a/b/d/e.md'], 'a/b/D/*.md', opts).should.eql(['a/b/d/e.md']); - mm.match(['a/b/c/e.md'], 'A/b/*/E.md').should.eql([], 'should not match a basename'); - mm.match(['a/b/c/e.md'], 'A/b/*/E.md', opts).should.eql(['a/b/c/e.md']); - mm.match(['a/b/c/e.md'], 'A/b/C/*.MD').should.eql([], 'should not match a file extension'); - mm.match(['a/b/c/e.md'], 'A/b/C/*.MD', opts).should.eql(['a/b/c/e.md']); - mm.match(['a/b/c/e.md'], 'A/b/C/E.MD').should.eql([], 'should not match a file extension'); - mm.match(['a/b/c/e.md'], 'A/b/C/E.MD', opts).should.eql(['a/b/c/e.md']); - }); -}); - -describe('options.ignore', function() { - it('should support the `ignore` option:', function() { - mm.match(['a/b', 'a/c', 'a/d', 'a/e'], '**').should.eql(['a/b', 'a/c', 'a/d', 'a/e'], 'nothing is ignored'); - mm.match(['a/b', 'a/c', 'a/d', 'a/e'], '**', {ignore: ['*/d', '*/e']}).should.eql(['a/b', 'a/c']); - mm.match(['a/b', 'a/c', 'a/d', 'a/e'], '**', {ignore: ['**']}).should.eql([]); - mm.match(['a/b', 'a/c', 'a/d', 'a/e'], '**', {ignore: ['**', '!*/d']}).should.eql(['a/d']); - }); -}); - -describe('options.matchBase', function() { - it('should support the `matchBase` option:', function() { - mm.match(['a/b/c/foo.md'], '*.md').should.eql([]); - mm.match(['a/b/c/foo.md'], '*.md', {matchBase: true}).should.eql(['a/b/c/foo.md']); - }); -}); - -describe('options.nodupes', function() { - it('should remove duplicate elements from the result array:', function() { - mm.match(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true}).should.eql(['abc', 'abc']); - mm.match(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true, nodupes: true}).should.eql(['abc']); - }); -}); - -describe('options.nobrace/nobraces', function() { - it('should not expect braces with `nobrace` is true:', function() { - mm.match(['1', '2', '3'], '{1..2}', {nobrace: true}).should.eql([]); - }); - - it('should not expect braces with `nobraces` is true:', function() { - mm.match(['1', '2', '3'], '{1..2}', {nobraces: true}).should.eql([]); - }); -}); - -describe('options.unescape', function() { - it('should remove backslashes in glob patterns:', function() { - mm.match(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c').should.eql(['\\a\\b\\c']); - mm.match(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true}).should.eql(['abc', 'abc']); - mm.match(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true, nodupes: true}).should.eql(['abc']); - }); -}); - -describe('options.dotfiles:', function() { - describe('when `dot` or `dotfile` is NOT true:', function() { - it('should not match dotfiles by default:', function() { - mm.match(['.dotfile'], '*').should.eql([]); - mm.match(['.dotfile'], '**').should.eql([]); - mm.match(['a/b/c/.dotfile.md'], '*.md').should.eql([]); - mm.match(['a/b', 'a/.b', '.a/b', '.a/.b'], '**').should.eql(['a/b']); - mm.match(['a/b/c/.dotfile'], '*.*').should.eql([]); - }); - - it('should match dotfiles when a leading dot is defined in the path:', function() { - mm.match(['a/b/c/.dotfile.md'], '**/.*').should.eql(['a/b/c/.dotfile.md']); - mm.match(['a/b/c/.dotfile.md'], '**/.*.md').should.eql(['a/b/c/.dotfile.md']); - }); - - it('should use negation patterns on dotfiles:', function() { - mm.match(['.a', '.b', 'c', 'c.md'], '!.*').should.eql(['c', 'c.md']); - mm.match(['.a', '.b', 'c', 'c.md'], '!.b').should.eql(['.a', 'c', 'c.md']); - }); - }); - - describe('when `dot` or `dotfile` is true:', function() { - it('should match dotfiles when there is a leading dot:', function() { - var opts = { dot: true }; - - mm.match(['.dotfile'], '*', opts).should.eql(['.dotfile']); - mm.match(['.dotfile'], '**', opts).should.eql(['.dotfile']); - mm.match(['a/b', 'a/.b', '.a/b', '.a/.b'], '**', opts).should.eql(['a/b', 'a/.b', '.a/b', '.a/.b']); - mm.match(['a/b', 'a/.b', 'a/.b', '.a/.b'], '{.*,**}', opts).should.eql(['a/b', 'a/.b', 'a/.b', '.a/.b']); - mm.match(['.dotfile'], '.dotfile', opts).should.eql(['.dotfile']); - mm.match(['.dotfile.md'], '.*.md', opts).should.eql(['.dotfile.md']); - }); - - it('should match dotfiles when there is not a leading dot:', function() { - var opts = { dot: true }; - mm.match(['.dotfile'], '*.*', opts).should.eql(['.dotfile']); - mm.match(['.a', '.b', 'c', 'c.md'], '*.*', opts).should.eql(['.a', '.b', 'c.md']); - mm.match(['.dotfile'], '*.md', opts).should.eql([]); - mm.match(['.verb.txt'], '*.md', opts).should.eql([]); - mm.match(['a/b/c/.dotfile'], '*.md', opts).should.eql([]); - mm.match(['a/b/c/.dotfile.md'], '*.md', opts).should.eql([]); - mm.match(['a/b/c/.verb.md'], '**/*.md', opts).should.eql(['a/b/c/.verb.md']); - mm.match(['foo.md'], '*.md', opts).should.eql(['foo.md']); - }); - - it('should match dotfiles when there is not a leading dot:', function() { - var opts = { dotfiles: true }; - mm.match(['.dotfile'], '*.*', opts).should.eql(['.dotfile']); - mm.match(['.a', '.b', 'c', 'c.md'], '*.*', opts).should.eql(['.a', '.b', 'c.md']); - mm.match(['.dotfile'], '*.md', opts).should.eql([]); - mm.match(['.verb.txt'], '*.md', opts).should.eql([]); - mm.match(['a/b/c/.dotfile'], '*.md', opts).should.eql([]); - mm.match(['a/b/c/.dotfile.md'], '*.md', opts).should.eql([]); - mm.match(['a/b/c/.verb.md'], '**/*.md', opts).should.eql(['a/b/c/.verb.md']); - mm.match(['foo.md'], '*.md', opts).should.eql(['foo.md']); - }); - - it('should use negation patterns on dotfiles:', function() { - mm.match(['.a', '.b', 'c', 'c.md'], '!*.*').should.eql(['.a', '.b', 'c']); - mm.match(['.a', '.b', 'c', 'c.md'], '!.*').should.eql(['c', 'c.md']); - }); - }); -}); diff --git a/test/pattern-string.js b/test/pattern-string.js deleted file mode 100644 index 5d7d5558..00000000 --- a/test/pattern-string.js +++ /dev/null @@ -1,245 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('should'); -var path = require('path'); -var argv = require('minimist')(process.argv.slice(2)); -var mm = require('..'); - -if ('multimatch' in argv || 'minimatch' in argv) { - mm = require('multimatch'); -} - -var files = ['a', 'b', 'c', 'd', 'a/a', 'a/b', 'a/b.js', 'a/c.js', 'a/b/c/d.js', '.a/.js', 'a/b/.js', 'a/b.md', 'a/b.txt'] - -describe('micromatch string patterns', function() { - it('should handle windows paths', function() { - mm(['a/b/c.md'], '**/*.md').should.eql(['a/b/c.md']); - mm(['E:/a/b/c.md'], 'E:/**/*.md').should.eql(['E:/a/b/c.md']); - }); - - it('should unixify file paths', function() { - if (path.sep === '\\') { - mm(['a\\b\\c.md'], '**/*.md').should.eql(['a/b/c.md']); - } - mm(['a\\b\\c.md'], '**/*.md', {unixify: true}).should.eql(['a/b/c.md']); - }); - - it('should unixify absolute paths', function() { - if (path.sep === '\\') { - mm(['E:\\a\\b\\c.md'], 'E:/**/*.md').should.eql(['E:/a/b/c.md']); - } - mm(['E:\\a\\b\\c.md'], 'E:/**/*.md', {unixify: true}).should.eql(['E:/a/b/c.md']); - }); - - it('should unixify patterns', function() { - if (path.sep === '\\') { - mm(['a\\b\\c.md'], '**\\*.md').should.eql(['a/b/c.md']); - mm(['E:\\a\\b\\c.md'], 'E:\\**\\*.md').should.eql(['E:/a/b/c.md']); - } - mm(['a\\b\\c.md'], '**\\*.md', {unixify: true}).should.eql(['a/b/c.md']); - mm(['E:\\a\\b\\c.md'], 'E:\\**\\*.md', {unixify: true}).should.eql(['E:/a/b/c.md']); - }); - - describe('file extensions:', function() { - it('should match extensions:', function() { - mm(['.md'], '.md').should.eql(['.md']); - mm(['.txt'], '.md').should.eql([]); - mm(['.dotfile'], '.md').should.eql([]); - }); - }); - - describe('common patterns:', function() { - it('should match directories:', function() { - mm(['a/'], 'a/*').should.eql([]); - mm(['a/'], 'a/').should.eql(['a/']); - }); - - it('should match files:', function() { - mm(files, 'a/*').should.eql(['a/a', 'a/b', 'a/b.js', 'a/c.js', 'a/b.md', 'a/b.txt']); - mm(files, 'a*').should.eql(['a']); - }); - }); - - describe('file names:', function() { - it('should match files with the given extension:', function() { - mm(['.md', '.txt'], '.md').should.eql(['.md']); - mm(['a.md', 'b.js', 'c.txt'], '*.{js,txt}').should.eql(['b.js', 'c.txt']); - mm(['.d.md'], '.*.md').should.eql(['.d.md']); - mm(['d.md'], '*.md').should.eql(['d.md']); - mm(['a/b/c/d.md'], '*.md').should.eql([]); - }); - - it('should match files with the given extension:', function() { - mm(['a.md', 'b.js', 'c.txt'], '!*.{js,txt}').should.eql(['a.md']); - mm(['a.md', 'a.min.js', 'b.js', 'c.txt'], '!*.{min.js,txt}').should.eql(['a.md', 'b.js']); - mm(['a.md', 'b.js', 'c.txt'], '!*.{js,txt}').should.eql(['a.md']); - mm(['a.md', 'b.js', 'c.txt', 'a/b.js', 'a/b.md'], '!{,**/}*.{js,txt}').should.eql(['a.md', 'a/b.md']); - mm(['a.md', 'b.js', 'c.txt', 'd.json'], ['*.*', '!*.{js,txt}']).should.eql(['a.md', 'd.json']); - }); - - it('should not match dotfiles, even if the dotfile name equals the extension:', function() { - mm(['.dotfile'], '*.md').should.eql([]); - mm(['.verb.txt'], '*.md').should.eql([]); - }); - }); - - describe('file paths:', function() { - it('should create a regular expression for file paths:', function() { - mm(['.dotfile'], 'a/b/c/*.md').should.eql([]); - mm(['.dotfile.md'], 'a/b/c/*.md').should.eql([]); - mm(['a/b/c/d.dotfile.md'], 'a/b/c/*.md').should.eql(['a/b/c/d.dotfile.md']); - mm(['a/b/d/.dotfile'], 'a/b/c/*.md').should.eql([]); - mm(['a/b/c/xyz.md'], 'a/b/c/*.md').should.eql(['a/b/c/xyz.md']); - mm(['a/b/c/.xyz.md'], 'a/b/c/.*.md').should.eql(['a/b/c/.xyz.md']); - mm(['a/bb/c/xyz.md'], 'a/*/c/*.md').should.eql(['a/bb/c/xyz.md']); - mm(['a/bbbb/c/xyz.md'], 'a/*/c/*.md').should.eql(['a/bbbb/c/xyz.md']); - mm(['a/bb.bb/c/xyz.md'], 'a/*/c/*.md').should.eql(['a/bb.bb/c/xyz.md']); - mm(['a/bb.bb/aa/bb/aa/c/xyz.md'], 'a/**/c/*.md').should.eql(['a/bb.bb/aa/bb/aa/c/xyz.md']); - mm(['a/bb.bb/aa/b.b/aa/c/xyz.md'], 'a/**/c/*.md').should.eql(['a/bb.bb/aa/b.b/aa/c/xyz.md']); - }); - }); - - describe('brace expansion:', function() { - it('should create a regular brace expansion:', function() { - mm(['iii.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/d/iii.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/c/iii.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/cd/iii.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/cd/iii.md']); - mm(['a/b/ce/iii.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/ce/iii.md']); - - mm(['xyz.md'], 'a/b/c{d,e}/xyz.md').should.eql([]); - mm(['a/b/d/xyz.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/c/xyz.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/cd/xyz.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/cd/xyz.md']); - mm(['a/b/ce/xyz.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/ce/xyz.md']); - mm(['a/b.js', 'a/c.js', 'a/d.js', 'a/e.js'], 'a/{c..e}.js').should.eql(['a/c.js', 'a/d.js', 'a/e.js']); - }); - }); - - describe('double stars:', function() { - it('should create a regular expression for double stars:', function() { - mm(['.dotfile'], 'a/**/z/*.md').should.eql([]); - mm(['a/b/z/.dotfile'], 'a/**/z/*.md').should.eql([]); - mm(['a/b/c/d/e/z/d.md'], 'a/**/z/*.md').should.eql(['a/b/c/d/e/z/d.md']); - - mm(['a/b/c/d/e/z/d.md'], 'a/**/j/**/z/*.md').should.eql([]); - mm(['a/b/c/j/e/z/d.md'], 'a/**/j/**/z/*.md').should.eql(['a/b/c/j/e/z/d.md']); - mm(['a/b/c/d/e/j/n/p/o/z/d.md'], 'a/**/j/**/z/*.md').should.eql(['a/b/c/d/e/j/n/p/o/z/d.md']); - mm(['a/b/c/j/e/z/d.txt'], 'a/**/j/**/z/*.md').should.eql([]); - - mm(['a/b/d/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm(['a/b/c/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm(['a/b/d/cd/e/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql(['a/b/d/cd/e/xyz.md']); - mm(['a/b/baz/ce/fez/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql(['a/b/baz/ce/fez/xyz.md']); - }); - }); - - describe('negation', function() { - it('should create a regular expression for negating extensions:', function() { - mm(['.md'], '!.md').should.eql([]); - mm(['d.md'], '!.md').should.eql(['d.md']); - mm(['d.md'], '!*.md').should.eql([]); - }); - - it('should be inclusive by default when the pattern is a string:', function() { - mm(['abc.md'], '!*.md').should.eql([]); - mm(['abc.md', 'abc.txt'], '!*.md').should.eql(['abc.txt']); - mm(['abc.txt'], '!*.md').should.eql(['abc.txt']); - }); - - it('should not be inclusive of dotfiles by default unless `dot: true` is set:', function() { - mm(['.dotfile.md'], '!*.md').should.eql(['.dotfile.md']); - mm(['.dotfile.md'], '!.*.md').should.eql([]); - mm(['.a.txt', '.a.md'], '!.*.md').should.eql(['.a.txt']); - }); - - it('should be exclusive by default when the pattern is an array:', function() { - mm(['abc.txt'], ['!*.md']).should.eql([]); - mm(['abc.txt'], ['*', '!*.md']).should.eql(['abc.txt']); - }); - - it('should match full paths:', function() { - mm(['.md'], 'a/b/*.md').should.eql([]); - mm(['a/b.md', 'a/c.txt'], 'a/*.md').should.eql(['a/b.md']); - mm(['a/b.md', 'a/c.txt'], 'a/*.txt').should.eql(['a/c.txt']); - mm(['a/b/.md'], 'a/b/*.md').should.eql([]); - mm(['a/b/a.md'], 'a/b/*.md').should.eql(['a/b/a.md']); - mm(['a/b/c/.dotfile'], 'a/b/c/*.md').should.eql([]); - mm(['a/b/c/d.md'], 'a/b/c/*.md').should.eql(['a/b/c/d.md']); - mm(['a/b/c/e.md'], 'a/b/c/*.md').should.eql(['a/b/c/e.md']); - }); - - it('should create a regex for brace expansion:', function() { - mm(['iii.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/d/iii.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/c/iii.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/cd/iii.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/cd/iii.md']); - mm(['a/b/ce/iii.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/ce/iii.md']); - - mm(['xyz.md'], 'a/b/c{d,e}/xyz.md').should.eql([]); - mm(['a/b/d/xyz.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/c/xyz.md'], 'a/b/c{d,e}/*.md').should.eql([]); - mm(['a/b/cd/xyz.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/cd/xyz.md']); - mm(['a/b/ce/xyz.md'], 'a/b/c{d,e}/*.md').should.eql(['a/b/ce/xyz.md']); - mm(['a/b/cef/xyz.md'], 'a/b/c{d,e{f,g}}/*.md').should.eql(['a/b/cef/xyz.md']); - mm(['a/b/ceg/xyz.md'], 'a/b/c{d,e{f,g}}/*.md').should.eql(['a/b/ceg/xyz.md']); - mm(['a/b/cd/xyz.md'], 'a/b/c{d,e{f,g}}/*.md').should.eql(['a/b/cd/xyz.md']); - }); - - it('should create a regular expression for double stars:', function() { - mm(['.dotfile'], 'a/**/z/*.md').should.eql([]); - - mm(['a/b/z/.dotfile.md'], 'a/**/z/.*.md').should.eql(['a/b/z/.dotfile.md']); - mm(['a/b/z/.dotfile'], 'a/**/z/*.md').should.eql([]); - mm(['a/b/c/d/e/z/d.md'], 'a/**/z/*.md').should.eql(['a/b/c/d/e/z/d.md']); - - mm(['a/b/c/d/e/z/d.md'], 'a/**/j/**/z/*.md').should.eql([]); - mm(['a/b/c/j/e/z/d.md'], 'a/**/j/**/z/*.md').should.eql(['a/b/c/j/e/z/d.md']); - mm(['a/b/c/d/e/j/n/p/o/z/d.md'], 'a/**/j/**/z/*.md').should.eql(['a/b/c/d/e/j/n/p/o/z/d.md']); - mm(['a/b/c/j/e/z/d.txt'], 'a/**/j/**/z/*.md').should.eql([]); - - mm(['a/b/d/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm(['a/b/c/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql([]); - mm(['a/b/d/cd/e/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql(['a/b/d/cd/e/xyz.md']); - mm(['a/b/baz/ce/fez/xyz.md'], 'a/b/**/c{d,e}/**/xyz.md').should.eql(['a/b/baz/ce/fez/xyz.md']); - }); - }); - - describe('options', function() { - it('should support the `matchBase` option:', function() { - mm(['a/b/c/d.md'], '*.md').should.eql([]); - mm(['a/b/c/d.md'], '*.md', {matchBase: true}).should.eql(['a/b/c/d.md']); - }); - - it('should support the `nocase` option:', function() { - mm(['a/b/d/e.md'], 'a/b/c/*.md').should.eql([]); - mm(['a/b/c/e.md'], 'A/b/C/*.md').should.eql([]); - mm(['a/b/c/e.md'], 'A/b/C/*.md', {nocase: true}).should.eql(['a/b/c/e.md']); - mm(['a/b/c/e.md'], 'A/b/C/*.MD', {nocase: true}).should.eql(['a/b/c/e.md']); - }); - - it('should match dotfiles when `dotfile` is true:', function() { - mm(['.dotfile'], '*.*', {dot: true}).should.eql(['.dotfile']); - mm(['.dotfile'], '*.md', {dot: true}).should.eql([]); - mm(['.dotfile'], '.dotfile', {dot: true}).should.eql(['.dotfile']); - mm(['.dotfile.md'], '.*.md', {dot: true}).should.eql(['.dotfile.md']); - mm(['.verb.txt'], '*.md', {dot: true}).should.eql([]); - mm(['.verb.txt'], '*.md', {dot: true}).should.eql([]); - mm(['a/b/c/.dotfile'], '*.md', {dot: true}).should.eql([]); - mm(['a/b/c/.dotfile.md'], '**/*.md', {dot: true}).should.eql(['a/b/c/.dotfile.md']); - mm(['a/b/c/.dotfile.md'], '**/.*').should.eql(['a/b/c/.dotfile.md']); - mm(['a/b/c/.dotfile.md'], '**/.*.md').should.eql(['a/b/c/.dotfile.md']); - mm(['a/b/c/.dotfile.md'], '*.md').should.eql([]); - mm(['a/b/c/.dotfile.md'], '*.md', {dot: true}).should.eql([]); - mm(['a/b/c/.verb.md'], '**/*.md', {dot: true}).should.eql(['a/b/c/.verb.md']); - mm(['d.md'], '*.md', {dot: true}).should.eql(['d.md']); - }); - }); -}); diff --git a/test/posix-brackets.js b/test/posix-brackets.js deleted file mode 100644 index 29226794..00000000 --- a/test/posix-brackets.js +++ /dev/null @@ -1,55 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('should'); -var path = require('path'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = ref; -} - -describe('POSIX bracket expressions', function() { - - it('character classes', function() { - // spec says this should match, I assume b/c the malformed backet pattern - // should be stripped completely from the pattern before performing the match - // mm.isMatch('ab', '[[:digit]ab]', {brackets: true}).should.be.true(); - mm.isMatch('A', '[[:lower:]]', {brackets: true}).should.be.false(); - mm.isMatch('A', '[![:lower:]]', {brackets: true}).should.be.true(); - mm.isMatch('a', '[![:lower:]]', {brackets: true}).should.be.false(); - mm.isMatch('a', '[[:lower:]]', {brackets: true}).should.be.true(); - mm.isMatch('a', '[[:upper:]]', {brackets: true}).should.be.false(); - mm.isMatch('A', '[[:upper:]]', {brackets: true}).should.be.true(); - mm.isMatch('a', '[[:digit:][:upper:][:space:]]', {brackets: true}).should.be.false(); - mm.isMatch('A', '[[:digit:][:upper:][:space:]]', {brackets: true}).should.be.true(); - mm.isMatch('1', '[[:digit:][:upper:][:space:]]', {brackets: true}).should.be.true(); - mm.isMatch(' ', '[[:digit:][:upper:][:space:]]', {brackets: true}).should.be.true(); - mm.isMatch('.', '[[:digit:][:upper:][:space:]]', {brackets: true}).should.be.false(); - mm.isMatch('5', '[[:xdigit:]]', {brackets: true}).should.be.true(); - mm.isMatch('f', '[[:xdigit:]]', {brackets: true}).should.be.true(); - mm.isMatch('D', '[[:xdigit:]]', {brackets: true}).should.be.true(); - mm.isMatch('.', '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]', {brackets: true}).should.be.true(); - mm.isMatch('.', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]', {brackets: true}).should.be.false(); - mm.isMatch('5', '[a-c[:digit:]x-z]', {brackets: true}).should.be.true(); - mm.isMatch('b', '[a-c[:digit:]x-z]', {brackets: true}).should.be.true(); - mm.isMatch('y', '[a-c[:digit:]x-z]', {brackets: true}).should.be.true(); - mm.isMatch('q', '[a-c[:digit:]x-z]', {brackets: true}).should.be.false(); - }); - - it('Case-sensitivy features (posix bracket expressions)', function() { - mm.isMatch('A', '[[:lower:]]', {brackets: true}).should.be.false(); - mm.isMatch('a', '[[:lower:]]', {brackets: true}).should.be.true(); - mm.isMatch('a', '[[:upper:]]', {brackets: true}).should.be.false(); - mm.isMatch('A', '[[:upper:]]', {brackets: true}).should.be.true(); - }); -}); - diff --git a/test/qmarks.js b/test/qmarks.js new file mode 100644 index 00000000..2bcb2ef8 --- /dev/null +++ b/test/qmarks.js @@ -0,0 +1,31 @@ +'use strict'; + +var assert = require('assert'); +var argv = require('yargs-parser')(process.argv.slice(2)); +var matcher = argv.mm ? require('minimatch') : require('..'); + +function match(arr, pattern, expected, options) { + var actual = matcher.match(arr, pattern, options); + assert.deepEqual(actual.sort(), expected.sort()); +} + +describe('qmarks and stars', function() { + it('should match with qmarks in globs:', function() { + match(['abc', 'abb', 'acc'], 'a***c', ['abc', 'acc']); + match(['abc'], 'a*****?c', ['abc']); + match(['abc', 'zzz', 'bbb'], '?*****??', ['abc', 'zzz', 'bbb']); + match(['abc', 'zzz', 'bbb'], '*****??', ['abc', 'zzz', 'bbb']); + match(['abc', 'abb', 'zzz'], '?*****?c', ['abc']); + match(['abc', 'bbb', 'zzz'], '?***?****c', ['abc']); + match(['abc', 'bbb', 'zzz'], '?***?****?', ['abc', 'bbb', 'zzz']); + match(['abc'], '?***?****', ['abc']); + match(['abc'], '*******c', ['abc']); + match(['abc'], '*******?', ['abc']); + match(['abcdecdhjk'], 'a*cd**?**??k', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a**?**cd**?**??k', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a**?**cd**?**??k***', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a**?**cd**?**??***k', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a**?**cd**?**??***k**', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a****c**?**??*****', ['abcdecdhjk']); + }); +}); diff --git a/test/reference/index.js b/test/reference/index.js new file mode 100644 index 00000000..23b2930d --- /dev/null +++ b/test/reference/index.js @@ -0,0 +1 @@ +module.exports = require('export-files')(__dirname); diff --git a/test/reference/matcher.js b/test/reference/matcher.js new file mode 100644 index 00000000..186202f0 --- /dev/null +++ b/test/reference/matcher.js @@ -0,0 +1,11 @@ +'use strict'; + +var argv = require('yargs-parser')(process.argv.slice(2)); +var mm = require('micromatch'); + +if ('mm' in argv) { + mm = require('minimatch'); + mm.minimatch = true; +} + +module.exports = mm; diff --git a/test/reference/negations.js b/test/reference/negations.js new file mode 100644 index 00000000..0371de1d --- /dev/null +++ b/test/reference/negations.js @@ -0,0 +1,107 @@ +'use strict'; + +/** + * minimatch "tricky negations test" + */ + +module.exports = { + options: { nonegate: true }, + cases: { + 'bar.min.js': { + '*.!(js|css)': true, + '!*.+(js|css)': false, + '*.+(js|css)': true + }, + + 'a-integration-test.js': { + '*.!(j)': true, + '!(*-integration-test.js)': false, + '*-!(integration-)test.js': true, + '*-!(integration)-test.js': false, + '*!(-integration)-test.js': true, + '*!(-integration-)test.js': true, + '*!(integration)-test.js': true, + '*!(integration-test).js': true, + '*-!(integration-test).js': true, + '*-!(integration-test.js)': true, + '*-!(integra)tion-test.js': false, + '*-integr!(ation)-test.js': false, + '*-integr!(ation-t)est.js': false, + '*-i!(ntegration-)test.js': false, + '*i!(ntegration-)test.js': true, + '*te!(gration-te)st.js': true, + '*-!(integration)?test.js': false, + '*?!(integration)?test.js': true + }, + + 'foo-integration-test.js': { + 'foo-integration-test.js': true, + '!(*-integration-test.js)': false + }, + + 'foo.jszzz.js': { + '*.!(js).js': true + }, + + 'asd.jss': { + '*.!(js)': true + }, + + 'asd.jss.xyz': { + '*.!(js).!(xy)': true + }, + + 'asd.jss.xy': { + '*.!(js).!(xy)': false + }, + + 'asd.js.xyz': { + '*.!(js).!(xy)': false + }, + + 'asd.js.xy': { + '*.!(js).!(xy)': false + }, + + 'asd.sjs.zxy': { + '*.!(js).!(xy)': true + }, + + 'asd..xyz': { + '*.!(js).!(xy)': true + }, + + 'asd..xy': { + '*.!(js).!(xy)': false, + '*.!(js|x).!(xy)': false + }, + + 'foo.js.js': { + '*.!(js)': false, // Bash 4.3 disagrees! + '*.!(js)*': false, // Bash 4.3 disagrees! + '*.!(js)+': false, + '*.!(js)*.!(js)': false, + }, + + 'testjson.json': { + '*(*.json|!(*.js))': true, + '+(*.json|!(*.js))': true, + '@(*.json|!(*.js))': true, + '?(*.json|!(*.js))': true + }, + + 'foojs.js': { + '*(*.json|!(*.js))': false, + '+(*.json|!(*.js))': false, + '@(*.json|!(*.js))': false, + '?(*.json|!(*.js))': false + }, + + 'other.bar': { + '*(*.json|!(*.js))': true, + '+(*.json|!(*.js))': true, + '@(*.json|!(*.js))': true, + '?(*.json|!(*.js))': true + } + } +}; diff --git a/test/regex.js b/test/regex.js deleted file mode 100644 index 14061346..00000000 --- a/test/regex.js +++ /dev/null @@ -1,31 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('should'); -var mm = require('..'); - -describe('regex matching', function() { - it('should support matching with regex', function() { - mm(['.'], /\./).should.eql(['.']); - mm(['ab'], /ab/).should.eql(['ab']); - mm(['ab', 'a'], /a$/).should.eql(['a']); - mm(['ab', 'a'], /\/a/).should.eql([]); - mm(['ab', 'a'], /aa/).should.eql([]); - mm(['/ab', '/a'], /\/a$/).should.eql(['/a']); - }); - - it('should support matching with regex', function() { - mm.match(['.'], /\./).should.eql(['.']); - mm.match(['ab'], /ab/).should.eql(['ab']); - mm.match(['ab', 'a'], /a$/).should.eql(['a']); - mm.match(['ab', 'a'], /\/a/).should.eql([]); - mm.match(['ab', 'a'], /aa/).should.eql([]); - mm.match(['/ab', '/a'], /\/a$/).should.eql(['/a']); - }); -}); diff --git a/test/special-chars.js b/test/special-chars.js deleted file mode 100644 index 78ab1fdf..00000000 --- a/test/special-chars.js +++ /dev/null @@ -1,81 +0,0 @@ -/*! - * micromatch - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -require('should'); -var path = require('path'); -var assert = require('assert'); -var argv = require('minimist')(process.argv.slice(2)); -var ref = require('./support/reference'); -var mm = require('..'); - -if ('minimatch' in argv) { - mm = ref.minimatch; -} - -describe('special characters', function() { - describe('$ dollar signs', function() { - it('should treat dollar signs as literal:', function() { - assert(mm.isMatch('$', '$')); - assert(mm.isMatch('$/foo', '$/*')); - assert(mm.isMatch('$/foo', '$/*')); - assert(mm.isMatch('$foo/foo', '$foo/*')); - assert(mm.isMatch('foo$/foo', 'foo$/*')); - }); - }); - - describe('?:', function() { - it('should match one character per question mark:', function() { - mm.match(['a/b/c.md'], 'a/?/c.md').should.eql(['a/b/c.md']); - mm.match(['a/bb/c.md'], 'a/?/c.md').should.eql([]); - mm.match(['a/bb/c.md'], 'a/??/c.md').should.eql(['a/bb/c.md']); - mm.match(['a/bbb/c.md'], 'a/??/c.md').should.eql([]); - mm.match(['a/bbb/c.md'], 'a/???/c.md').should.eql(['a/bbb/c.md']); - mm.match(['a/bbbb/c.md'], 'a/????/c.md').should.eql(['a/bbbb/c.md']); - }); - - it('should match multiple groups of question marks:', function() { - mm.match(['a/bb/c/dd/e.md'], 'a/?/c/?/e.md').should.eql([]); - mm.match(['a/b/c/d/e.md'], 'a/?/c/?/e.md').should.eql(['a/b/c/d/e.md']); - mm.match(['a/b/c/d/e.md'], 'a/?/c/???/e.md').should.eql([]); - mm.match(['a/b/c/zzz/e.md'], 'a/?/c/???/e.md').should.eql(['a/b/c/zzz/e.md']); - }); - - it('should use special characters and glob stars together:', function() { - mm.match(['a/b/c/d/e.md'], 'a/?/c/?/*/e.md').should.eql([]); - mm.match(['a/b/c/d/e/e.md'], 'a/?/c/?/*/e.md').should.eql(['a/b/c/d/e/e.md']); - mm.match(['a/b/c/d/efghijk/e.md'], 'a/?/c/?/*/e.md').should.eql(['a/b/c/d/efghijk/e.md']); - mm.match(['a/b/c/d/efghijk/e.md'], 'a/?/**/e.md').should.eql(['a/b/c/d/efghijk/e.md']); - mm.match(['a/bb/c/d/efghijk/e.md'], 'a/?/**/e.md').should.eql([]); - mm.match(['a/b/c/d/efghijk/e.md'], 'a/*/?/**/e.md').should.eql(['a/b/c/d/efghijk/e.md']); - mm.match(['a/b/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md').should.eql(['a/b/c/d/efgh.ijk/e.md']); - mm.match(['a/b.bb/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md').should.eql(['a/b.bb/c/d/efgh.ijk/e.md']); - mm.match(['a/bbb/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md').should.eql(['a/bbb/c/d/efgh.ijk/e.md']); - }); - }); - - describe('[ab] - brackets:', function() { - it('should support regex character classes:', function() { - mm.match(['a/b.md', 'a/c.md', 'a/d.md', 'a/E.md'], 'a/[A-Z].md').should.eql(['a/E.md']); - mm.match(['a/b.md', 'a/c.md', 'a/d.md'], 'a/[bd].md').should.eql(['a/b.md', 'a/d.md']); - mm.match(['a-1.md', 'a-2.md', 'a-3.md', 'a-4.md', 'a-5.md'], 'a-[2-4].md').should.eql(['a-2.md', 'a-3.md', 'a-4.md']); - mm.match(['a/b.md', 'b/b.md', 'c/b.md', 'b/c.md', 'a/d.md'], '[bc]/[bd].md').should.eql(['b/b.md', 'c/b.md']); - }); - }); - - describe('(a|b) - logical OR:', function() { - it('should support regex logical OR:', function() { - mm.match(['a/a', 'a/b', 'a/c', 'b/a', 'b/b'], '(a|b)/b').should.eql(['a/b', 'b/b']); - mm.match(['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'c/b'], '((a|b)|c)/b').should.eql(['a/b', 'b/b', 'c/b']); - mm.match(['a/b.md', 'a/c.md', 'a/d.md'], 'a/(b|d).md').should.eql(['a/b.md', 'a/d.md']); - mm.match(['a-1.md', 'a-2.md', 'a-3.md', 'a-4.md', 'a-5.md'], 'a-(2|3|4).md').should.eql(['a-2.md', 'a-3.md', 'a-4.md']); - mm.match(['a/b.md', 'b/b.md', 'c/b.md', 'b/c.md', 'a/d.md'], '(b|c)/(b|d).md').should.eql(['b/b.md', 'c/b.md']); - mm.match(['a/b.md', 'b/b.md', 'c/b.md', 'b/c.md', 'a/d.md'], '{b,c}/{b,d}.md').should.eql(['b/b.md', 'c/b.md']); - }); - }); -}); diff --git a/test/support/cc.sh b/test/support/cc.sh new file mode 100644 index 00000000..e051cadb --- /dev/null +++ b/test/support/cc.sh @@ -0,0 +1,35 @@ +# +# More ksh-like extended globbing tests, cribbed from zsh-3.1.5 +# +shopt -s extglob + +failed=0 +while read res str pat; do + [[ $res = '#' ]] && continue + [[ $str = ${pat} ]] + ts=$? + [[ $1 = -q ]] || echo "$ts: [[ $str = $pat ]]" + if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then + echo "Test failed: [[ $str = $pat ]]" + (( failed += 1 )) + fi +done <, - * which were extracted from the `github.com/git/git` repository - * Version used: http://git.io/xDZI - * @attribution - */ - -var mm = require('..'); -require('should'); - -describe('original wildmatch', function() { - it('Basic wildmat features', function() { - mm.isMatch('foo', 'foo').should.be.true(); - mm.isMatch('foo', 'bar').should.be.false(); - mm.isMatch('', '').should.be.true(); - mm.isMatch('foo', '???').should.be.true(); - mm.isMatch('foo', '??').should.be.false(); - mm.isMatch('foo', '*').should.be.true(); - mm.isMatch('foo', 'f*').should.be.true(); - mm.isMatch('foo', '*f').should.be.false(); - mm.isMatch('foo', '*foo*').should.be.true(); - mm.isMatch('foobar', '*ob*a*r*').should.be.true(); - mm.isMatch('aaaaaaabababab', '*ab').should.be.true(); - mm.isMatch('foo*', 'foo\\*', {unixify: false}).should.be.true(); - mm.isMatch('foobar', 'foo\\*bar').should.be.false(); - mm.isMatch('f\\oo', 'f\\oo').should.be.true(); - mm.isMatch('ball', '*[al]?').should.be.true(); - mm.isMatch('ten', '[ten]').should.be.false(); - // mm.isMatch('ten', '**[!te]').should.be.false(); - mm.isMatch('ten', '**[!ten]').should.be.false(); - mm.isMatch('ten', 't[a-g]n').should.be.true(); - mm.isMatch('ten', 't[!a-g]n').should.be.false(); - mm.isMatch('ton', 't[!a-g]n').should.be.true(); - mm.isMatch('ton', 't[^a-g]n').should.be.true(); - mm.isMatch('a]b', 'a[]]b').should.be.false(); - // mm.isMatch('a-b', 'a[]-]b').should.be.true(); - // mm.isMatch('a]b', 'a[]-]b').should.be.true(); - mm.isMatch('aab', 'a[]-]b').should.be.false(); - // mm.isMatch('aab', 'a[]a-]b').should.be.true(); - mm.isMatch(']', ']').should.be.true(); - mm.isMatch('3', '[1-3]').should.be.true(); - }); - - it('Various additional tests', function() { - mm.isMatch('acrt', 'a[c-c]st').should.be.false(); - mm.isMatch('acrt', 'a[c-c]rt').should.be.true(); - mm.isMatch(']', '[!]-]').should.be.false(); - // mm.isMatch('a', '[!]-]').should.be.true(); - mm.isMatch('', '\\', {unixify: false}).should.be.false(); - mm.isMatch('\\', '\\', {unixify: false}).should.be.true(); - mm.isMatch('XXX/\\', '\\', {unixify: false}).should.be.false(); - // mm.isMatch('XXX/\\', '*/\\\\', {unixify: false}).should.be.true(); - mm.isMatch('foo', 'foo').should.be.true(); - mm.isMatch('@foo', '@foo').should.be.true(); - mm.isMatch('foo', '@foo').should.be.false(); - mm.isMatch('[ab]', '\\[ab]', {unixify: false}).should.be.true(); - mm.isMatch('[ab]', '[[]ab]').should.be.false(); - // mm.isMatch('[ab]', '[[:]ab]').should.be.false(); - mm.isMatch('[ab]', '[[::]ab]').should.be.false(); - // mm.isMatch('[ab]', '[\\[:]ab]', {unixify: false}).should.be.false(); - mm.isMatch('[ab]', '[[:]ab]', {nobrackets: true}).should.be.true(); - mm.isMatch('[ab]', '[[::]ab]', {nobrackets: true}).should.be.true(); - mm.isMatch('[ab]', '[\\[:]ab]', {unixify: false, nobrackets: true}).should.be.true(); - mm.isMatch('[ab]', '[[::]ab]', {brackets: true}).should.be.false(); - // mm.isMatch('[ab]', '[\\[:]ab]', {unixify: false, brackets: true}).should.be.false(); - mm.isMatch('?a?b', '\\??\\?b', {unixify: false}).should.be.true(); - mm.isMatch('foo', '').should.be.false(); - mm.isMatch('foo/bar/baz/to', '**/t[o]').should.be.true(); - }); - - it('malformed wildmats:', function() { - mm.isMatch(']', '[\\\\-^]').should.be.false(); - mm.isMatch('[', '[\\\\-^]').should.be.false(); - mm.isMatch('-', '[\\-_]').should.be.true(); - // mm.isMatch(']', '[\\]]').should.be.true(); - mm.isMatch('\\]', '[\\]]').should.be.false(); - mm.isMatch('\\', '[\\]]').should.be.false(); - mm.isMatch('ab', 'a[]b').should.be.false(); - mm.isMatch('a[]b', 'a[]b').should.be.true(); - mm.isMatch('ab[', 'ab[').should.be.true(); - mm.isMatch('ab', '[!').should.be.false(); - mm.isMatch('ab', '[-').should.be.false(); - mm.isMatch('-', '[-]').should.be.true(); - mm.isMatch('-', '[a-').should.be.false(); - mm.isMatch('-', '[!a-').should.be.false(); - mm.isMatch('-', '[--A]').should.be.true(); - mm.isMatch('5', '[--A]').should.be.true(); - mm.isMatch(' ', '[ --]').should.be.true(); - mm.isMatch('$', '[ --]').should.be.true(); - mm.isMatch('-', '[ --]').should.be.true(); - mm.isMatch('0', '[ --]').should.be.false(); - mm.isMatch('-', '[---]').should.be.true(); - mm.isMatch('-', '[------]').should.be.true(); - mm.isMatch('j', '[a-e-n]').should.be.false(); - mm.isMatch('-', '[a-e-n]').should.be.true(); - // mm.isMatch('a', '[!------]').should.be.true(); - mm.isMatch('[', '[]-a]').should.be.false(); - mm.isMatch('^', '[]-a]').should.be.false(); - mm.isMatch('^', '[!]-a]').should.be.false(); - // mm.isMatch('[', '[!]-a]').should.be.true(); - mm.isMatch('^', '[a^bc]').should.be.true(); - // mm.isMatch('-b]', '[a-]b]').should.be.true(); - mm.isMatch('\\', '[\\]', {unixify: false}).should.be.false(); - mm.isMatch('\\', '[\\\\]', {unixify: false}).should.be.true(); - // mm.isMatch('\\', '[!\\\\]', {unixify: false}).should.be.false(); - mm.isMatch('G', '[A-\\\\]', {unixify: false}).should.be.true(); - mm.isMatch('aaabbb', 'b*a').should.be.false(); - mm.isMatch('aabcaa', '*ba*').should.be.false(); - mm.isMatch(',', '[,]').should.be.true(); - // mm.isMatch(',', '[\\\\,]').should.be.true(); - mm.isMatch('\\', '[\\\\,]', {unixify: false}).should.be.true(); - mm.isMatch('-', '[,-.]').should.be.true(); - mm.isMatch('+', '[,-.]').should.be.false(); - mm.isMatch('-.]', '[,-.]').should.be.false(); - // mm.isMatch('2', '[\\1-\\3]', {unixify: false}).should.be.true(); - // mm.isMatch('3', '[\\1-\\3]', {unixify: false}).should.be.true(); - mm.isMatch('4', '[\\1-\\3]', {unixify: false}).should.be.false(); - mm.isMatch('\\', '[[-\\]]', {unixify: false}).should.be.true(); - mm.isMatch('[', '[[-\\]]', {unixify: false}).should.be.true(); - mm.isMatch(']', '[[-\\]]', {unixify: false}).should.be.true(); - mm.isMatch('-', '[[-\\]]', {unixify: false}).should.be.false(); - }); - - it('Test recursion and the abort code', function() { - mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*').should.be.true(); - mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*').should.be.false(); - mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*').should.be.false(); - mm.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*', {unixify: false}).should.be.true(); - mm.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*').should.be.false(); - mm.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt', '**/*a*b*g*n*t').should.be.true(); - mm.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz', '**/*a*b*g*n*t').should.be.false(); - mm.isMatch('foo', '*/*/*').should.be.false(); - mm.isMatch('foo/bar', '*/*/*').should.be.false(); - mm.isMatch('foo/bba/arr', '*/*/*').should.be.true(); - mm.isMatch('foo/bb/aa/rr', '*/*/*').should.be.false(); - mm.isMatch('foo/bb/aa/rr', '**/**/**').should.be.true(); - mm.isMatch('abcXdefXghi', '*X*i').should.be.true(); - mm.isMatch('ab/cXd/efXg/hi', '*X*i').should.be.false(); - mm.isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i').should.be.true(); - mm.isMatch('ab/cXd/efXg/hi', '**/*X*/**/*i').should.be.true(); - }); - - it('Test pathName option', function() { - mm.isMatch('foo', 'foo').should.be.true(); - mm.isMatch('foo', 'fo').should.be.false(); - mm.isMatch('foo/bar', 'foo/bar').should.be.true(); - mm.isMatch('foo/bar', 'foo/*').should.be.true(); - mm.isMatch('foo/bba/arr', 'foo/*').should.be.false(); - mm.isMatch('foo/bba/arr', 'foo/**').should.be.true(); - mm.isMatch('foo/bba/arr', 'foo*').should.be.false(); - mm.isMatch('foo/bba/arr', 'foo**').should.be.false(); - mm.isMatch('foo/bba/arr', 'foo/*arr').should.be.false(); - mm.isMatch('foo/bba/arr', 'foo/**arr').should.be.true(); - mm.isMatch('foo/bba/arr', 'foo/*z').should.be.false(); - mm.isMatch('foo/bba/arr', 'foo/**z').should.be.false(); - mm.isMatch('foo/bar', 'foo?bar').should.be.false(); - mm.isMatch('foo/bar', 'foo[/]bar').should.be.true(); - mm.isMatch('foo', '*/*/*').should.be.false(); - mm.isMatch('foo/bar', '*/*/*').should.be.false(); - mm.isMatch('foo/bba/arr', '*/*/*').should.be.true(); - mm.isMatch('foo/bb/aa/rr', '*/*/*').should.be.false(); - mm.isMatch('abcXdefXghi', '*X*i').should.be.true(); - mm.isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i').should.be.true(); - mm.isMatch('ab/cXd/efXg/hi', '*Xg*i').should.be.false(); - }); - - it('Case-sensitivy features', function() { - mm.isMatch('a', '[A-Z]').should.be.false(); - mm.isMatch('A', '[a-z]').should.be.false(); - mm.isMatch('A', '[A-Z]').should.be.true(); - mm.isMatch('a', '[a-z]').should.be.true(); - mm.isMatch('A', '[B-a]').should.be.false(); - mm.isMatch('a', '[B-a]').should.be.true(); - mm.isMatch('A', '[B-Za]').should.be.false(); - mm.isMatch('a', '[B-Za]').should.be.true(); - mm.isMatch('z', '[Z-y]').should.be.false(); - mm.isMatch('Z', '[Z-y]').should.be.true(); - }); -}); diff --git a/test/utils.js b/test/utils.js deleted file mode 100644 index 91da8c9d..00000000 --- a/test/utils.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -require('should'); -var path = require('path'); -var assert = require('assert'); -var utils = require('../lib/utils'); -var mm = require('..'); - -describe('utils.hasPath', function() { - it('should return a function', function() { - assert.equal(typeof utils.hasPath('foo/bar'), 'function'); - }); - - it('should return true if the first path contains the second:', function() { - assert.equal(utils.hasPath('foo/bar')('foo'), true); - }); -}); - -describe('utils.matchPath', function() { - it('should return true if two paths are the same:', function() { - assert.equal(utils.matchPath('foo')('foo'), true); - }); - - it('should return true if the first path contains the second:', function() { - assert.equal(utils.matchPath('foo/bar', {contains: true})('foo'), true); - }); -}); - -describe('utils.unixify', function() { - it('should convert a path to unix slashes', function() { - var sep = path.sep; - path.sep = '\\'; - assert.equal(utils.unixify('foo\\bar'), 'foo/bar'); - path.sep = sep; - }); - - it('should return an empty string:', function() { - assert.equal(utils.unixify(''), ''); - }); - - it('should retain trailing slashes with unix paths:', function() { - assert.equal(utils.unixify('a/b/c/d/'), 'a/b/c/d/'); - }); - - it('should retain trailing slashes with windows paths:', function() { - var sep = path.sep; - path.sep = '\\'; - assert.equal(utils.unixify('a\\b\\c\\d\\'), 'a/b/c/d/'); - path.sep = sep; - }); - - it('should unescape word chars when `options.unescape` is true:', function() { - var fp = utils.unixify('foo\\bar\\baz\\quux', {unescape: true}); - assert.equal(fp, 'foobarbazquux'); - }); - - it('should not blow up on empty strings:', function() { - var fp = utils.unixify('', {unescape: true}); - assert.equal(fp, ''); - }); -}); - -describe('utils.escapePath', function() { - it('should escape dots and backslashes in a path', function() { - assert.equal(utils.escapePath('foo\\bar.baz'), 'foo\\\\bar\\.baz'); - }); -}); - -describe('utils.escapeRe', function() { - it('should escape regex characters in a path', function() { - assert.equal(utils.escapeRe('foo^bar*baz?#'), 'foo\\^bar\\*baz\\?\\#'); - }); -}); From ab1442ea4dd61e0e8ffe154488cc77520d9b9424 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Wed, 7 Sep 2016 02:27:23 -0400 Subject: [PATCH 03/68] clean up parsers/compilers --- lib/compilers.js | 20 ++------------------ lib/micromatch.js | 10 ++++------ lib/parsers.js | 8 ++------ 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/lib/compilers.js b/lib/compilers.js index 142b1efe..7ed4a437 100644 --- a/lib/compilers.js +++ b/lib/compilers.js @@ -5,23 +5,7 @@ var brackets = require('expand-brackets'); var extglob = require('extglob'); module.exports = function(micromatch) { - - /** - * Compiler plugins - */ - micromatch.use(nanomatch.compilers); - if (micromatch.options.brackets !== false) { - micromatch.use(brackets.compilers); - } - if (micromatch.options.extglob !== false) { - micromatch.use(extglob.compilers); - } - - /** - * Micromatch compilers - */ - - // micromatch.compiler - + micromatch.use(brackets.compilers); + micromatch.use(extglob.compilers); }; diff --git a/lib/micromatch.js b/lib/micromatch.js index 6f3808a2..ddda57e1 100644 --- a/lib/micromatch.js +++ b/lib/micromatch.js @@ -14,6 +14,10 @@ function Micromatch(options) { debug('initializing from <%s>', __filename); this.options = utils.extend({source: 'micromatch'}, options); this.snapdragon = this.options.snapdragon || new Snapdragon(this.options); + this.compiler = this.snapdragon.compiler; + this.parser = this.snapdragon.parser; + this.snapdragon.use(compilers); + this.snapdragon.use(parsers); /** * Override Snapdragon `.parse` method @@ -84,12 +88,6 @@ function Micromatch(options) { utils.define(this, 'toRegex', function() { return this.snapdragon.toRegex.apply(this.snapdragon, arguments); }); - - this.compiler = this.snapdragon.compiler; - this.parser = this.snapdragon.parser; - - compilers(this.snapdragon); - parsers(this.snapdragon); } /** diff --git a/lib/parsers.js b/lib/parsers.js index 9ee733f1..6dd56aa5 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -12,12 +12,8 @@ module.exports = function(micromatch) { */ micromatch.use(nanomatch.parsers); - if (micromatch.options.brackets !== false) { - micromatch.use(brackets.parsers); - } - if (micromatch.options.extglob !== false) { - micromatch.use(extglob.parsers); - } + micromatch.use(brackets.parsers); + micromatch.use(extglob.parsers); /** * Micromatch parsers From acd7648283cf9ca6fb40c1d6b3ff8cc9e0565d9a Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Sat, 8 Oct 2016 07:37:23 -0400 Subject: [PATCH 04/68] update examples --- examples/extglobs.js | 5 ++++- examples/negation.js | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 examples/negation.js diff --git a/examples/extglobs.js b/examples/extglobs.js index 2a6437f3..1e6dae09 100644 --- a/examples/extglobs.js +++ b/examples/extglobs.js @@ -1,4 +1,4 @@ -var mm = require('../'); +var mm = require('..'); console.log(mm.isMatch('src/a/b/c.js', 'src/**/*!(_test).js')); //=> true @@ -12,5 +12,8 @@ console.log(mm.isMatch('src/a/b/c_test.js', 'src/**/.!(_test).js')); console.log(mm.isMatch('src/a/b/c_test.js', 'src/**/.!(_test).js')); //=> false +console.log(mm('a**(z)')); +//=> false + // var arr = ['a.a', 'a.b', 'a.c.d', 'c.c', 'a.', 'd.d', 'e.e', 'f.f'] // console.log(mm(arr, '!(*.a|*.b|*.c)')); diff --git a/examples/negation.js b/examples/negation.js new file mode 100644 index 00000000..0017496c --- /dev/null +++ b/examples/negation.js @@ -0,0 +1,3 @@ +var mm = require('../'); + +console.log(mm('!**/a.js').ast); From ec0fc55103e3a90caa9e4c8f8142e103c573d71c Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 20 Oct 2016 17:35:57 -0400 Subject: [PATCH 05/68] run update --- .gitattributes | 2 +- .gitignore | 1 - .travis.yml | 11 +- benchmark/code/isMatch/micromatch.js | 7 + benchmark/code/isMatch/minimatch.js | 5 + benchmark/code/match/micromatch.js | 7 + benchmark/code/match/minimatch.js | 5 + benchmark/fixtures/isMatch/basename.js | 1 + benchmark/fixtures/{ => match}/basename.js | 0 benchmark/fixtures/match/braces-multiple.js | 167 ++++++++++++++++++ benchmark/fixtures/{ => match}/braces.js | 0 .../fixtures/match/globstar-small-list.js | 2 + benchmark/fixtures/{ => match}/immediate.js | 0 benchmark/fixtures/{ => match}/large.js | 0 benchmark/fixtures/{ => match}/long.js | 0 benchmark/fixtures/{ => match}/no-glob.js | 0 benchmark/fixtures/{ => match}/range.js | 0 benchmark/index.js | 20 ++- benchmark/package.json | 20 +++ package.json | 51 +++--- 20 files changed, 265 insertions(+), 34 deletions(-) create mode 100644 benchmark/code/isMatch/micromatch.js create mode 100644 benchmark/code/isMatch/minimatch.js create mode 100644 benchmark/code/match/micromatch.js create mode 100644 benchmark/code/match/minimatch.js create mode 100644 benchmark/fixtures/isMatch/basename.js rename benchmark/fixtures/{ => match}/basename.js (100%) create mode 100644 benchmark/fixtures/match/braces-multiple.js rename benchmark/fixtures/{ => match}/braces.js (100%) create mode 100644 benchmark/fixtures/match/globstar-small-list.js rename benchmark/fixtures/{ => match}/immediate.js (100%) rename benchmark/fixtures/{ => match}/large.js (100%) rename benchmark/fixtures/{ => match}/long.js (100%) rename benchmark/fixtures/{ => match}/no-glob.js (100%) rename benchmark/fixtures/{ => match}/range.js (100%) create mode 100644 benchmark/package.json diff --git a/.gitattributes b/.gitattributes index 4a3f1d3d..660957e7 100755 --- a/.gitattributes +++ b/.gitattributes @@ -7,4 +7,4 @@ *.jpg binary *.gif binary *.png binary -*.jpeg binary \ No newline at end of file +*.jpeg binary diff --git a/.gitignore b/.gitignore index 79881544..13bb9bac 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ npm-debug.log # misc _gh_pages -benchmark bower_components vendor temp diff --git a/.travis.yml b/.travis.yml index 3932eaa2..f28113ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,11 @@ sudo: false +os: + - linux + - osx language: node_js node_js: + - node - '6' - '5' - - '4' - '0.12' - '0.10' -matrix: - fast_finish: true - allow_failures: - - node_js: '4' - - node_js: '0.10' - - node_js: '0.12' diff --git a/benchmark/code/isMatch/micromatch.js b/benchmark/code/isMatch/micromatch.js new file mode 100644 index 00000000..34dc7463 --- /dev/null +++ b/benchmark/code/isMatch/micromatch.js @@ -0,0 +1,7 @@ +'use strict'; + +var micromatch = require('../../..'); + +module.exports = function(file, pattern) { + return micromatch.isMatch(file, pattern); +}; diff --git a/benchmark/code/isMatch/minimatch.js b/benchmark/code/isMatch/minimatch.js new file mode 100644 index 00000000..85bd523f --- /dev/null +++ b/benchmark/code/isMatch/minimatch.js @@ -0,0 +1,5 @@ +var minimatch = require('minimatch'); + +module.exports = function(file, pattern) { + return minimatch(file, pattern); +}; diff --git a/benchmark/code/match/micromatch.js b/benchmark/code/match/micromatch.js new file mode 100644 index 00000000..3375d935 --- /dev/null +++ b/benchmark/code/match/micromatch.js @@ -0,0 +1,7 @@ +'use strict'; + +var micromatch = require('../../..'); + +module.exports = function(files, pattern) { + return micromatch.match(files, pattern); +}; diff --git a/benchmark/code/match/minimatch.js b/benchmark/code/match/minimatch.js new file mode 100644 index 00000000..e7a5d6d7 --- /dev/null +++ b/benchmark/code/match/minimatch.js @@ -0,0 +1,5 @@ +var multimatch = require('multimatch'); + +module.exports = function(files, pattern) { + return multimatch(files, pattern); +}; diff --git a/benchmark/fixtures/isMatch/basename.js b/benchmark/fixtures/isMatch/basename.js new file mode 100644 index 00000000..dfa21c58 --- /dev/null +++ b/benchmark/fixtures/isMatch/basename.js @@ -0,0 +1 @@ +module.exports = ["abc.txt", "c*3.txt"]; \ No newline at end of file diff --git a/benchmark/fixtures/basename.js b/benchmark/fixtures/match/basename.js similarity index 100% rename from benchmark/fixtures/basename.js rename to benchmark/fixtures/match/basename.js diff --git a/benchmark/fixtures/match/braces-multiple.js b/benchmark/fixtures/match/braces-multiple.js new file mode 100644 index 00000000..0189a1bb --- /dev/null +++ b/benchmark/fixtures/match/braces-multiple.js @@ -0,0 +1,167 @@ +module.exports = [ + [ + "a/g-j.txt", + "b/g-j.txt", + "c/g-j.txt", + "a/h-j.txt", + "b/h-j.txt", + "c/h-j.txt", + "a/i-j.txt", + "b/i-j.txt", + "c/i-j.txt", + "a/g-k.txt", + "b/g-k.txt", + "c/g-k.txt", + "a/h-k.txt", + "b/h-k.txt", + "c/h-k.txt", + "a/i-k.txt", + "b/i-k.txt", + "c/i-k.txt", + "a/g-l.txt", + "b/g-l.txt", + "c/g-l.txt", + "a/h-l.txt", + "b/h-l.txt", + "c/h-l.txt", + "a/i-l.txt", + "b/i-l.txt", + "c/i-l.txt", + "a/g-j.js", + "b/g-j.js", + "c/g-j.js", + "a/h-j.js", + "b/h-j.js", + "c/h-j.js", + "a/i-j.js", + "b/i-j.js", + "c/i-j.js", + "a/g-k.js", + "b/g-k.js", + "c/g-k.js", + "a/h-k.js", + "b/h-k.js", + "c/h-k.js", + "a/i-k.js", + "b/i-k.js", + "c/i-k.js", + "a/g-l.js", + "b/g-l.js", + "c/g-l.js", + "a/h-l.js", + "b/h-l.js", + "c/h-l.js", + "a/i-l.js", + "b/i-l.js", + "c/i-l.js", + "a/g-j.md", + "b/g-j.md", + "c/g-j.md", + "a/h-j.md", + "b/h-j.md", + "c/h-j.md", + "a/i-j.md", + "b/i-j.md", + "c/i-j.md", + "a/g-k.md", + "b/g-k.md", + "c/g-k.md", + "a/h-k.md", + "b/h-k.md", + "c/h-k.md", + "a/i-k.md", + "b/i-k.md", + "c/i-k.md", + "a/g-l.md", + "b/g-l.md", + "c/g-l.md", + "a/h-l.md", + "b/h-l.md", + "c/h-l.md", + "a/i-l.md", + "b/i-l.md", + "c/i-l.md", + "a/g-j.hbs", + "b/g-j.hbs", + "c/g-j.hbs", + "a/h-j.hbs", + "b/h-j.hbs", + "c/h-j.hbs", + "a/i-j.hbs", + "b/i-j.hbs", + "c/i-j.hbs", + "a/g-k.hbs", + "b/g-k.hbs", + "c/g-k.hbs", + "a/h-k.hbs", + "b/h-k.hbs", + "c/h-k.hbs", + "a/i-k.hbs", + "b/i-k.hbs", + "c/i-k.hbs", + "a/g-l.hbs", + "b/g-l.hbs", + "c/g-l.hbs", + "a/h-l.hbs", + "b/h-l.hbs", + "c/h-l.hbs", + "a/i-l.hbs", + "b/i-l.hbs", + "c/i-l.hbs", + "a/g-j.json", + "b/g-j.json", + "c/g-j.json", + "a/h-j.json", + "b/h-j.json", + "c/h-j.json", + "a/i-j.json", + "b/i-j.json", + "c/i-j.json", + "a/g-k.json", + "b/g-k.json", + "c/g-k.json", + "a/h-k.json", + "b/h-k.json", + "c/h-k.json", + "a/i-k.json", + "b/i-k.json", + "c/i-k.json", + "a/g-l.json", + "b/g-l.json", + "c/g-l.json", + "a/h-l.json", + "b/h-l.json", + "c/h-l.json", + "a/i-l.json", + "b/i-l.json", + "c/i-l.json", + "a/g-j.coffee", + "b/g-j.coffee", + "c/g-j.coffee", + "a/h-j.coffee", + "b/h-j.coffee", + "c/h-j.coffee", + "a/i-j.coffee", + "b/i-j.coffee", + "c/i-j.coffee", + "a/g-k.coffee", + "b/g-k.coffee", + "c/g-k.coffee", + "a/h-k.coffee", + "b/h-k.coffee", + "c/h-k.coffee", + "a/i-k.coffee", + "b/i-k.coffee", + "c/i-k.coffee", + "a/g-l.coffee", + "b/g-l.coffee", + "c/g-l.coffee", + "a/h-l.coffee", + "b/h-l.coffee", + "c/h-l.coffee", + "a/i-l.coffee", + "b/i-l.coffee", + "c/i-l.coffee" + ], + "{a..z}/{a..z}-{a..z}.{txt,md,js}" +]; \ No newline at end of file diff --git a/benchmark/fixtures/braces.js b/benchmark/fixtures/match/braces.js similarity index 100% rename from benchmark/fixtures/braces.js rename to benchmark/fixtures/match/braces.js diff --git a/benchmark/fixtures/match/globstar-small-list.js b/benchmark/fixtures/match/globstar-small-list.js new file mode 100644 index 00000000..636e1871 --- /dev/null +++ b/benchmark/fixtures/match/globstar-small-list.js @@ -0,0 +1,2 @@ +var fixture = ['a/a/a', 'a/a/b', 'a/a/c', 'a/a/c', 'a/a/a/a/a/c', 'a/b/b', 'a/a/b/b/b/b/bb/c', 'a/c/c/s/z/c', 'a/b/c', 'a/c/c/b/c', 'z/a/a/z']; +module.exports = [fixture, 'a/**/c']; diff --git a/benchmark/fixtures/immediate.js b/benchmark/fixtures/match/immediate.js similarity index 100% rename from benchmark/fixtures/immediate.js rename to benchmark/fixtures/match/immediate.js diff --git a/benchmark/fixtures/large.js b/benchmark/fixtures/match/large.js similarity index 100% rename from benchmark/fixtures/large.js rename to benchmark/fixtures/match/large.js diff --git a/benchmark/fixtures/long.js b/benchmark/fixtures/match/long.js similarity index 100% rename from benchmark/fixtures/long.js rename to benchmark/fixtures/match/long.js diff --git a/benchmark/fixtures/no-glob.js b/benchmark/fixtures/match/no-glob.js similarity index 100% rename from benchmark/fixtures/no-glob.js rename to benchmark/fixtures/match/no-glob.js diff --git a/benchmark/fixtures/range.js b/benchmark/fixtures/match/range.js similarity index 100% rename from benchmark/fixtures/range.js rename to benchmark/fixtures/match/range.js diff --git a/benchmark/index.js b/benchmark/index.js index d52932ef..39e8d166 100755 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -4,9 +4,11 @@ var path = require('path'); var util = require('util'); var cyan = require('ansi-cyan'); var argv = require('yargs-parser')(process.argv.slice(2)); +var isPrimitive = require('is-primitive'); +var isObject = require('is-object'); var Suite = require('benchmarked'); -function run(type) { +function run(type, pattern) { var suite = new Suite({ cwd: __dirname, fixtures: path.join('fixtures', type, '*.js'), @@ -14,10 +16,22 @@ function run(type) { }); if (argv.dry) { + console.log(type); + console.log(); suite.dryRun(function(code, fixture) { console.log(cyan('%s > %s'), code.key, fixture.key); var args = require(fixture.path); - console.log(util.inspect(code.run(args), null, 10)); + var last = []; + if (args.length > 2) { + last = args.pop(); + } + var expected = util.inspect(last, {depth: null}); + var res = code.run.apply(null, args); + console.log(util.inspect(res, {depth: null})); + if (Array.isArray(res)) { + console.log(); + console.log(cyan(' total:'), res.length, 'items'); + } console.log(); }); } else { @@ -25,4 +39,4 @@ function run(type) { } } -run(argv._[0] || 'match'); +run(argv._[0] || 'match', argv._[1] || 'large*'); diff --git a/benchmark/package.json b/benchmark/package.json new file mode 100644 index 00000000..faac8343 --- /dev/null +++ b/benchmark/package.json @@ -0,0 +1,20 @@ +{ + "name": "extglob-benchmarks", + "version": "0.0.0", + "private": true, + "main": "index.js", + "scripts": { + "test": "mocha" + }, + "devDependencies": { + "ansi-cyan": "^0.1.1", + "benchmarked": "^0.2.2", + "braces": "^1.8.5", + "is-object": "^1.0.1", + "is-primitive": "^2.0.0", + "minimatch": "^3.0.0", + "multimatch": "^2.1.0", + "write": "^0.3.2", + "yargs-parser": "^3.2.0" + } +} diff --git a/package.json b/package.json index 9e1db4f6..2958824c 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,7 @@ "license": "MIT", "files": [ "index.js", - "lib", - "LICENSE", - "README.md" + "lib" ], "main": "index.js", "engines": { @@ -36,31 +34,40 @@ }, "dependencies": { "arr-diff": "^3.0.0", + "arr-union": "^3.1.0", "array-unique": "^0.3.2", + "bash-match": "^0.1.3", + "braces": "^2.0.1", "debug": "^2.2.0", "define-property": "^0.2.5", - "expand-brackets": "^0.1.4", + "expand-brackets": "^2.1.2", "extend-shallow": "^2.0.1", - "extglob": "^0.3.1", - "fill-array": "^1.0.0", - "is-glob": "^3.0.0", - "normalize-path": "^2.0.1", - "repeat-string": "^1.5.4" + "extglob": "^1.0.0", + "for-own": "^0.1.4", + "fragment-cache": "^0.2.0", + "is-glob": "^3.1.0", + "kind-of": "^3.0.4", + "nanomatch": "^0.2.1", + "object.pick": "^1.1.2", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "devDependencies": { - "ansi-cyan": "^0.1.1", - "cross-spawn": "^4.0.0", - "delete": "^0.3.2", + "cross-spawn": "^4.0.2", "export-files": "^2.1.1", - "gulp": "^3.9.0", - "gulp-eslint": "^1.1.1", - "gulp-format-md": "^0.1.8", - "gulp-istanbul": "^0.10.1", - "gulp-mocha": "^2.1.3", - "minimatch": "^3.0.0", - "mocha": "^2", - "should": "^8", - "yargs-parser": "^3.2.0" + "fs-exists-sync": "^0.1.0", + "gulp": "^3.9.1", + "gulp-eslint": "^3.0.1", + "gulp-format-md": "^0.1.11", + "gulp-istanbul": "^1.1.1", + "gulp-mocha": "^3.0.1", + "gulp-unused": "^0.2.0", + "minimatch": "^3.0.3", + "mocha": "^3.1.2", + "multimatch": "^2.1.0", + "should": "^11.1.1", + "yargs-parser": "^4.0.2" }, "keywords": [ "bash", @@ -124,4 +131,4 @@ "reflinks": true } } -} +} \ No newline at end of file From 1c31e62dc4b99bfc2949717be6463474a54be103 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 20 Oct 2016 17:37:44 -0400 Subject: [PATCH 06/68] refactor to use parsers/compilers from: - nanomatch - braces - extglob - expand-brackets --- index.js | 604 +++++++++++++++++--------- lib/cache.js | 1 + lib/compilers.js | 29 +- lib/micromatch.js | 110 ++--- lib/parsers.js | 76 +++- lib/utils.js | 238 ++++++---- test/actual/micro-dot-matchBase.js | 305 ------------- test/actual/micro-dot.js | 305 ------------- test/actual/micro-matchBase.js | 305 ------------- test/actual/micro-negate.js | 305 ------------- test/actual/micro.js | 305 ------------- test/actual/mini-dot-matchBase.js | 305 ------------- test/actual/mini-dot.js | 305 ------------- test/actual/mini-matchBase.js | 305 ------------- test/actual/mini-negate.js | 305 ------------- test/actual/mini.js | 305 ------------- test/any.js | 225 ---------- test/api.any.js | 239 ++++++++++ test/{contains.js => api.contains.js} | 170 ++++++-- test/api.isMatch.js | 317 ++++++++++++++ test/api.js | 153 +++++++ test/api.match.js | 69 +++ test/api.matchKeys.js | 40 ++ test/api.not.js | 121 ++++++ test/bash.js | 218 ++++++++++ test/bash/dotglob.txt | 23 + test/bash/glob.txt | 78 ++++ test/bash/globstar.txt | 30 ++ test/braces.js | 349 +++++++++++++++ test/brackets.js | 513 ++++++++++++---------- test/dotfiles.js | 156 ++++--- test/extglobs.js | 127 ++++-- test/fixtures/a/b/c/d/e/z.js | 0 test/fixtures/a/b/c/d/z.js | 0 test/fixtures/a/b/c/z.js | 0 test/fixtures/a/b/z.js | 0 test/fixtures/a/z.js | 0 test/fixtures/ax | 0 test/fixtures/b | 0 test/fixtures/dotglob.txt | 19 + test/fixtures/glob.txt | 81 ++++ test/fixtures/globstar.txt | 30 ++ test/fixtures/patterns.js | 268 ++++++++++++ test/fixtures/z.js | 0 test/globstars.js | 110 ++++- test/integration.js | 16 + test/isMatch.js | 251 ----------- test/issue-related.js | 70 ++- test/malicious.js | 30 ++ test/minimatch.js | 33 ++ test/minimatch/basic.js | 131 ------ test/minimatch/defaults.js | 125 ------ test/minimatch/temp.js | 132 ------ test/negation.js | 87 +++- test/options.js | 269 ++++++++++++ test/patterns.js | 270 ++++++++++++ test/qmarks.js | 61 ++- test/random.js | 33 ++ test/regex.ranges.js | 39 ++ test/special-chars.js | 97 +++++ test/stars.js | 84 ++++ test/support/bash.js | 52 +++ test/support/cc.sh | 35 -- test/support/compare.js | 5 + test/support/exists.js | 20 + test/support/match.js | 61 +++ test/support/matcher.js | 84 ++++ test/support/parse.js | 47 ++ test/support/refs.js | 29 ++ test/support/run.js | 39 -- test/support/spawn.js | 37 -- test/support/utils.js | 16 + 72 files changed, 4799 insertions(+), 4798 deletions(-) create mode 100644 lib/cache.js delete mode 100644 test/actual/micro-dot-matchBase.js delete mode 100644 test/actual/micro-dot.js delete mode 100644 test/actual/micro-matchBase.js delete mode 100644 test/actual/micro-negate.js delete mode 100644 test/actual/micro.js delete mode 100644 test/actual/mini-dot-matchBase.js delete mode 100644 test/actual/mini-dot.js delete mode 100644 test/actual/mini-matchBase.js delete mode 100644 test/actual/mini-negate.js delete mode 100644 test/actual/mini.js delete mode 100644 test/any.js create mode 100644 test/api.any.js rename test/{contains.js => api.contains.js} (56%) create mode 100644 test/api.isMatch.js create mode 100644 test/api.js create mode 100644 test/api.match.js create mode 100644 test/api.matchKeys.js create mode 100644 test/api.not.js create mode 100644 test/bash.js create mode 100644 test/bash/dotglob.txt create mode 100644 test/bash/glob.txt create mode 100644 test/bash/globstar.txt create mode 100644 test/braces.js delete mode 100644 test/fixtures/a/b/c/d/e/z.js delete mode 100644 test/fixtures/a/b/c/d/z.js delete mode 100644 test/fixtures/a/b/c/z.js delete mode 100644 test/fixtures/a/b/z.js delete mode 100644 test/fixtures/a/z.js delete mode 100644 test/fixtures/ax delete mode 100644 test/fixtures/b create mode 100644 test/fixtures/dotglob.txt create mode 100644 test/fixtures/glob.txt create mode 100644 test/fixtures/globstar.txt create mode 100644 test/fixtures/patterns.js delete mode 100644 test/fixtures/z.js create mode 100644 test/integration.js delete mode 100644 test/isMatch.js create mode 100644 test/malicious.js create mode 100644 test/minimatch.js delete mode 100644 test/minimatch/basic.js delete mode 100644 test/minimatch/defaults.js delete mode 100644 test/minimatch/temp.js create mode 100644 test/options.js create mode 100644 test/patterns.js create mode 100644 test/random.js create mode 100644 test/regex.ranges.js create mode 100644 test/special-chars.js create mode 100644 test/stars.js create mode 100644 test/support/bash.js delete mode 100644 test/support/cc.sh create mode 100644 test/support/compare.js create mode 100644 test/support/exists.js create mode 100644 test/support/match.js create mode 100644 test/support/matcher.js create mode 100644 test/support/parse.js create mode 100644 test/support/refs.js delete mode 100644 test/support/run.js delete mode 100644 test/support/spawn.js create mode 100644 test/support/utils.js diff --git a/index.js b/index.js index 51ce7a68..0d69d70b 100644 --- a/index.js +++ b/index.js @@ -1,168 +1,240 @@ 'use strict'; -var path = require('path'); -var util = require('util'); +/** + * Module dependencies + */ + +var braces = require('braces'); +var toRegex = require('to-regex'); var debug = require('debug')('micromatch'); +var extend = require('extend-shallow'); + +/** + * Local dependencies + */ + var Micromatch = require('./lib/micromatch'); var compilers = require('./lib/compilers'); var parsers = require('./lib/parsers'); +var cache = require('./lib/cache'); var utils = require('./lib/utils'); -var regexCache = {}; +var MAX_LENGTH = 1024 * 64; /** - * Convert the given glob `pattern` into a regex-compatible string. + * The main function takes a list of strings and one or more + * glob patterns to use for matching. * * ```js * var micromatch = require('micromatch'); - * var str = micromatch('*.js'); - * console.log(str); + * console.log(micromatch(['a.js', 'a.txt'], ['*.js'])); + * //=> [ 'a.js' ] * ``` - * @param {String} `str` + * @param {Array} `list` + * @param {String|Array} `patterns` Glob patterns * @param {Object} `options` - * @return {String} + * @return {Array} Returns an array of matches * @api public */ -function micromatch(str, options) { - var matcher = new Micromatch(options); - var ast = matcher.parse(str, options); - return matcher.compile(ast, options); +function micromatch(list, patterns, options) { + debug('micromatch <%s>', patterns); + + patterns = utils.arrayify(patterns); + list = utils.arrayify(list); + var len = patterns.length; + + if (list.length === 0 || len === 0) { + return []; + } + + if (len === 1) { + return micromatch.match(list, patterns[0], options); + } + + var negated = false; + var omit = []; + var keep = []; + var idx = -1; + + while (++idx < len) { + var pattern = patterns[idx]; + + if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) { + omit.push.apply(omit, micromatch.match(list, pattern.slice(1), options)); + negated = true; + } else { + keep.push.apply(keep, micromatch.match(list, pattern, options)); + } + } + + // minimatch.match parity + if (negated && keep.length === 0) { + keep = list.map(utils.unixify(options)); + } + + var matches = utils.diff(keep, omit); + if (!options || options.nodupes !== false) { + return utils.unique(matches); + } + + return matches; } /** - * Takes an array of strings and a glob pattern and returns a new - * array that contains only the strings that match the pattern. + * Cache + */ + +micromatch.cache = cache; +micromatch.clearCache = function() { + micromatch.cache.__data__ = {}; +}; + +/** + * Similar to the main function, but `pattern` must be a string. * * ```js - * var nano = require('micromatch'); - * console.log(nano.match(['a.a', 'a.b', 'a.c'], '*.!(*a)')); - * //=> ['a.b', 'a.c'] + * var micromatch = require('micromatch'); + * console.log(micromatch.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); + * //=> ['a.a', 'a.aa'] * ``` - * @param {Array} `arr` Array of strings to match + * @param {Array} `list` Array of strings to match * @param {String} `pattern` Glob pattern * @param {Object} `options` - * @return {Array} + * @return {Array} Returns an array of matches * @api public */ -micromatch.match = function(files, pattern, options) { - var opts = utils.extend({}, options); - var isMatch = micromatch.matcher(pattern, opts); - var unixify = utils.unixify(opts); - var matches = []; +micromatch.match = function(list, pattern, options) { + var unixify = utils.unixify(options); + var isMatch = micromatch.matcher(pattern, options); - files = utils.arrayify(files); - var len = files.length; + list = utils.arrayify(list); + var len = list.length; var idx = -1; + var matches = []; while (++idx < len) { - var file = unixify(files[idx]); - if (isMatch(file)) { - matches.push(file); + var ele = list[idx]; + + if (ele === pattern) { + matches.push(unixify(ele)); + continue; + } + + var unix = unixify(ele); + if (unix === pattern || isMatch(unix)) { + matches.push(unix); } } + // if no options were passed, uniquify results and return + if (typeof options === 'undefined') { + return utils.unique(matches); + } + if (matches.length === 0) { - if (opts.failglob === true) { + if (options.failglob === true) { throw new Error('no matches found for "' + pattern + '"'); } - if (opts.nonull === true || opts.nullglob === true) { - return [pattern.split('\\').join('')]; + if (options.nonull === true || options.nullglob === true) { + return [options.unescape ? utils.unescape(pattern) : pattern]; } } - // if `ignore` was defined, diff ignored files - if (opts.ignore) { - var ignore = utils.arrayify(opts.ignore); - delete opts.ignore; - var ignored = micromatch.matchEach(matches, ignore, opts); - matches = utils.diff(matches, ignored); + // if `opts.ignore` was defined, diff ignored list + if (options.ignore) { + matches = micromatch.not(matches, options.ignore, options); } - return opts.nodupes ? utils.unique(matches) : matches; + + return options.nodupes !== false ? utils.unique(matches) : matches; }; /** - * Takes an array of strings and a one or more glob patterns and returns a new - * array with strings that match any of the given patterns. + * Returns true if the specified `string` matches the given glob `pattern`. * * ```js - * var nano = require('micromatch'); - * console.log(nano.matchEach(['a.a', 'a.b', 'a.c'], ['*.!(*a)'])); - * //=> ['a.b', 'a.c'] + * var micromatch = require('micromatch'); + * console.log(micromatch.isMatch('a.a', '*.a')); + * //=> true + * console.log(micromatch.isMatch('a.b', '*.a')); + * //=> false * ``` - * @param {Array} `arr` Array of strings to match + * @param {String} `string` String to match * @param {String} `pattern` Glob pattern - * @param {Object} `options` - * @return {Array} + * @param {String} `options` + * @return {Boolean} Returns true if the string matches the glob pattern. * @api public */ -micromatch.matchEach = function(files, patterns, options) { - if (!Array.isArray(files)) { - return []; +micromatch.isMatch = function(str, pattern, options) { + if (pattern === str) { + return true; } - if (!Array.isArray(patterns)) { - return micromatch.match.apply(micromatch, arguments); + if (utils.isSimpleChar(pattern) || utils.isSlash(pattern)) { + return str === pattern; } - var opts = utils.extend({cache: true}, options); - var omit = []; - var keep = []; - - var len = patterns.length; - var idx = -1; - - while (++idx < len) { - var pattern = patterns[idx]; - if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) { - omit.push.apply(omit, micromatch.match(files, pattern.slice(1), opts)); - } else { - keep.push.apply(keep, micromatch.match(files, pattern, opts)); - } - } - return utils.diff(keep, omit); + return micromatch.matcher(pattern, options)(str); }; /** - * Returns true if a file path matches any of the - * given patterns. + * Returns a list of strings that do _not_ match any of the given `patterns`. * - * @param {String} `fp` The filepath to test. - * @param {String|Array} `patterns` Glob patterns to use. - * @param {Object} `opts` Options to pass to the `matcher()` function. - * @return {String} + * ```js + * var micromatch = require('micromatch'); + * console.log(micromatch.not(['a.a', 'b.b', 'c.c'], '*.a')); + * //=> ['b.b', 'c.c'] + * ``` + * @param {Array} `list` Array of strings to match. + * @param {String} `pattern` One or more glob patterns. + * @param {Object} `options` + * @return {Array} Returns an array of strings that do not match the given patterns. + * @api public */ -micromatch.any = function(filepath, patterns, options) { - if (!Array.isArray(patterns) && typeof patterns !== 'string') { - throw new TypeError('expected patterns to be a string or array'); - } +micromatch.not = function(list, patterns, options) { + var opts = extend({}, options); + var ignore = opts.ignore; + delete opts.ignore; var unixify = utils.unixify(opts); - var opts = utils.extend({}, options); + var unixified = list.map(function(fp) { + return unixify(fp, opts); + }); - patterns = utils.arrayify(patterns); - filepath = unixify(filepath); - var len = patterns.length; + var matches = utils.diff(unixified, micromatch(unixified, patterns, opts)); + if (ignore) { + matches = utils.diff(matches, micromatch(unixified, ignore)); + } - for (var i = 0; i < len; i++) { - var pattern = patterns[i]; - if (!utils.isString(pattern)) { - continue; - } + return opts.nodupes !== false ? utils.unique(matches) : matches; +}; - if (!utils.isGlob(pattern)) { - if (filepath === pattern) { - return true; - } - if (opts.contains && filepath.indexOf(pattern) !== -1) { - return true; - } - continue; - } +/** + * Returns true if the given `string` matches any of the given glob `patterns`. + * + * ```js + * var micromatch = require('micromatch'); + * console.log(micromatch.any('a.a', ['b.*', '*.a'])); + * //=> true + * console.log(micromatch.any('a.a', 'b.*')); + * //=> false + * ``` + * @param {String} `str` The string to test. + * @param {String|Array} `patterns` Glob patterns to use. + * @param {Object} `options` Options to pass to the `matcher()` function. + * @return {Boolean} Returns true if any patterns match `str` + * @api public + */ + +micromatch.any = function(str, patterns, options) { + var unixify = utils.unixify(options); + str = unixify(str); - if (micromatch.isMatch(filepath, pattern, opts)) { + patterns = utils.arrayify(patterns); + for (var i = 0; i < patterns.length; i++) { + if (micromatch.isMatch(str, patterns[i], options)) { return true; } } @@ -170,78 +242,81 @@ micromatch.any = function(filepath, patterns, options) { }; /** - * Returns true if the filepath matches the - * given pattern. + * Returns true if the given `string` contains the given pattern. Similar to `.isMatch` but + * the pattern can match any part of the string. + * + * ```js + * var micromatch = require('micromatch'); + * console.log(micromatch.contains('aa/bb/cc', '*b')); + * //=> true + * console.log(micromatch.contains('aa/bb/cc', '*d')); + * //=> false + * ``` + * @param {String} `str` The string to match. + * @param {String} `pattern` Glob pattern to use for matching. + * @param {Object} `options` + * @return {Boolean} Returns true if the patter matches any part of `str`. + * @api public */ -micromatch.contains = function(filepath, pattern, options) { - if (typeof filepath !== 'string') { - throw new TypeError('expected filepath to be a string'); +micromatch.contains = function(str, pattern, options) { + if (pattern === str) { + return true; } - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); + + if (utils.isSimpleChar(pattern)) { + return str === pattern; } - var opts = utils.extend({contains: pattern !== ''}, options); + var opts = extend({}, options, {contains: true}); opts.strictClose = false; opts.strictOpen = false; - if (opts.contains && !utils.isGlob(pattern)) { - filepath = utils.unixify(opts)(filepath); - return filepath.indexOf(pattern) !== -1; - } - return micromatch.matcher(pattern, opts)(filepath); + return micromatch(str, pattern, opts).length > 0; }; /** - * Returns true if the specified `string` matches the given - * glob `pattern`. + * Returns true if the given pattern and options should enable + * the `matchBase` option. + * @return {Boolean} + */ + +micromatch.matchBase = function(pattern, options) { + if (pattern && pattern.indexOf('/') !== -1 || !options) return false; + return options.basename === true || options.matchBase === true; +}; + +/** + * Filter the keys of the given object with the given `glob` pattern + * and `options`. Does not attempt to match nested keys. If you need this feature, + * use [glob-object][] instead. * * ```js - * var nano = require('micromatch'); - * - * console.log(nano.isMatch('a.a', '*.!(*a)')); - * //=> false - * console.log(nano.isMatch('a.b', '*.!(*a)')); - * //=> true + * var micromatch = require('micromatch'); + * var obj = { aa: 'a', ab: 'b', ac: 'c' }; + * console.log(micromatch.matchKeys(obj, '*b')); + * //=> { ab: 'b' } * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Glob pattern - * @param {String} `options` - * @return {Boolean} + * @param {Object} `object` + * @param {Array|String} `patterns` One or more glob patterns. + * @return {Object} Returns an object with only keys that match the given patterns. * @api public */ -micromatch.isMatch = function(filepath, pattern, options) { - if (pattern === '' || pattern === ' ') { - return filepath === pattern; +micromatch.matchKeys = function(obj, patterns, options) { + if (!utils.isObject(obj)) { + throw new TypeError('expected the first argument to be an object'); } - - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - var opts = utils.extend({}, options); - if (micromatch.matchBase(pattern, opts)) { - filepath = path.basename(filepath); - - } else if (opts.extname === true) { - filepath = path.extname(filepath); - - } else if (opts.dirname === true) { - filepath = path.dirname(filepath); - } - - var re = micromatch.makeRe(pattern, utils.extend({prepend: false}, opts)); - return re.test(filepath); + var keys = micromatch(Object.keys(obj), patterns, options); + return utils.pick(obj, keys); }; /** - * Takes a glob pattern and returns a matcher function. The returned - * function takes the string to match as its only argument. + * Creates a matcher function from the given glob `pattern` and `options`. The returned + * function takes a string to match as its only argument. * * ```js - * var nano = require('micromatch'); + * var micromatch = require('micromatch'); * var isMatch = micromatch.matcher('*.!(*a)'); * * console.log(isMatch('a.a')); @@ -251,117 +326,222 @@ micromatch.isMatch = function(filepath, pattern, options) { * ``` * @param {String} `pattern` Glob pattern * @param {String} `options` - * @return {Boolean} + * @return {Function} Returns a matcher function. * @api public */ micromatch.matcher = function(pattern, options) { - // pattern is a function - if (typeof pattern === 'function') { - return pattern; + function matcher() { + var unixify = utils.unixify(options); + + // if pattern is a regex + if (pattern instanceof RegExp) { + return function(str) { + return pattern.test(str) || pattern.test(unixify(str)); + }; + } + + // if pattern is invalid + if (!utils.isString(pattern)) { + throw new TypeError('expected pattern to be a string or regex'); + } + + // if pattern is a non-glob string + if (!utils.hasSpecialChars(pattern)) { + if (options && options.nocase === true) { + pattern = pattern.toLowerCase(); + } + return utils.matchPath(pattern, options); + } + + // if pattern is a glob string + var re = micromatch.makeRe(pattern, options); + + // if `options.matchBase` or `options.basename` is defined + if (micromatch.matchBase(pattern, options)) { + return utils.matchBasename(re, options); + } + + // everything else... + return function(str) { + return re.test(str) || re.test(unixify(str)); + }; } - var opts = utils.extend({}, options); - var unixify = utils.unixify(opts); + return memoize('matcher', pattern, options, matcher); +}; - // pattern is a regex +/** + * Create a regular expression from the given glob `pattern`. + * + * ```js + * var micromatch = require('micromatch'); + * console.log(micromatch.makeRe('*.js')); + * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ + * ``` + * @param {String} `pattern` The pattern to convert to regex. + * @param {Object} `options` + * @return {RegExp} Returns a regex created from the given pattern. + * @api public + */ + +micromatch.makeRe = function(pattern, options) { if (pattern instanceof RegExp) { - return function(fp) { - return pattern.test(unixify(fp)); - }; + return pattern; } if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string, regex or function'); + throw new TypeError('expected pattern to be a string'); } - // pattern is an empty string, only match an empty string. - if (pattern === '') { - return function(fp) { - return fp === pattern; - } + if (pattern.length > MAX_LENGTH) { + throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); } - // pattern is a glob string - var re = micromatch.makeRe(pattern, utils.extend({prepend: false}, opts)); + function makeRe() { + var opts = extend({strictErrors: false}, options); + if (opts.strictErrors === true) opts.strict = true; + + var patterns = micromatch.create(pattern, opts).map(function(obj) { + return obj.output; + }); + return toRegex(patterns.join('|'), opts); + } - // `matchBase` is defined - if (micromatch.matchBase(pattern, options)) { - return utils.matchBasename(re); + var regex = memoize('makeRe', pattern, options, makeRe); + if (regex.source.length > MAX_LENGTH) { + throw new SyntaxError('potentially malicious regex detected'); } - // `matchBase` is not defined - return function(fp) { - return re.test(unixify(fp)); - }; + return regex; }; /** - * Returns true if the given pattern and options should enable - * the `matchBase` option. - * @return {Boolean} + * Expand the given brace `pattern`. + * + * ```js + * var micromatch = require('micromatch'); + * console.log(micromatch.braces('foo/{a,b}/bar')); + * //=> ['foo/(a|b)/bar'] + * + * console.log(micromatch.braces('foo/{a,b}/bar', {expand: true})); + * //=> ['foo/(a|b)/bar'] + * ``` + * @param {String} pattern + * @param {Object} options + * @return {Array} + * @api public */ -micromatch.matchBase = function(pattern, options) { - if (pattern && pattern.indexOf('/') !== -1 || !options) return false; - return options.basename === true - || options.matchBase === true; +micromatch.braces = function(pattern, options) { + return memoize('braces', pattern, options, function() { + if (options && options.nobrace === true) { + return [pattern]; + } + if (!/\{.*\}/.test(pattern)) { + return [pattern]; + } + return braces(pattern, options); + }); }; /** - * Create a regular expression from the given string `pattern`. + * Parses the given glob `pattern` and returns an object with the compiled `output` + * and optional source `map`. * * ```js * var micromatch = require('micromatch'); - * var re = micromatch.makeRe('[[:alpha:]]'); - * console.log(re); - * //=> /^(?:[a-zA-Z])$/ + * console.log(micromatch.create('abc/*.js')); + * // { options: { source: 'string', sourcemap: true }, + * // state: {}, + * // compilers: + * // { ... }, + * // output: '(\\.[\\\\\\/])?abc\\/(?!\\.)(?=.)[^\\/]*?\\.js', + * // ast: + * // { type: 'root', + * // errors: [], + * // nodes: + * // [ ... ], + * // dot: false, + * // input: 'abc/*.js' }, + * // parsingErrors: [], + * // map: + * // { version: 3, + * // sources: [ 'string' ], + * // names: [], + * // mappings: 'AAAA,GAAG,EAAC,kBAAC,EAAC,EAAE', + * // sourcesContent: [ 'abc/*.js' ] }, + * // position: { line: 1, column: 28 }, + * // content: {}, + * // files: {}, + * // idx: 6 } * ``` - * @param {String} `pattern` The pattern to convert to regex. + * @param {String} `pattern` Glob pattern * @param {Object} `options` - * @return {RegExp} + * @return {Object} Returns an object with the parsed AST, compiled string and optional source map. * @api public */ -micromatch.makeRe = function(pattern, options) { - if (!pattern) return /$^/; - var key = pattern; - var regex; - - if (options) { - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - key += ';' + prop + '=' + String(options[prop]); +micromatch.create = function(pattern, options) { + return memoize('create', pattern, options, function() { + function compile(str, opts) { + var mm = new Micromatch(opts); + var ast = mm.parse(str, opts); + return mm.compile(ast, opts); + } + + if (pattern.slice(0, 2) === './') { + pattern = pattern.slice(2); + } + + pattern = utils.combineDuplicates(pattern, '\\*\\*\\/|\\/\\*\\*'); + pattern = micromatch.braces(pattern, options); + + if (Array.isArray(pattern)) { + var len = pattern.length; + var idx = -1; + var res = []; + + while (++idx < len) { + res.push(compile(pattern[idx], options)); } + return res; } - } - options = options || {}; - if (pattern.charAt(0) === '^') { - pattern = pattern.slice(1); - options.strictOpen = true; - } + return compile(pattern, options); + }); +}; - if (pattern[pattern.length - 1] === '$') { - pattern = pattern.slice(0, pattern.length -1); - options.strictClose = true; +/** + * Memoize a generated regex or function + */ + +function memoize(type, pattern, options, fn) { + var key = utils.createKey(type + pattern, options); + + if (cache.has(type, key)) { + return cache.get(type, key); } - if (options.cache !== false && regexCache.hasOwnProperty(key)) { - return regexCache[key]; + var val = fn(pattern, options); + if (options && options.cache === false) { + return val; } - var mm = new Micromatch(options); - regex = regexCache[key] = mm.makeRe(pattern, options); - return regex; -}; + cache.set(type, key, val); + return val; +} + +/** + * Expose parser, compiler and constructor on `micromatch` + */ + +micromatch.compilers = compilers; +micromatch.parsers = parsers; /** - * Expose `Micromatch` constructor + * Expose `micromatch` * @type {Function} */ module.exports = micromatch; -module.exports.Micromatch = Micromatch; -module.exports.compilers = compilers; -module.exports.parsers = parsers; diff --git a/lib/cache.js b/lib/cache.js new file mode 100644 index 00000000..fffc4c17 --- /dev/null +++ b/lib/cache.js @@ -0,0 +1 @@ +module.exports = new (require('fragment-cache'))(); diff --git a/lib/compilers.js b/lib/compilers.js index 7ed4a437..7ff4ae8e 100644 --- a/lib/compilers.js +++ b/lib/compilers.js @@ -1,11 +1,36 @@ 'use strict'; var nanomatch = require('nanomatch'); -var brackets = require('expand-brackets'); var extglob = require('extglob'); module.exports = function(micromatch) { + var compilers = micromatch.compiler.compilers; + + micromatch.state = micromatch.state || {}; micromatch.use(nanomatch.compilers); - micromatch.use(brackets.compilers); + + // store nanomatch compilers to override extglob compilers + var escape = compilers.escape; + var qmark = compilers.qmark; + var slash = compilers.slash; + var star = compilers.star; + var plus = compilers.plus; + var text = compilers.text; + var dot = compilers.dot; + micromatch.use(extglob.compilers); + micromatch.compiler + .set('dot', dot) + .set('escape', escape) + .set('plus', plus) + .set('slash', slash) + .set('qmark', qmark) + .set('star', star) + .set('text', text) + .set('eos', function(node) { + if (micromatch.state.metachar && this.output.slice(-3) !== '\\/?') { + this.output += '\\/?'; + } + return this.emit(node.val, node); + }) }; diff --git a/lib/micromatch.js b/lib/micromatch.js index ddda57e1..b0e68bcc 100644 --- a/lib/micromatch.js +++ b/lib/micromatch.js @@ -1,10 +1,20 @@ 'use strict'; +/** + * Module dependencies + */ + var debug = require('debug')('micromatch'); var Snapdragon = require('snapdragon'); +var define = require('define-property'); +var extend = require('extend-shallow'); + +/** + * Local dependencies + */ + var compilers = require('./compilers'); var parsers = require('./parsers'); -var utils = require('./utils'); /** * Customize Snapdragon parser and renderer @@ -12,83 +22,73 @@ var utils = require('./utils'); function Micromatch(options) { debug('initializing from <%s>', __filename); - this.options = utils.extend({source: 'micromatch'}, options); + this.options = extend({}, options); this.snapdragon = this.options.snapdragon || new Snapdragon(this.options); this.compiler = this.snapdragon.compiler; this.parser = this.snapdragon.parser; - this.snapdragon.use(compilers); - this.snapdragon.use(parsers); /** * Override Snapdragon `.parse` method */ - utils.define(this.snapdragon, 'parse', function(str, options) { + define(this.snapdragon, 'parse', function(str, options) { var parsed = Snapdragon.prototype.parse.apply(this, arguments); + parsed.input = str; - // escape ummatched brace/bracket/parens + // escape unmatched brace/bracket/parens var last = this.parser.stack.pop(); - if (last) { - var node = last.nodes[0]; - - if (last.type !== 'bracket') { - node.val = '\\' + node.val; - } - - var sibling = node.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; + if (last && this.options.strictErrors !== true) { + var open = last.nodes[0]; + var inner = last.nodes[1]; + if (last.type === 'bracket') { + if (inner.val.charAt(0) === '[') { + inner.val = '\\' + inner.val; + } + + } else { + open.val = '\\' + open.val; + var sibling = open.parent.nodes[1]; + if (sibling.type === 'star') { + sibling.loose = true; + } } } // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); + define(parsed, 'parser', this.parser); return parsed; }); +} - /** - * Decorate `.parse` method - */ - - utils.define(this, 'parse', function(ast, options) { - return this.snapdragon.parse.apply(this.snapdragon, arguments); - }); - - /** - * Decorate `.compile` method - */ +/** + * Initialize defaults + */ - utils.define(this, 'compile', function(ast, options) { - return this.snapdragon.compile.apply(this.snapdragon, arguments); - }); +Micromatch.prototype.init = function() { + if (!this.isInitialized) { + this.isInitialized = true; + compilers(this.snapdragon); + parsers(this.snapdragon); + } +}; - /** - * Create a regular expression from the given glob `pattern`. - * - * ```js - * var mm = require('micromatch'); - * var re = mm.makeRe('*.!(*a)'); - * console.log(re); - * //=> /^[^\/]*?\.(?![^\/]*?a)[^\/]*?$/ - * ``` - * @param {String} `pattern` The glob pattern to convert - * @param {Object} `options` - * @return {RegExp} - * @api public - */ +/** +* Decorate `.parse` method +*/ - utils.define(this, 'makeRe', function() { - return this.snapdragon.makeRe.apply(this.snapdragon, arguments); - }); +Micromatch.prototype.parse = function(ast, options) { + this.init(); + return this.snapdragon.parse.apply(this.snapdragon, arguments); +}; - /** - * Create a regex from the given `string` and `options` - */ +/** +* Decorate `.compile` method +*/ - utils.define(this, 'toRegex', function() { - return this.snapdragon.toRegex.apply(this.snapdragon, arguments); - }); -} +Micromatch.prototype.compile = function(ast, options) { + this.init(); + return this.snapdragon.compile.apply(this.snapdragon, arguments); +}; /** * Expose `Micromatch` diff --git a/lib/parsers.js b/lib/parsers.js index 6dd56aa5..056f9bc9 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -1,34 +1,76 @@ 'use strict'; -var nanomatch = require('nanomatch'); -var brackets = require('expand-brackets'); var extglob = require('extglob'); -var utils = require('./utils'); +var nanomatch = require('nanomatch'); +var regexNot = require('regex-not'); +var toRegex = require('to-regex'); -module.exports = function(micromatch) { +/** + * Characters to use in negation regex (we want to "not" match + * characters that are matched by other parsers) + */ + +var cached; +var patterns = [ + '[!@*?+]?\\(', + '\\)', + '\\[:?(?=.*?:?\\])', + ':?\\]', + '[*+?!^$.\\\\/]' +]; - /** - * Parser plugins - */ +var NOT_REGEX = '(' + patterns.join('|') + ')+'; +var not = textRegex(NOT_REGEX); + +module.exports = function(micromatch) { + var parsers = micromatch.parser.parsers; micromatch.use(nanomatch.parsers); - micromatch.use(brackets.parsers); + var escape = parsers.escape; + var slash = parsers.slash; + var qmark = parsers.qmark; + var plus = parsers.plus; + var star = parsers.star; + var dot = parsers.dot; + micromatch.use(extglob.parsers); + micromatch.parser + .use(function() { + this.notRegex = /^\!+(?!\()/; + }) + .capture('escape', escape) + .capture('slash', slash) + .capture('qmark', qmark) + .capture('star', star) + .capture('plus', plus) + .capture('dot', dot) - /** - * Micromatch parsers - */ + /** + * Text + */ - micromatch.parser - .capture('star', /^(?:\*(?![(])|[*]{3,})/) - .set('text', function() { + .capture('text', function() { + if (this.isInside('bracket')) return; var pos = this.position(); - var m = this.match(/^((?!(?:([!@*?+])?\(|[*.+?^\/\(\[\])\\]|\[\]\])).)*/); + var m = this.match(not); if (!m || !m[0]) return; + var val = m[0].replace(/([\[\]^$])/g, '\\$1'); return pos({ type: 'text', - val: m[0] + val: val }); - }) + }); }; + +/** + * Create text regex + */ + +function textRegex(pattern) { + if (cached) return cached; + var opts = {contains: true, strictClose: false}; + var not = regexNot.create(pattern, opts); + var re = toRegex('^(?:[\\^]|\\\\|' + not + ')', opts); + return (cached = re); +} diff --git a/lib/utils.js b/lib/utils.js index 4486ce37..c62194a4 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,44 +1,47 @@ 'use strict'; -var isWindows = process.platform === 'win32'; var path = require('path'); -var utils = module.exports; - -utils.fill = require('fill-array'); -utils.unique = require('array-unique'); -utils.define = require('define-property'); -utils.extend = require('extend-shallow'); -utils.repeat = require('repeat-string'); -utils.normalize = require('normalize-path'); -utils.isGlob = require('is-glob'); -utils.diff = require('arr-diff'); -var unixifyCache = {}; +var cache = {}; /** - * Create a negation regex from the given string - * @param {String} `str` - * @return {RegExp} + * Utils */ -utils.not = function(str) { - return '^((?!(?:' + str + ')).)*'; -}; - -utils.expand = function(str) { - var segs = str.split(',').filter(Boolean); - var arr = segs.slice(); +exports.define = require('define-property'); +exports.diff = require('arr-diff'); +exports.extend = require('extend-shallow'); +exports.isGlob = require('is-glob'); +exports.typeOf = require('kind-of'); +exports.pick = require('object.pick'); +exports.union = require('arr-union'); +exports.unique = require('array-unique'); - if (arr.length === 1) { - arr = str.split('..'); +/** + * Create the key to use for memoization. The key is generated + * by iterating over the options and concatenating key-value pairs + * to the pattern string. + */ - if (arr.length > 1) { - segs = utils.fill.apply(null, arr); +exports.createKey = function(pattern, options) { + var key = pattern; + if (typeof options === 'undefined') { + return key; + } + for (var prop in options) { + if (options.hasOwnProperty(prop)) { + key += ';' + prop + '=' + String(options[prop]); } } - return segs; + return key; }; -utils.arrayify = function(val) { +/** + * Cast `val` to an array + * @return {Array} + */ + +exports.arrayify = function(val) { + if (typeof val === 'string') return [val]; return val ? (Array.isArray(val) ? val : [val]) : []; }; @@ -46,36 +49,91 @@ utils.arrayify = function(val) { * Return true if `val` is a non-empty string */ -utils.isString = function(val) { - return val && typeof val === 'string'; +exports.isString = function(val) { + return typeof val === 'string'; }; /** - * Get the last element from `array` - * @param {Array} `array` - * @return {*} + * Return true if `val` is a non-empty string */ -utils.last = function(arr) { - return arr[arr.length - 1]; +exports.isRegex = function(val) { + return exports.typeOf(val) === 'regexp'; }; -utils.hasSpecialChars = function(str) { - return /(?:(^|\/)[!.]|[*?()\[\]{}]|[+@]\()/.test(str); +/** + * Return true if `val` is a non-empty string + */ + +exports.isObject = function(val) { + return exports.typeOf(val) === 'object'; }; /** - * Returns a function that returns true if the given - * regex matches the `filename` of a file path. + * Escape regex characters in the given string + */ + +exports.escapeRegex = function(str) { + return str.replace(/[\-\[\]{}()^$|\s*+?.\\\/]/g, '\\$&'); +}; + +/** + * Combines duplicate characters in the provided string. + * @param {String} `str` + * @returns {String} + */ + +exports.combineDuplicates = function(str, val) { + if (typeof val === 'string') { + var re = new RegExp('(' + val + ')(?=(?:' + val + ')*\\1)', 'g'); + return str.replace(re, ''); + } + return str.replace(/(.)(?=.*\1)/g, ''); +}; + +/** + * Returns true if the given `str` has special characters + */ + +exports.hasSpecialChars = function(str) { + return /(?:(^|\/)[!.]|[*?+()|\[\]{}]|[+@]\()/.test(str); +}; + +/** + * Strip backslashes from a string. * - * @param {RegExp} `re` Matching regex - * @return {Function} + * @param {String} `filepath` + * @return {String} */ -utils.matchBasename = function(re) { - return function(filepath) { - return re.test(filepath) || re.test(path.basename(filepath)); - }; +exports.unescape = function(str) { + return exports.normalize(str.replace(/\\(\W)/g, '$1')); +}; + +/** + * Normalize slashes in the given filepath. + * + * @param {String} `filepath` + * @return {String} + */ + +exports.normalize = function(filepath) { + return filepath.replace(/[\\\/]+(?=[\w._-])(?![*?+\\!])/g, '/'); +}; + +/** + * Returns true if `str` is a common character that doesn't need + * to be processed to be used for matching. + * @param {String} `str` + * @return {Boolean} + */ + +exports.isSimpleChar = function(str) { + return str === '' || str === ' ' || str === '.'; +}; + +exports.isSlash = function(str) { + return str === '/' || str === '\\' || str === '\\\\'; }; /** @@ -86,10 +144,10 @@ utils.matchBasename = function(re) { * @return {Function} */ -utils.matchPath = function(pattern, options) { +exports.matchPath = function(pattern, options) { return (options && options.contains) - ? utils.containsPath(pattern, options) - : utils.equalsPath(pattern, options); + ? exports.containsPattern(pattern, options) + : exports.equalsPattern(pattern, options); }; /** @@ -100,14 +158,14 @@ utils.matchPath = function(pattern, options) { * @return {Function} */ -utils.equalsPath = function(pattern, options) { - options = options || {}; +exports.equalsPattern = function(pattern, options) { + var unixify = exports.unixify(options); + return function(filepath) { - if (options.nocase === true) { - return pattern.toLowerCase() === filepath.toLowerCase(); - } else { - return pattern === filepath; + if (options && options.nocase === true) { + filepath = filepath.toLowerCase(); } + return pattern === filepath || pattern === unixify(filepath); }; }; @@ -119,23 +177,47 @@ utils.equalsPath = function(pattern, options) { * @return {Function} */ -utils.containsPath = function(pattern) { +exports.containsPattern = function(pattern, options) { + var unixify = exports.unixify(options); + return function(filepath) { + if (options && options.nocase === true) { + return unixify(filepath.toLowerCase()).indexOf(pattern) !== -1; + } else { + return unixify(filepath).indexOf(pattern) !== -1; + } + }; +}; + +/** + * Returns a function that returns true if the given + * regex matches the `filename` of a file path. + * + * @param {RegExp} `re` Matching regex + * @return {Function} + */ + +exports.matchBasename = function(re) { return function(filepath) { - return pattern.indexOf(filepath) !== -1; + return re.test(filepath) || re.test(path.basename(filepath)); }; }; -utils.stripPrefix = function(filepath, options) { - var opts = utils.extend({}, options); - if (opts.normalize !== true) { - return filepath; +/** + * Strip the prefix from a filepath + * @param {String} `filepath` + * @return {String} + */ + +exports.stripPrefix = function(fp) { + if (typeof fp !== 'string') { + return fp; } - filepath = String(filepath || ''); - if (filepath.slice(0, 2) === './') { - return filepath.slice(2); + if (fp.charAt(0) === '.' && (fp.charAt(1) === '/' || fp.charAt(1) === '\\')) { + return fp.slice(2); } - return filepath; + + return fp; }; /** @@ -143,25 +225,31 @@ utils.stripPrefix = function(filepath, options) { * forward slashes. */ -utils.unixify = function(options) { - var opts = utils.extend({}, options); - var unixify; +exports.unixify = function(options) { + var key = exports.createKey('unixify', options); - if (path.sep !== '/' || opts.unixify === true) { - unixify = function(filepath) { - return utils.normalize(utils.stripPrefix(filepath, opts), false); - }; + if (cache.hasOwnProperty(key) && path.sep === '/') { + return cache[key]; + } + + var opts = exports.extend({}, options); - } else if (opts.unescape === true) { + var unixify = function(filepath) { + return exports.stripPrefix(filepath); + }; + + if (path.sep !== '/' || opts.unixify === true || opts.normalize === true) { unixify = function(filepath) { - return utils.stripPrefix(filepath, opts).replace(/\\([-.\w])/g, '$1'); + return exports.stripPrefix(exports.normalize(filepath)); }; + } - } else { + if (opts.unescape === true) { unixify = function(filepath) { - return utils.stripPrefix(filepath, opts); + return exports.stripPrefix(exports.normalize(exports.unescape(filepath))); }; } + cache[key] = unixify; return unixify; }; diff --git a/test/actual/micro-dot-matchBase.js b/test/actual/micro-dot-matchBase.js deleted file mode 100644 index 6cc8f578..00000000 --- a/test/actual/micro-dot-matchBase.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("**/a/*/b/c/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b\/c\/\.js)$/); - -var actual = fn("**/a/*/b/c.d/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b\/c\.d\/\.js)$/); - -var actual = fn("**/*.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/*.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|gitignore))$/); - -var actual = fn("**/{a,/.gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(a|\/\.gitignore))$/); - -var actual = fn("**/{a..z..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(a|c|e|g|i|k|m|o|q|s|u|w|y)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{a..c}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[a-c]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[1-10]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(1|3|5|7|9)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[b-s]\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[01-10]\.js)$/); - -var actual = fn("a"); -actual.should.eql(/^(?:a)$/); - -var actual = fn("a/"); -actual.should.eql(/^(?:a\/)$/); - -var actual = fn("a/*"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?)$/); - -var actual = fn(".*"); -actual.should.eql(/^(?:(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/*.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("**/*."); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.)$/); - -var actual = fn("**/*.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.a)$/); - -var actual = fn("**/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\.js)$/); - -var actual = fn("**/.*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\.md)$/); - -var actual = fn("**/.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.a)$/); - -var actual = fn("**/.a.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.a\.js)$/); - -var actual = fn("**/.gitignore"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("*.*"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.a"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.a)$/); - -var actual = fn("*.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*.{gitignore,*}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(gitignore|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?))$/); - -var actual = fn("*.{*,gitignore,js}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore|js))$/); - -var actual = fn("*.{*,gitignore}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore))$/); - -var actual = fn(".{*,gitignore}"); -actual.should.eql(/^(?:.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/.(js|gitignore))$/); - -var actual = fn("**/.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/.(js|md))$/); - -var actual = fn("**/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(a|b)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[a-z]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("*.js"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("*.md"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("*.{js,txt}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|txt))$/); - -var actual = fn("*/*.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*/.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.gitignore)$/); - -var actual = fn(".a"); -actual.should.eql(/^(?:\.a)$/); - -var actual = fn(".gitignore"); -actual.should.eql(/^(?:\.gitignore)$/); - -var actual = fn(".js"); -actual.should.eql(/^(?:\.js)$/); - -var actual = fn(".md"); -actual.should.eql(/^(?:\.md)$/); - -var actual = fn("a/**/c/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/c/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/j/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/j\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/j/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/j\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.txt"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.txt)$/); - -var actual = fn("a/*/.b"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.b)$/); - -var actual = fn("a/*/.b.a"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.b\.a)$/); - -var actual = fn("a/*/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.js)$/); - -var actual = fn("a/*/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.md)$/); - -var actual = fn("a/*/b"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b)$/); - -var actual = fn("a/*/c/*.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*/c/*.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/.*/b"); -actual.should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - -var actual = fn("a/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.js)$/); - -var actual = fn("a/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.md)$/); - -var actual = fn("a/?/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\.js)$/); - -var actual = fn("a/?/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\.md)$/); - -var actual = fn("a/?/c/?/*/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/e\.js)$/); - -var actual = fn("a/?/c/?/*/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/e\.md)$/); - -var actual = fn("a/?/c/?/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/e\.js)$/); - -var actual = fn("a/?/c/?/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/e\.md)$/); - -var actual = fn("a/?/c/???/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]..\/e\.js)$/); - -var actual = fn("a/?/c/???/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]..\/e\.md)$/); - -var actual = fn("a/??/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/].\/c\.js)$/); - -var actual = fn("a/??/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/].\/c\.md)$/); - -var actual = fn("a/???/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]..\/c\.js)$/); - -var actual = fn("a/???/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]..\/c\.md)$/); - -var actual = fn("a/????/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]...\/c\.js)$/); - -var actual = fn("a/????/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]...\/c\.md)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c(d|e)\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.js)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c(d|e)\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.md)$/); - -var actual = fn("a/b/c/*.js"); -actual.should.eql(/^(?:a\/b\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("A/b/C/*.js"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c/*.md"); -actual.should.eql(/^(?:a\/b\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.md"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.MD"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.MD)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|a\/b\/ce(f|g)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md|a\/b\/ce(f|g)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/*.js"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e}/*.md"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/xyz\.js)$/); - -var actual = fn("a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/xyz\.md)$/); - -var actual = fn("a/{c..e}.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[c-e]\.js)$/); - -var actual = fn("E:**/*.js"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("E:**/*.md"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("E:\\**/*.js"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("E:\\**/*.md"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); diff --git a/test/actual/micro-dot.js b/test/actual/micro-dot.js deleted file mode 100644 index 6cc8f578..00000000 --- a/test/actual/micro-dot.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("**/a/*/b/c/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b\/c\/\.js)$/); - -var actual = fn("**/a/*/b/c.d/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b\/c\.d\/\.js)$/); - -var actual = fn("**/*.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/*.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|gitignore))$/); - -var actual = fn("**/{a,/.gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(a|\/\.gitignore))$/); - -var actual = fn("**/{a..z..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(a|c|e|g|i|k|m|o|q|s|u|w|y)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{a..c}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[a-c]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[1-10]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(1|3|5|7|9)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[b-s]\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[01-10]\.js)$/); - -var actual = fn("a"); -actual.should.eql(/^(?:a)$/); - -var actual = fn("a/"); -actual.should.eql(/^(?:a\/)$/); - -var actual = fn("a/*"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?)$/); - -var actual = fn(".*"); -actual.should.eql(/^(?:(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/*.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("**/*."); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.)$/); - -var actual = fn("**/*.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.a)$/); - -var actual = fn("**/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\.js)$/); - -var actual = fn("**/.*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\.md)$/); - -var actual = fn("**/.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.a)$/); - -var actual = fn("**/.a.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.a\.js)$/); - -var actual = fn("**/.gitignore"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("*.*"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.a"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.a)$/); - -var actual = fn("*.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*.{gitignore,*}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(gitignore|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?))$/); - -var actual = fn("*.{*,gitignore,js}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore|js))$/); - -var actual = fn("*.{*,gitignore}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore))$/); - -var actual = fn(".{*,gitignore}"); -actual.should.eql(/^(?:.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/.((?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/.(js|gitignore))$/); - -var actual = fn("**/.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/.(js|md))$/); - -var actual = fn("**/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(a|b)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[a-z]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("*.js"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("*.md"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("*.{js,txt}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.(js|txt))$/); - -var actual = fn("*/*.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*/.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.gitignore)$/); - -var actual = fn(".a"); -actual.should.eql(/^(?:\.a)$/); - -var actual = fn(".gitignore"); -actual.should.eql(/^(?:\.gitignore)$/); - -var actual = fn(".js"); -actual.should.eql(/^(?:\.js)$/); - -var actual = fn(".md"); -actual.should.eql(/^(?:\.md)$/); - -var actual = fn("a/**/c/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/c/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/j/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/j\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/j/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/j\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.txt"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.txt)$/); - -var actual = fn("a/*/.b"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.b)$/); - -var actual = fn("a/*/.b.a"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.b\.a)$/); - -var actual = fn("a/*/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.js)$/); - -var actual = fn("a/*/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.md)$/); - -var actual = fn("a/*/b"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b)$/); - -var actual = fn("a/*/c/*.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*/c/*.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/.*/b"); -actual.should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - -var actual = fn("a/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.js)$/); - -var actual = fn("a/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.md)$/); - -var actual = fn("a/?/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\.js)$/); - -var actual = fn("a/?/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\.md)$/); - -var actual = fn("a/?/c/?/*/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/e\.js)$/); - -var actual = fn("a/?/c/?/*/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/e\.md)$/); - -var actual = fn("a/?/c/?/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/e\.js)$/); - -var actual = fn("a/?/c/?/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/e\.md)$/); - -var actual = fn("a/?/c/???/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]..\/e\.js)$/); - -var actual = fn("a/?/c/???/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]..\/e\.md)$/); - -var actual = fn("a/??/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/].\/c\.js)$/); - -var actual = fn("a/??/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/].\/c\.md)$/); - -var actual = fn("a/???/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]..\/c\.js)$/); - -var actual = fn("a/???/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]..\/c\.md)$/); - -var actual = fn("a/????/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]...\/c\.js)$/); - -var actual = fn("a/????/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]...\/c\.md)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c(d|e)\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.js)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c(d|e)\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.md)$/); - -var actual = fn("a/b/c/*.js"); -actual.should.eql(/^(?:a\/b\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("A/b/C/*.js"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c/*.md"); -actual.should.eql(/^(?:a\/b\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.md"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.MD"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.MD)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|a\/b\/ce(f|g)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md|a\/b\/ce(f|g)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/*.js"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e}/*.md"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/xyz\.js)$/); - -var actual = fn("a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/xyz\.md)$/); - -var actual = fn("a/{c..e}.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[c-e]\.js)$/); - -var actual = fn("E:**/*.js"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("E:**/*.md"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("E:\\**/*.js"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("E:\\**/*.md"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); diff --git a/test/actual/micro-matchBase.js b/test/actual/micro-matchBase.js deleted file mode 100644 index a45f84bc..00000000 --- a/test/actual/micro-matchBase.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("**/a/*/b/c/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\/\.js)$/); - -var actual = fn("**/a/*/b/c.d/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\.d\/\.js)$/); - -var actual = fn("**/*.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.((?!\.)(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/*.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.(js|gitignore))$/); - -var actual = fn("**/{a,/.gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(a|\/\.gitignore))$/); - -var actual = fn("**/{a..z..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(a|c|e|g|i|k|m|o|q|s|u|w|y)\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{a..c}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-c]\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[1-10]\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(1|3|5|7|9)\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[b-s]\/xyz\/(?!\.)(?=.)[^/]*?-(?!\.)(?=.)[01-10]\.js)$/); - -var actual = fn("a"); -actual.should.eql(/^(?:a)$/); - -var actual = fn("a/"); -actual.should.eql(/^(?:a\/)$/); - -var actual = fn("a/*"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?)$/); - -var actual = fn(".*"); -actual.should.eql(/^(?:(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/*.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("**/*."); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.)$/); - -var actual = fn("**/*.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.a)$/); - -var actual = fn("**/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.js)$/); - -var actual = fn("**/.*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.md)$/); - -var actual = fn("**/.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.a)$/); - -var actual = fn("**/.a.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.a\.js)$/); - -var actual = fn("**/.gitignore"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("*.*"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.a"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.a)$/); - -var actual = fn("*.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*.{gitignore,*}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.(gitignore|(?!\.)(?=.)[^/]*?))$/); - -var actual = fn("*.{*,gitignore,js}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.((?!\.)(?=.)[^/]*?|gitignore|js))$/); - -var actual = fn("*.{*,gitignore}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.((?!\.)(?=.)[^/]*?|gitignore))$/); - -var actual = fn(".{*,gitignore}"); -actual.should.eql(/^(?:.((?!\.)(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/.((?!\.)(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/.(js|gitignore))$/); - -var actual = fn("**/.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/.(js|md))$/); - -var actual = fn("**/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(a|b)\/(?!\.)(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-z]\/(?!\.)(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("*.js"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("*.md"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("*.{js,txt}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.(js|txt))$/); - -var actual = fn("*/*.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*/.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\/\.gitignore)$/); - -var actual = fn(".a"); -actual.should.eql(/^(?:\.a)$/); - -var actual = fn(".gitignore"); -actual.should.eql(/^(?:\.gitignore)$/); - -var actual = fn(".js"); -actual.should.eql(/^(?:\.js)$/); - -var actual = fn(".md"); -actual.should.eql(/^(?:\.md)$/); - -var actual = fn("a/**/c/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/c/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/j/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/j/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.txt"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.txt)$/); - -var actual = fn("a/*/.b"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/\.b)$/); - -var actual = fn("a/*/.b.a"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/\.b\.a)$/); - -var actual = fn("a/*/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$/); - -var actual = fn("a/*/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$/); - -var actual = fn("a/*/b"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/b)$/); - -var actual = fn("a/*/c/*.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*/c/*.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/.*/b"); -actual.should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - -var actual = fn("a/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$/); - -var actual = fn("a/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$/); - -var actual = fn("a/?/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\.js)$/); - -var actual = fn("a/?/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\.md)$/); - -var actual = fn("a/?/c/?/*/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.js)$/); - -var actual = fn("a/?/c/?/*/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.md)$/); - -var actual = fn("a/?/c/?/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.js)$/); - -var actual = fn("a/?/c/?/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.md)$/); - -var actual = fn("a/?/c/???/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]..\/e\.js)$/); - -var actual = fn("a/?/c/???/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]..\/e\.md)$/); - -var actual = fn("a/??/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/].\/c\.js)$/); - -var actual = fn("a/??/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/].\/c\.md)$/); - -var actual = fn("a/???/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]..\/c\.js)$/); - -var actual = fn("a/???/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]..\/c\.md)$/); - -var actual = fn("a/????/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]...\/c\.js)$/); - -var actual = fn("a/????/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]...\/c\.md)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/c(d|e)\/(?:(?!(?:\/|^)\.).)*?\/xyz\.js)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/c(d|e)\/(?:(?!(?:\/|^)\.).)*?\/xyz\.md)$/); - -var actual = fn("a/b/c/*.js"); -actual.should.eql(/^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("A/b/C/*.js"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c/*.md"); -actual.should.eql(/^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.md"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.MD"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.MD)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.js|a\/b\/ce(f|g)\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.md|a\/b\/ce(f|g)\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/*.js"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e}/*.md"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/xyz\.js)$/); - -var actual = fn("a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/xyz\.md)$/); - -var actual = fn("a/{c..e}.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[c-e]\.js)$/); - -var actual = fn("E:**/*.js"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("E:**/*.md"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("E:\\**/*.js"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("E:\\**/*.md"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$/); diff --git a/test/actual/micro-negate.js b/test/actual/micro-negate.js deleted file mode 100644 index 07c3b415..00000000 --- a/test/actual/micro-negate.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("!**/a/*/b/c/.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\/\.js)$).*$/); - -var actual = fn("!**/a/*/b/c.d/.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\.d\/\.js)$).*$/); - -var actual = fn("!**/*.{*,gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.((?!\.)(?=.)[^/]*?|gitignore))$).*$/); - -var actual = fn("!**/*.{js,gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.(js|gitignore))$).*$/); - -var actual = fn("!**/{a,/.gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(a|\/\.gitignore))$).*$/); - -var actual = fn("!**/{a..z..2}/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(a|c|e|g|i|k|m|o|q|s|u|w|y)\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!**/{a..c}/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-c]\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!**/{1..10}/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[1-10]\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!**/{1..10..2}/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(1|3|5|7|9)\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[b-s]\/xyz\/(?!\.)(?=.)[^/]*?-(?!\.)(?=.)[01-10]\.js)$).*$/); - -var actual = fn("!a"); -actual.should.eql(/^(?!^(?:a)$).*$/); - -var actual = fn("!a/"); -actual.should.eql(/^(?!^(?:a\/)$).*$/); - -var actual = fn("!a/*"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?)$).*$/); - -var actual = fn("!.*"); -actual.should.eql(/^(?!^(?:(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/**/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/**/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/.*/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/*.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.[^/]*?)$).*$/); - -var actual = fn("!**/*."); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.)$).*$/); - -var actual = fn("!**/*.a"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.a)$).*$/); - -var actual = fn("!**/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!**/*.md"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!**/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/.*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.js)$).*$/); - -var actual = fn("!**/.*.md"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.md)$).*$/); - -var actual = fn("!**/.a"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/\.a)$).*$/); - -var actual = fn("!**/.a.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/\.a\.js)$).*$/); - -var actual = fn("!**/.gitignore"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$).*$/); - -var actual = fn("!*.*"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.[^/]*?)$).*$/); - -var actual = fn("!*.a"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.a)$).*$/); - -var actual = fn("!*.gitignore"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.gitignore)$).*$/); - -var actual = fn("!*.{gitignore,*}"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.(gitignore|(?!\.)(?=.)[^/]*?))$).*$/); - -var actual = fn("!*.{*,gitignore,js}"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.((?!\.)(?=.)[^/]*?|gitignore|js))$).*$/); - -var actual = fn("!*.{*,gitignore}"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.((?!\.)(?=.)[^/]*?|gitignore))$).*$/); - -var actual = fn("!.{*,gitignore}"); -actual.should.eql(/^(?!^(?:.((?!\.)(?=.)[^/]*?|gitignore))$).*$/); - -var actual = fn("!**/.{*,gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/.((?!\.)(?=.)[^/]*?|gitignore))$).*$/); - -var actual = fn("!**/.{js,gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/.(js|gitignore))$).*$/); - -var actual = fn("!**/.{js,md}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/.(js|md))$).*$/); - -var actual = fn("!**/*.{js,md}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.(js|md))$).*$/); - -var actual = fn("!**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(a|b)\/(?!\.)(?=.)[^/]*?\.(js|md))$).*$/); - -var actual = fn("!**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-z]\/(?!\.)(?=.)[^/]*?\.(js|md))$).*$/); - -var actual = fn("!*.js"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!*.md"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!*.{js,txt}"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.(js|txt))$).*$/); - -var actual = fn("!*/*.gitignore"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]*?\.gitignore)$).*$/); - -var actual = fn("!*/.gitignore"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\/\.gitignore)$).*$/); - -var actual = fn("!.a"); -actual.should.eql(/^(?!^(?:\.a)$).*$/); - -var actual = fn("!.gitignore"); -actual.should.eql(/^(?!^(?:\.gitignore)$).*$/); - -var actual = fn("!.js"); -actual.should.eql(/^(?!^(?:\.js)$).*$/); - -var actual = fn("!.md"); -actual.should.eql(/^(?!^(?:\.md)$).*$/); - -var actual = fn("!a/**/c/*.js"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/**/c/*.md"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/**/j/**/z/*.js"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/**/j/**/z/*.md"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/**/z/*.js"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/**/z/*.md"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/*.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/*.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/*.txt"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\.txt)$).*$/); - -var actual = fn("!a/*/.b"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/\.b)$).*$/); - -var actual = fn("!a/*/.b.a"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/\.b\.a)$).*$/); - -var actual = fn("!a/*/?/**/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$).*$/); - -var actual = fn("!a/*/?/**/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$).*$/); - -var actual = fn("!a/*/b"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/b)$).*$/); - -var actual = fn("!a/*/c/*.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/*/c/*.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/.*/b"); -actual.should.eql(/^(?!^(?:a\/(?=.)\.[^/]*?\/b)$).*$/); - -var actual = fn("!a/?/**/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$).*$/); - -var actual = fn("!a/?/**/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$).*$/); - -var actual = fn("!a/?/c.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\.js)$).*$/); - -var actual = fn("!a/?/c.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\.md)$).*$/); - -var actual = fn("!a/?/c/?/*/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.js)$).*$/); - -var actual = fn("!a/?/c/?/*/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.md)$).*$/); - -var actual = fn("!a/?/c/?/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.js)$).*$/); - -var actual = fn("!a/?/c/?/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.md)$).*$/); - -var actual = fn("!a/?/c/???/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]..\/e\.js)$).*$/); - -var actual = fn("!a/?/c/???/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]..\/e\.md)$).*$/); - -var actual = fn("!a/??/c.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/].\/c\.js)$).*$/); - -var actual = fn("!a/??/c.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/].\/c\.md)$).*$/); - -var actual = fn("!a/???/c.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]..\/c\.js)$).*$/); - -var actual = fn("!a/???/c.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]..\/c\.md)$).*$/); - -var actual = fn("!a/????/c.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]...\/c\.js)$).*$/); - -var actual = fn("!a/????/c.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]...\/c\.md)$).*$/); - -var actual = fn("!a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?!^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/c(d|e)\/(?:(?!(?:\/|^)\.).)*?\/xyz\.js)$).*$/); - -var actual = fn("!a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?!^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/c(d|e)\/(?:(?!(?:\/|^)\.).)*?\/xyz\.md)$).*$/); - -var actual = fn("!a/b/c/*.js"); -actual.should.eql(/^(?!^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!A/b/C/*.js"); -actual.should.eql(/^(?!^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/b/c/*.md"); -actual.should.eql(/^(?!^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!A/b/C/*.md"); -actual.should.eql(/^(?!^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!A/b/C/*.MD"); -actual.should.eql(/^(?!^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.MD)$).*$/); - -var actual = fn("!a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?!^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.js|a\/b\/ce(f|g)\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?!^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.md|a\/b\/ce(f|g)\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/b/c{d,e}/*.js"); -actual.should.eql(/^(?!^(?:a\/b\/c(d|e)\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/b/c{d,e}/*.md"); -actual.should.eql(/^(?!^(?:a\/b\/c(d|e)\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?!^(?:a\/b\/c(d|e)\/xyz\.js)$).*$/); - -var actual = fn("!a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?!^(?:a\/b\/c(d|e)\/xyz\.md)$).*$/); - -var actual = fn("!a/{c..e}.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[c-e]\.js)$).*$/); - -var actual = fn("!E:**/*.js"); -actual.should.eql(/^(?!^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!E:**/*.md"); -actual.should.eql(/^(?!^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!E:\\**/*.js"); -actual.should.eql(/^(?!^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!E:\\**/*.md"); -actual.should.eql(/^(?!^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$).*$/); diff --git a/test/actual/micro.js b/test/actual/micro.js deleted file mode 100644 index a45f84bc..00000000 --- a/test/actual/micro.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("**/a/*/b/c/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\/\.js)$/); - -var actual = fn("**/a/*/b/c.d/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\.d\/\.js)$/); - -var actual = fn("**/*.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.((?!\.)(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/*.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.(js|gitignore))$/); - -var actual = fn("**/{a,/.gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(a|\/\.gitignore))$/); - -var actual = fn("**/{a..z..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(a|c|e|g|i|k|m|o|q|s|u|w|y)\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{a..c}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-c]\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[1-10]\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(1|3|5|7|9)\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[b-s]\/xyz\/(?!\.)(?=.)[^/]*?-(?!\.)(?=.)[01-10]\.js)$/); - -var actual = fn("a"); -actual.should.eql(/^(?:a)$/); - -var actual = fn("a/"); -actual.should.eql(/^(?:a\/)$/); - -var actual = fn("a/*"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?)$/); - -var actual = fn(".*"); -actual.should.eql(/^(?:(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/*.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("**/*."); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.)$/); - -var actual = fn("**/*.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.a)$/); - -var actual = fn("**/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.js)$/); - -var actual = fn("**/.*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.md)$/); - -var actual = fn("**/.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.a)$/); - -var actual = fn("**/.a.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.a\.js)$/); - -var actual = fn("**/.gitignore"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("*.*"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.a"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.a)$/); - -var actual = fn("*.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*.{gitignore,*}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.(gitignore|(?!\.)(?=.)[^/]*?))$/); - -var actual = fn("*.{*,gitignore,js}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.((?!\.)(?=.)[^/]*?|gitignore|js))$/); - -var actual = fn("*.{*,gitignore}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.((?!\.)(?=.)[^/]*?|gitignore))$/); - -var actual = fn(".{*,gitignore}"); -actual.should.eql(/^(?:.((?!\.)(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/.((?!\.)(?=.)[^/]*?|gitignore))$/); - -var actual = fn("**/.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/.(js|gitignore))$/); - -var actual = fn("**/.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/.(js|md))$/); - -var actual = fn("**/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(a|b)\/(?!\.)(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-z]\/(?!\.)(?=.)[^/]*?\.(js|md))$/); - -var actual = fn("*.js"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("*.md"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("*.{js,txt}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.(js|txt))$/); - -var actual = fn("*/*.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*/.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\/\.gitignore)$/); - -var actual = fn(".a"); -actual.should.eql(/^(?:\.a)$/); - -var actual = fn(".gitignore"); -actual.should.eql(/^(?:\.gitignore)$/); - -var actual = fn(".js"); -actual.should.eql(/^(?:\.js)$/); - -var actual = fn(".md"); -actual.should.eql(/^(?:\.md)$/); - -var actual = fn("a/**/c/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/c/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/j/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/j/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.txt"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.txt)$/); - -var actual = fn("a/*/.b"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/\.b)$/); - -var actual = fn("a/*/.b.a"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/\.b\.a)$/); - -var actual = fn("a/*/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$/); - -var actual = fn("a/*/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$/); - -var actual = fn("a/*/b"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/b)$/); - -var actual = fn("a/*/c/*.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*/c/*.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/.*/b"); -actual.should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - -var actual = fn("a/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$/); - -var actual = fn("a/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$/); - -var actual = fn("a/?/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\.js)$/); - -var actual = fn("a/?/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\.md)$/); - -var actual = fn("a/?/c/?/*/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.js)$/); - -var actual = fn("a/?/c/?/*/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.md)$/); - -var actual = fn("a/?/c/?/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.js)$/); - -var actual = fn("a/?/c/?/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.md)$/); - -var actual = fn("a/?/c/???/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]..\/e\.js)$/); - -var actual = fn("a/?/c/???/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]..\/e\.md)$/); - -var actual = fn("a/??/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/].\/c\.js)$/); - -var actual = fn("a/??/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/].\/c\.md)$/); - -var actual = fn("a/???/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]..\/c\.js)$/); - -var actual = fn("a/???/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]..\/c\.md)$/); - -var actual = fn("a/????/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]...\/c\.js)$/); - -var actual = fn("a/????/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]...\/c\.md)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/c(d|e)\/(?:(?!(?:\/|^)\.).)*?\/xyz\.js)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/c(d|e)\/(?:(?!(?:\/|^)\.).)*?\/xyz\.md)$/); - -var actual = fn("a/b/c/*.js"); -actual.should.eql(/^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("A/b/C/*.js"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c/*.md"); -actual.should.eql(/^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.md"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.MD"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.MD)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.js|a\/b\/ce(f|g)\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.md|a\/b\/ce(f|g)\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/*.js"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e}/*.md"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/xyz\.js)$/); - -var actual = fn("a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?:a\/b\/c(d|e)\/xyz\.md)$/); - -var actual = fn("a/{c..e}.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[c-e]\.js)$/); - -var actual = fn("E:**/*.js"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("E:**/*.md"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("E:\\**/*.js"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("E:\\**/*.md"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$/); diff --git a/test/actual/mini-dot-matchBase.js b/test/actual/mini-dot-matchBase.js deleted file mode 100644 index b09cc47d..00000000 --- a/test/actual/mini-dot-matchBase.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("**/a/*/b/c/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b\/c\/\.js)$/); - -var actual = fn("**/a/*/b/c.d/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b\/c\.d\/\.js)$/); - -var actual = fn("**/*.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("**/*.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("**/{a,/.gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("**/{a..z..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/g\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/i\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/k\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/m\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/o\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/q\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/s\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/u\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/w\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/y\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{a..c}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/b\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/1\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/2\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/3\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/4\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/5\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/6\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/7\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/8\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/9\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/10\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/1\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/3\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/5\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/7\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/9\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?:a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js)$/); - -var actual = fn("a"); -actual.should.eql(/^(?:a)$/); - -var actual = fn("a/"); -actual.should.eql(/^(?:a\/)$/); - -var actual = fn("a/*"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?)$/); - -var actual = fn(".*"); -actual.should.eql(/^(?:(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/*.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("**/*."); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.)$/); - -var actual = fn("**/*.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.a)$/); - -var actual = fn("**/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\.js)$/); - -var actual = fn("**/.*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\.md)$/); - -var actual = fn("**/.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.a)$/); - -var actual = fn("**/.a.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.a\.js)$/); - -var actual = fn("**/.gitignore"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("*.*"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.a"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.a)$/); - -var actual = fn("*.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*.{gitignore,*}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.{*,gitignore,js}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("*.{*,gitignore}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn(".{*,gitignore}"); -actual.should.eql(/^(?:(?=.)\.[^/]*?|\.gitignore)$/); - -var actual = fn("**/.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("**/.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("**/.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.md)$/); - -var actual = fn("**/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\(a\|b\)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\(a\|b\)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[a-z]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[a-z]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("*.js"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("*.md"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("*.{js,txt}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.txt)$/); - -var actual = fn("*/*.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*/.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.gitignore)$/); - -var actual = fn(".a"); -actual.should.eql(/^(?:\.a)$/); - -var actual = fn(".gitignore"); -actual.should.eql(/^(?:\.gitignore)$/); - -var actual = fn(".js"); -actual.should.eql(/^(?:\.js)$/); - -var actual = fn(".md"); -actual.should.eql(/^(?:\.md)$/); - -var actual = fn("a/**/c/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/c/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/j/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/j\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/j/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/j\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.txt"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.txt)$/); - -var actual = fn("a/*/.b"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.b)$/); - -var actual = fn("a/*/.b.a"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.b\.a)$/); - -var actual = fn("a/*/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.js)$/); - -var actual = fn("a/*/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.md)$/); - -var actual = fn("a/*/b"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b)$/); - -var actual = fn("a/*/c/*.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*/c/*.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/.*/b"); -actual.should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - -var actual = fn("a/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.js)$/); - -var actual = fn("a/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.md)$/); - -var actual = fn("a/?/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\.js)$/); - -var actual = fn("a/?/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\.md)$/); - -var actual = fn("a/?/c/?/*/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/e\.js)$/); - -var actual = fn("a/?/c/?/*/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/e\.md)$/); - -var actual = fn("a/?/c/?/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/e\.js)$/); - -var actual = fn("a/?/c/?/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/e\.md)$/); - -var actual = fn("a/?/c/???/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/]\/e\.js)$/); - -var actual = fn("a/?/c/???/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/]\/e\.md)$/); - -var actual = fn("a/??/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/]\/c\.js)$/); - -var actual = fn("a/??/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/]\/c\.md)$/); - -var actual = fn("a/???/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/]\/c\.js)$/); - -var actual = fn("a/???/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/]\/c\.md)$/); - -var actual = fn("a/????/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/][^/]\/c\.js)$/); - -var actual = fn("a/????/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/][^/]\/c\.md)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/cd\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.js|a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/ce\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.js)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/cd\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.md|a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/ce\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.md)$/); - -var actual = fn("a/b/c/*.js"); -actual.should.eql(/^(?:a\/b\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("A/b/C/*.js"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c/*.md"); -actual.should.eql(/^(?:a\/b\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.md"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.MD"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.MD)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|a\/b\/cef\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|a\/b\/ceg\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md|a\/b\/cef\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md|a\/b\/ceg\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|a\/b\/ce\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md|a\/b\/ce\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?:a\/b\/cd\/xyz\.js|a\/b\/ce\/xyz\.js)$/); - -var actual = fn("a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?:a\/b\/cd\/xyz\.md|a\/b\/ce\/xyz\.md)$/); - -var actual = fn("a/{c..e}.js"); -actual.should.eql(/^(?:a\/c\.js|a\/d\.js|a\/e\.js)$/); - -var actual = fn("E:**/*.js"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("E:**/*.md"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("E:\\**/*.js"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("E:\\**/*.md"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); diff --git a/test/actual/mini-dot.js b/test/actual/mini-dot.js deleted file mode 100644 index b09cc47d..00000000 --- a/test/actual/mini-dot.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("**/a/*/b/c/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b\/c\/\.js)$/); - -var actual = fn("**/a/*/b/c.d/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b\/c\.d\/\.js)$/); - -var actual = fn("**/*.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("**/*.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("**/{a,/.gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("**/{a..z..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/g\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/i\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/k\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/m\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/o\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/q\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/s\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/u\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/w\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/y\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{a..c}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/b\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/1\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/2\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/3\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/4\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/5\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/6\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/7\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/8\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/9\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/10\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/1\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/3\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/5\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/7\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/9\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?:a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/b\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/c\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/d\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/e\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/f\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/g\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/h\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/i\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/j\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/k\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/l\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/m\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/n\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/o\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/p\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/q\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/r\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-01\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-02\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-03\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-04\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-05\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-06\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-07\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-08\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-09\.js|a\/s\/xyz\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?-10\.js)$/); - -var actual = fn("a"); -actual.should.eql(/^(?:a)$/); - -var actual = fn("a/"); -actual.should.eql(/^(?:a\/)$/); - -var actual = fn("a/*"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?)$/); - -var actual = fn(".*"); -actual.should.eql(/^(?:(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/*.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("**/*."); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.)$/); - -var actual = fn("**/*.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.a)$/); - -var actual = fn("**/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("**/*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\.js)$/); - -var actual = fn("**/.*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?\.md)$/); - -var actual = fn("**/.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.a)$/); - -var actual = fn("**/.a.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.a\.js)$/); - -var actual = fn("**/.gitignore"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("*.*"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.a"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.a)$/); - -var actual = fn("*.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*.{gitignore,*}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.{*,gitignore,js}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("*.{*,gitignore}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.[^/]*?|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn(".{*,gitignore}"); -actual.should.eql(/^(?:(?=.)\.[^/]*?|\.gitignore)$/); - -var actual = fn("**/.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?=.)\.[^/]*?|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("**/.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.gitignore)$/); - -var actual = fn("**/.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\.md)$/); - -var actual = fn("**/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\(a\|b\)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/\(a\|b\)\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[a-z]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[a-z]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("*.js"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("*.md"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("*.{js,txt}"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.txt)$/); - -var actual = fn("*/*.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*/.gitignore"); -actual.should.eql(/^(?:(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.gitignore)$/); - -var actual = fn(".a"); -actual.should.eql(/^(?:\.a)$/); - -var actual = fn(".gitignore"); -actual.should.eql(/^(?:\.gitignore)$/); - -var actual = fn(".js"); -actual.should.eql(/^(?:\.js)$/); - -var actual = fn(".md"); -actual.should.eql(/^(?:\.md)$/); - -var actual = fn("a/**/c/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/c/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/j/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/j\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/j/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/j\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/z\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.txt"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.txt)$/); - -var actual = fn("a/*/.b"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.b)$/); - -var actual = fn("a/*/.b.a"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/\.b\.a)$/); - -var actual = fn("a/*/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.js)$/); - -var actual = fn("a/*/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.md)$/); - -var actual = fn("a/*/b"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b)$/); - -var actual = fn("a/*/c/*.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*/c/*.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/.*/b"); -actual.should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - -var actual = fn("a/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.js)$/); - -var actual = fn("a/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/e\.md)$/); - -var actual = fn("a/?/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\.js)$/); - -var actual = fn("a/?/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\.md)$/); - -var actual = fn("a/?/c/?/*/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/e\.js)$/); - -var actual = fn("a/?/c/?/*/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/e\.md)$/); - -var actual = fn("a/?/c/?/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/e\.js)$/); - -var actual = fn("a/?/c/?/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/e\.md)$/); - -var actual = fn("a/?/c/???/e.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/]\/e\.js)$/); - -var actual = fn("a/?/c/???/e.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/]\/e\.md)$/); - -var actual = fn("a/??/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/]\/c\.js)$/); - -var actual = fn("a/??/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/]\/c\.md)$/); - -var actual = fn("a/???/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/]\/c\.js)$/); - -var actual = fn("a/???/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/]\/c\.md)$/); - -var actual = fn("a/????/c.js"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/][^/]\/c\.js)$/); - -var actual = fn("a/????/c.md"); -actual.should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/][^/][^/][^/]\/c\.md)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/cd\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.js|a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/ce\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.js)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/cd\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.md|a\/b\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/ce\/(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?\/xyz\.md)$/); - -var actual = fn("a/b/c/*.js"); -actual.should.eql(/^(?:a\/b\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("A/b/C/*.js"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c/*.md"); -actual.should.eql(/^(?:a\/b\/c\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.md"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.MD"); -actual.should.eql(/^(?:A\/b\/C\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.MD)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|a\/b\/cef\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|a\/b\/ceg\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md|a\/b\/cef\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md|a\/b\/ceg\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js|a\/b\/ce\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md|a\/b\/ce\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?:a\/b\/cd\/xyz\.js|a\/b\/ce\/xyz\.js)$/); - -var actual = fn("a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?:a\/b\/cd\/xyz\.md|a\/b\/ce\/xyz\.md)$/); - -var actual = fn("a/{c..e}.js"); -actual.should.eql(/^(?:a\/c\.js|a\/d\.js|a\/e\.js)$/); - -var actual = fn("E:**/*.js"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("E:**/*.md"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); - -var actual = fn("E:\\**/*.js"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.js)$/); - -var actual = fn("E:\\**/*.md"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\.md)$/); diff --git a/test/actual/mini-matchBase.js b/test/actual/mini-matchBase.js deleted file mode 100644 index 1cd249fa..00000000 --- a/test/actual/mini-matchBase.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("**/a/*/b/c/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\/\.js)$/); - -var actual = fn("**/a/*/b/c.d/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\.d\/\.js)$/); - -var actual = fn("**/*.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.[^/]*?|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("**/*.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("**/{a,/.gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a|(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("**/{a..z..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/e\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/g\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/i\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/k\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/m\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/o\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/q\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/s\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/u\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/w\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/y\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{a..c}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/b\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/1\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/2\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/3\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/4\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/5\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/6\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/7\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/8\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/9\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/10\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/1\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/3\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/5\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/7\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/9\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?:a\/b\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-10\.js)$/); - -var actual = fn("a"); -actual.should.eql(/^(?:a)$/); - -var actual = fn("a/"); -actual.should.eql(/^(?:a\/)$/); - -var actual = fn("a/*"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?)$/); - -var actual = fn(".*"); -actual.should.eql(/^(?:(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/*.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("**/*."); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.)$/); - -var actual = fn("**/*.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.a)$/); - -var actual = fn("**/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.js)$/); - -var actual = fn("**/.*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.md)$/); - -var actual = fn("**/.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.a)$/); - -var actual = fn("**/.a.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.a\.js)$/); - -var actual = fn("**/.gitignore"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("*.*"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.a"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.a)$/); - -var actual = fn("*.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*.{gitignore,*}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.gitignore|(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.{*,gitignore,js}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.[^/]*?|(?!\.)(?=.)[^/]*?\.gitignore|(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("*.{*,gitignore}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.[^/]*?|(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn(".{*,gitignore}"); -actual.should.eql(/^(?:(?=.)\.[^/]*?|\.gitignore)$/); - -var actual = fn("**/.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?|(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("**/.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.js|(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("**/.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.js|(?:(?!(?:\/|^)\.).)*?\/\.md)$/); - -var actual = fn("**/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\(a\|b\)\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/\(a\|b\)\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-z]\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-z]\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("*.js"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("*.md"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("*.{js,txt}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.js|(?!\.)(?=.)[^/]*?\.txt)$/); - -var actual = fn("*/*.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*/.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\/\.gitignore)$/); - -var actual = fn(".a"); -actual.should.eql(/^(?:\.a)$/); - -var actual = fn(".gitignore"); -actual.should.eql(/^(?:\.gitignore)$/); - -var actual = fn(".js"); -actual.should.eql(/^(?:\.js)$/); - -var actual = fn(".md"); -actual.should.eql(/^(?:\.md)$/); - -var actual = fn("a/**/c/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/c/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/j/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/j/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.txt"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.txt)$/); - -var actual = fn("a/*/.b"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/\.b)$/); - -var actual = fn("a/*/.b.a"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/\.b\.a)$/); - -var actual = fn("a/*/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$/); - -var actual = fn("a/*/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$/); - -var actual = fn("a/*/b"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/b)$/); - -var actual = fn("a/*/c/*.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*/c/*.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/.*/b"); -actual.should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - -var actual = fn("a/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$/); - -var actual = fn("a/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$/); - -var actual = fn("a/?/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\.js)$/); - -var actual = fn("a/?/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\.md)$/); - -var actual = fn("a/?/c/?/*/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.js)$/); - -var actual = fn("a/?/c/?/*/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.md)$/); - -var actual = fn("a/?/c/?/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.js)$/); - -var actual = fn("a/?/c/?/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.md)$/); - -var actual = fn("a/?/c/???/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/][^/][^/]\/e\.js)$/); - -var actual = fn("a/?/c/???/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/][^/][^/]\/e\.md)$/); - -var actual = fn("a/??/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/]\/c\.js)$/); - -var actual = fn("a/??/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/]\/c\.md)$/); - -var actual = fn("a/???/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/][^/]\/c\.js)$/); - -var actual = fn("a/???/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/][^/]\/c\.md)$/); - -var actual = fn("a/????/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/][^/][^/]\/c\.js)$/); - -var actual = fn("a/????/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/][^/][^/]\/c\.md)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/cd\/(?:(?!(?:\/|^)\.).)*?\/xyz\.js|a\/b\/(?:(?!(?:\/|^)\.).)*?\/ce\/(?:(?!(?:\/|^)\.).)*?\/xyz\.js)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/cd\/(?:(?!(?:\/|^)\.).)*?\/xyz\.md|a\/b\/(?:(?!(?:\/|^)\.).)*?\/ce\/(?:(?!(?:\/|^)\.).)*?\/xyz\.md)$/); - -var actual = fn("a/b/c/*.js"); -actual.should.eql(/^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("A/b/C/*.js"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c/*.md"); -actual.should.eql(/^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.md"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.MD"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.MD)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.js|a\/b\/cef\/(?!\.)(?=.)[^/]*?\.js|a\/b\/ceg\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.md|a\/b\/cef\/(?!\.)(?=.)[^/]*?\.md|a\/b\/ceg\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.js|a\/b\/ce\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.md|a\/b\/ce\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?:a\/b\/cd\/xyz\.js|a\/b\/ce\/xyz\.js)$/); - -var actual = fn("a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?:a\/b\/cd\/xyz\.md|a\/b\/ce\/xyz\.md)$/); - -var actual = fn("a/{c..e}.js"); -actual.should.eql(/^(?:a\/c\.js|a\/d\.js|a\/e\.js)$/); - -var actual = fn("E:**/*.js"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("E:**/*.md"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("E:\\**/*.js"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("E:\\**/*.md"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$/); diff --git a/test/actual/mini-negate.js b/test/actual/mini-negate.js deleted file mode 100644 index 426c24ed..00000000 --- a/test/actual/mini-negate.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("!**/a/*/b/c/.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\/\.js)$).*$/); - -var actual = fn("!**/a/*/b/c.d/.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\.d\/\.js)$).*$/); - -var actual = fn("!**/*.{*,gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.[^/]*?|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.gitignore)$).*$/); - -var actual = fn("!**/*.{js,gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.gitignore)$).*$/); - -var actual = fn("!**/{a,/.gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/a|(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$).*$/); - -var actual = fn("!**/{a..z..2}/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/e\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/g\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/i\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/k\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/m\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/o\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/q\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/s\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/u\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/w\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/y\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!**/{a..c}/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/b\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!**/{1..10}/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/1\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/2\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/3\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/4\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/5\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/6\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/7\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/8\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/9\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/10\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!**/{1..10..2}/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/1\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/3\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/5\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/7\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/9\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?!^(?:a\/b\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-10\.js)$).*$/); - -var actual = fn("!a"); -actual.should.eql(/^(?!^(?:a)$).*$/); - -var actual = fn("!a/"); -actual.should.eql(/^(?!^(?:a\/)$).*$/); - -var actual = fn("!a/*"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?)$).*$/); - -var actual = fn("!.*"); -actual.should.eql(/^(?!^(?:(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/**/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/**/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/.*/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/*.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.[^/]*?)$).*$/); - -var actual = fn("!**/*."); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.)$).*$/); - -var actual = fn("!**/*.a"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.a)$).*$/); - -var actual = fn("!**/*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!**/*.md"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!**/.*"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$).*$/); - -var actual = fn("!**/.*.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.js)$).*$/); - -var actual = fn("!**/.*.md"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.md)$).*$/); - -var actual = fn("!**/.a"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/\.a)$).*$/); - -var actual = fn("!**/.a.js"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/\.a\.js)$).*$/); - -var actual = fn("!**/.gitignore"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$).*$/); - -var actual = fn("!*.*"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.[^/]*?)$).*$/); - -var actual = fn("!*.a"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.a)$).*$/); - -var actual = fn("!*.gitignore"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.gitignore)$).*$/); - -var actual = fn("!*.{gitignore,*}"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.gitignore|(?!\.)(?=.)[^/]*?\.[^/]*?)$).*$/); - -var actual = fn("!*.{*,gitignore,js}"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.[^/]*?|(?!\.)(?=.)[^/]*?\.gitignore|(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!*.{*,gitignore}"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.[^/]*?|(?!\.)(?=.)[^/]*?\.gitignore)$).*$/); - -var actual = fn("!.{*,gitignore}"); -actual.should.eql(/^(?!^(?:(?=.)\.[^/]*?|\.gitignore)$).*$/); - -var actual = fn("!**/.{*,gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?|(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$).*$/); - -var actual = fn("!**/.{js,gitignore}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/\.js|(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$).*$/); - -var actual = fn("!**/.{js,md}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/\.js|(?:(?!(?:\/|^)\.).)*?\/\.md)$).*$/); - -var actual = fn("!**/*.{js,md}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/\(a\|b\)\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/\(a\|b\)\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?!^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-z]\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-z]\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!*.js"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!*.md"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!*.{js,txt}"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\.js|(?!\.)(?=.)[^/]*?\.txt)$).*$/); - -var actual = fn("!*/*.gitignore"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]*?\.gitignore)$).*$/); - -var actual = fn("!*/.gitignore"); -actual.should.eql(/^(?!^(?:(?!\.)(?=.)[^/]*?\/\.gitignore)$).*$/); - -var actual = fn("!.a"); -actual.should.eql(/^(?!^(?:\.a)$).*$/); - -var actual = fn("!.gitignore"); -actual.should.eql(/^(?!^(?:\.gitignore)$).*$/); - -var actual = fn("!.js"); -actual.should.eql(/^(?!^(?:\.js)$).*$/); - -var actual = fn("!.md"); -actual.should.eql(/^(?!^(?:\.md)$).*$/); - -var actual = fn("!a/**/c/*.js"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/**/c/*.md"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/**/j/**/z/*.js"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/**/j/**/z/*.md"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/**/z/*.js"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/**/z/*.md"); -actual.should.eql(/^(?!^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/*.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/*.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/*.txt"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\.txt)$).*$/); - -var actual = fn("!a/*/.b"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/\.b)$).*$/); - -var actual = fn("!a/*/.b.a"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/\.b\.a)$).*$/); - -var actual = fn("!a/*/?/**/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$).*$/); - -var actual = fn("!a/*/?/**/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$).*$/); - -var actual = fn("!a/*/b"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/b)$).*$/); - -var actual = fn("!a/*/c/*.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/*/c/*.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/.*/b"); -actual.should.eql(/^(?!^(?:a\/(?=.)\.[^/]*?\/b)$).*$/); - -var actual = fn("!a/?/**/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$).*$/); - -var actual = fn("!a/?/**/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$).*$/); - -var actual = fn("!a/?/c.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\.js)$).*$/); - -var actual = fn("!a/?/c.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\.md)$).*$/); - -var actual = fn("!a/?/c/?/*/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.js)$).*$/); - -var actual = fn("!a/?/c/?/*/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.md)$).*$/); - -var actual = fn("!a/?/c/?/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.js)$).*$/); - -var actual = fn("!a/?/c/?/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.md)$).*$/); - -var actual = fn("!a/?/c/???/e.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/][^/][^/]\/e\.js)$).*$/); - -var actual = fn("!a/?/c/???/e.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/][^/][^/]\/e\.md)$).*$/); - -var actual = fn("!a/??/c.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/][^/]\/c\.js)$).*$/); - -var actual = fn("!a/??/c.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/][^/]\/c\.md)$).*$/); - -var actual = fn("!a/???/c.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/][^/][^/]\/c\.js)$).*$/); - -var actual = fn("!a/???/c.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/][^/][^/]\/c\.md)$).*$/); - -var actual = fn("!a/????/c.js"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/][^/][^/][^/]\/c\.js)$).*$/); - -var actual = fn("!a/????/c.md"); -actual.should.eql(/^(?!^(?:a\/(?!\.)(?=.)[^/][^/][^/][^/]\/c\.md)$).*$/); - -var actual = fn("!a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?!^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/cd\/(?:(?!(?:\/|^)\.).)*?\/xyz\.js|a\/b\/(?:(?!(?:\/|^)\.).)*?\/ce\/(?:(?!(?:\/|^)\.).)*?\/xyz\.js)$).*$/); - -var actual = fn("!a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?!^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/cd\/(?:(?!(?:\/|^)\.).)*?\/xyz\.md|a\/b\/(?:(?!(?:\/|^)\.).)*?\/ce\/(?:(?!(?:\/|^)\.).)*?\/xyz\.md)$).*$/); - -var actual = fn("!a/b/c/*.js"); -actual.should.eql(/^(?!^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!A/b/C/*.js"); -actual.should.eql(/^(?!^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/b/c/*.md"); -actual.should.eql(/^(?!^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!A/b/C/*.md"); -actual.should.eql(/^(?!^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!A/b/C/*.MD"); -actual.should.eql(/^(?!^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.MD)$).*$/); - -var actual = fn("!a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?!^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.js|a\/b\/cef\/(?!\.)(?=.)[^/]*?\.js|a\/b\/ceg\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?!^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.md|a\/b\/cef\/(?!\.)(?=.)[^/]*?\.md|a\/b\/ceg\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/b/c{d,e}/*.js"); -actual.should.eql(/^(?!^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.js|a\/b\/ce\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!a/b/c{d,e}/*.md"); -actual.should.eql(/^(?!^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.md|a\/b\/ce\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?!^(?:a\/b\/cd\/xyz\.js|a\/b\/ce\/xyz\.js)$).*$/); - -var actual = fn("!a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?!^(?:a\/b\/cd\/xyz\.md|a\/b\/ce\/xyz\.md)$).*$/); - -var actual = fn("!a/{c..e}.js"); -actual.should.eql(/^(?!^(?:a\/c\.js|a\/d\.js|a\/e\.js)$).*$/); - -var actual = fn("!E:**/*.js"); -actual.should.eql(/^(?!^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!E:**/*.md"); -actual.should.eql(/^(?!^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$).*$/); - -var actual = fn("!E:\\**/*.js"); -actual.should.eql(/^(?!^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$).*$/); - -var actual = fn("!E:\\**/*.md"); -actual.should.eql(/^(?!^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$).*$/); diff --git a/test/actual/mini.js b/test/actual/mini.js deleted file mode 100644 index 1cd249fa..00000000 --- a/test/actual/mini.js +++ /dev/null @@ -1,305 +0,0 @@ -var actual = fn("**/a/*/b/c/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\/\.js)$/); - -var actual = fn("**/a/*/b/c.d/.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\/b\/c\.d\/\.js)$/); - -var actual = fn("**/*.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.[^/]*?|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("**/*.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("**/{a,/.gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a|(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("**/{a..z..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/e\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/g\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/i\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/k\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/m\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/o\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/q\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/s\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/u\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/w\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/y\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{a..c}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/a\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/b\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/1\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/2\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/3\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/4\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/5\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/6\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/7\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/8\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/9\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/10\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/{1..10..2}/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/1\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/3\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/5\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/7\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/9\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/{b..s}/xyz/*-{01..10}.js"); -actual.should.eql(/^(?:a\/b\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/b\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/c\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/d\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/e\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/f\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/g\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/h\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/i\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/j\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/k\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/l\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/m\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/n\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/o\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/p\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/q\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/r\/xyz\/(?!\.)(?=.)[^/]*?-10\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-01\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-02\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-03\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-04\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-05\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-06\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-07\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-08\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-09\.js|a\/s\/xyz\/(?!\.)(?=.)[^/]*?-10\.js)$/); - -var actual = fn("a"); -actual.should.eql(/^(?:a)$/); - -var actual = fn("a/"); -actual.should.eql(/^(?:a\/)$/); - -var actual = fn("a/*"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?)$/); - -var actual = fn(".*"); -actual.should.eql(/^(?:(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/*.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("**/*."); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.)$/); - -var actual = fn("**/*.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.a)$/); - -var actual = fn("**/*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("**/*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("**/.*"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?)$/); - -var actual = fn("**/.*.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.js)$/); - -var actual = fn("**/.*.md"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?\.md)$/); - -var actual = fn("**/.a"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.a)$/); - -var actual = fn("**/.a.js"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.a\.js)$/); - -var actual = fn("**/.gitignore"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("*.*"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.a"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.a)$/); - -var actual = fn("*.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*.{gitignore,*}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.gitignore|(?!\.)(?=.)[^/]*?\.[^/]*?)$/); - -var actual = fn("*.{*,gitignore,js}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.[^/]*?|(?!\.)(?=.)[^/]*?\.gitignore|(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("*.{*,gitignore}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.[^/]*?|(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn(".{*,gitignore}"); -actual.should.eql(/^(?:(?=.)\.[^/]*?|\.gitignore)$/); - -var actual = fn("**/.{*,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?=.)\.[^/]*?|(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("**/.{js,gitignore}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.js|(?:(?!(?:\/|^)\.).)*?\/\.gitignore)$/); - -var actual = fn("**/.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.js|(?:(?!(?:\/|^)\.).)*?\/\.md)$/); - -var actual = fn("**/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("**/(a|b)/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\(a\|b\)\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/\(a\|b\)\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("**/[a-z]/*.{js,md}"); -actual.should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-z]\/(?!\.)(?=.)[^/]*?\.js|(?:(?!(?:\/|^)\.).)*?\/(?!\.)(?=.)[a-z]\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("*.js"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("*.md"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("*.{js,txt}"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\.js|(?!\.)(?=.)[^/]*?\.txt)$/); - -var actual = fn("*/*.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]*?\.gitignore)$/); - -var actual = fn("*/.gitignore"); -actual.should.eql(/^(?:(?!\.)(?=.)[^/]*?\/\.gitignore)$/); - -var actual = fn(".a"); -actual.should.eql(/^(?:\.a)$/); - -var actual = fn(".gitignore"); -actual.should.eql(/^(?:\.gitignore)$/); - -var actual = fn(".js"); -actual.should.eql(/^(?:\.js)$/); - -var actual = fn(".md"); -actual.should.eql(/^(?:\.md)$/); - -var actual = fn("a/**/c/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/c/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/j/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/j/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/j\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/**/z/*.js"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/**/z/*.md"); -actual.should.eql(/^(?:a\/(?:(?!(?:\/|^)\.).)*?\/z\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/*.txt"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\.txt)$/); - -var actual = fn("a/*/.b"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/\.b)$/); - -var actual = fn("a/*/.b.a"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/\.b\.a)$/); - -var actual = fn("a/*/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$/); - -var actual = fn("a/*/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$/); - -var actual = fn("a/*/b"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/b)$/); - -var actual = fn("a/*/c/*.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/*/c/*.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/.*/b"); -actual.should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - -var actual = fn("a/?/**/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.js)$/); - -var actual = fn("a/?/**/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/(?:(?!(?:\/|^)\.).)*?\/e\.md)$/); - -var actual = fn("a/?/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\.js)$/); - -var actual = fn("a/?/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\.md)$/); - -var actual = fn("a/?/c/?/*/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.js)$/); - -var actual = fn("a/?/c/?/*/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?\/e\.md)$/); - -var actual = fn("a/?/c/?/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.js)$/); - -var actual = fn("a/?/c/?/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/]\/e\.md)$/); - -var actual = fn("a/?/c/???/e.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/][^/][^/]\/e\.js)$/); - -var actual = fn("a/?/c/???/e.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/]\/c\/(?!\.)(?=.)[^/][^/][^/]\/e\.md)$/); - -var actual = fn("a/??/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/]\/c\.js)$/); - -var actual = fn("a/??/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/]\/c\.md)$/); - -var actual = fn("a/???/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/][^/]\/c\.js)$/); - -var actual = fn("a/???/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/][^/]\/c\.md)$/); - -var actual = fn("a/????/c.js"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/][^/][^/]\/c\.js)$/); - -var actual = fn("a/????/c.md"); -actual.should.eql(/^(?:a\/(?!\.)(?=.)[^/][^/][^/][^/]\/c\.md)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.js"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/cd\/(?:(?!(?:\/|^)\.).)*?\/xyz\.js|a\/b\/(?:(?!(?:\/|^)\.).)*?\/ce\/(?:(?!(?:\/|^)\.).)*?\/xyz\.js)$/); - -var actual = fn("a/b/**/c{d,e}/**/xyz.md"); -actual.should.eql(/^(?:a\/b\/(?:(?!(?:\/|^)\.).)*?\/cd\/(?:(?!(?:\/|^)\.).)*?\/xyz\.md|a\/b\/(?:(?!(?:\/|^)\.).)*?\/ce\/(?:(?!(?:\/|^)\.).)*?\/xyz\.md)$/); - -var actual = fn("a/b/c/*.js"); -actual.should.eql(/^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("A/b/C/*.js"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c/*.md"); -actual.should.eql(/^(?:a\/b\/c\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.md"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("A/b/C/*.MD"); -actual.should.eql(/^(?:A\/b\/C\/(?!\.)(?=.)[^/]*?\.MD)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.js|a\/b\/cef\/(?!\.)(?=.)[^/]*?\.js|a\/b\/ceg\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e{f,g}}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.md|a\/b\/cef\/(?!\.)(?=.)[^/]*?\.md|a\/b\/ceg\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/*.js"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.js|a\/b\/ce\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("a/b/c{d,e}/*.md"); -actual.should.eql(/^(?:a\/b\/cd\/(?!\.)(?=.)[^/]*?\.md|a\/b\/ce\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("a/b/c{d,e}/xyz.js"); -actual.should.eql(/^(?:a\/b\/cd\/xyz\.js|a\/b\/ce\/xyz\.js)$/); - -var actual = fn("a/b/c{d,e}/xyz.md"); -actual.should.eql(/^(?:a\/b\/cd\/xyz\.md|a\/b\/ce\/xyz\.md)$/); - -var actual = fn("a/{c..e}.js"); -actual.should.eql(/^(?:a\/c\.js|a\/d\.js|a\/e\.js)$/); - -var actual = fn("E:**/*.js"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("E:**/*.md"); -actual.should.eql(/^(?:(?=.)E:[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$/); - -var actual = fn("E:\\**/*.js"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.js)$/); - -var actual = fn("E:\\**/*.md"); -actual.should.eql(/^(?:(?=.)E:\\[^/]*?[^/]*?\/(?!\.)(?=.)[^/]*?\.md)$/); diff --git a/test/any.js b/test/any.js deleted file mode 100644 index 6eb844c0..00000000 --- a/test/any.js +++ /dev/null @@ -1,225 +0,0 @@ -'use strict'; - -require('mocha'); -var assert = require('assert'); -var nm = require('..'); - -describe('.any()', function() { - describe('error handling', function() { - it('should throw on undefined args:', function() { - assert.throws(function() { - nm.any(); - }, /expected patterns to be a string or array/); - }); - - it('should throw on bad args:', function() { - assert.throws(function() { - nm.any({}); - }, /expected patterns to be a string or array/); - }); - }); - - it('should correctly handle empty patterns', function() { - assert(!nm.any('ab', '')); - assert(!nm.any('a', '')); - assert(!nm.any('.', '')); - }); - - it('should support an array of patterns', function() { - assert(!nm.any('ab', [''])); - assert(!nm.any('a', [''])); - assert(!nm.any('.', [''])); - }); - - it('should return true when the path contains the pattern', function() { - assert(!nm.any('ab', 'b')); - assert(nm.any('.', '.')); - assert(!nm.any('a/b/c', 'a/b')); - assert(!nm.any('/ab', '/a')); - assert(nm.any('a', 'a')); - assert(!nm.any('ab', 'a')); - assert(nm.any('ab', 'ab')); - assert(!nm.any('abcd', 'd')); - assert(!nm.any('abcd', 'c')); - assert(!nm.any('abcd', 'cd')); - assert(!nm.any('abcd', 'bc')); - assert(!nm.any('abcd', 'ab')); - }); - - it('should return true when the path contains any of the patterns', function() { - assert(!nm.any('ab', ['b', 'foo'])); - assert(nm.any('.', ['.', 'foo'])); - assert(!nm.any('a/b/c', ['a/b', 'foo'])); - assert(!nm.any('/ab', ['/a', 'foo'])); - assert(nm.any('a', ['a', 'foo'])); - assert(!nm.any('ab', ['a', 'foo'])); - assert(nm.any('ab', ['ab', 'foo'])); - assert(!nm.any('abcd', ['d', 'foo'])); - assert(!nm.any('abcd', ['c', 'foo'])); - assert(!nm.any('abcd', ['cd', 'foo'])); - assert(!nm.any('abcd', ['bc', 'foo'])); - assert(!nm.any('abcd', ['ab', 'foo'])); - }); - - it('should match with conmon glob patterns', function() { - assert(nm.any('/ab', '*/*')); - assert(nm.any('/ab', '/*')); - assert(nm.any('/ab', '/??')); - assert(nm.any('/ab', '/?b')); - assert(nm.any('/cd', '/*')); - assert(nm.any('a/b', '?/?')); - assert(nm.any('ab', '*')); - assert(nm.any('ab', 'ab')); - assert(!nm.any('/ab', '*/')); - assert(!nm.any('/ab', '*/a')); - assert(!nm.any('/ab', '/')); - assert(!nm.any('/ab', '/?')); - assert(!nm.any('/ab', '/a')); - assert(!nm.any('a/b/c', 'a/*')); - }); - - it('should return false when the path does not contain the pattern', function() { - assert(!nm.any('/ab', '?/?')); - assert(!nm.any('ab', '*/*')); - assert(!nm.any('abcd', 'f')); - assert(!nm.any('ab', 'c')); - assert(!nm.any('ab', '/a')); - assert(!nm.any('/ab', 'a/*')); - assert(!nm.any('ef', '/*')); - assert(!nm.any('ab', './*')); - }); - - it('should return false when the path does not contain any pattern', function() { - assert(!nm.any('/ab', ['?/?', 'foo', 'bar'])); - assert(!nm.any('ab', ['*/*', 'foo', 'bar'])); - assert(!nm.any('abcd', ['f', 'foo', 'bar'])); - assert(!nm.any('ab', ['c', 'foo', 'bar'])); - assert(!nm.any('ab', ['/a', 'foo', 'bar'])); - assert(!nm.any('/ab', ['a/*', 'foo', 'bar'])); - assert(!nm.any('ef', ['/*', 'foo', 'bar'])); - assert(!nm.any('ab', ['./*', 'foo', 'bar'])); - }); - - it('should match files that contain the given extension:', function() { - assert(!nm.any('.md', '.m')); - assert(nm.any('.c.md', '.*.md')); - assert(nm.any('c.md', '*.md')); - assert(!nm.any('a/b/c.md', '.md')); - assert(nm.any('a/b/c.md', 'a/*/*.md')); - assert(nm.any('a/b/c.md', '**/*.md')); - assert(nm.any('c.md', '*.md')); - assert(!nm.any('.c.md', '.md')); - assert(!nm.any('.c.md', '.c.')); - assert(!nm.any('a/b/c.md', '*.md')); - assert(!nm.any('a/b/c/c.md', '*.md')); - assert(!nm.any('.c.md', '*.md')); - }); - - it('should not match files that do not contain the given extension:', function() { - assert(!nm.any('.md', '*.md')); - assert(!nm.any('a/b/c/c.md', 'c.js')); - assert(!nm.any('a/b/c.md', 'a/*.md')); - }); - - it('should match dotfiles when a dot is explicitly defined in the pattern:', function() { - assert(nm.any('.a', '.a')); - assert(nm.any('.ab', '.*')); - assert(nm.any('.ab', '.a*')); - assert(!nm.any('.abc', '.a')); - assert(nm.any('.b', '.b*')); - assert(nm.any('.md', '.md')); - assert(!nm.any('.c.md', '*.md')); - assert(nm.any('a/.c.md', 'a/.c.md')); - assert(nm.any('a/b/c/.xyz.md', 'a/b/c/.*.md')); - assert(!nm.any('a/.c.md', '*.md')); - assert(nm.any('a/b/c/d.a.md', 'a/b/c/*.md')); - }); - - it('should match dotfiles when `dot` or `dotfiles` is set:', function() { - assert(!nm.any('a/b/c/.xyz.md', '.*.md', {dot: true})); - assert(nm.any('.c.md', '*.md', {dot: true})); - assert(nm.any('.c.md', '.*', {dot: true})); - assert(nm.any('a/b/c/.xyz.md', '**/*.md', {dot: true})); - assert(nm.any('a/b/c/.xyz.md', '**/.*.md', {dot: true})); - assert(nm.any('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true})); - assert(nm.any('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true})); - }); - - it('should not match dotfiles when `dot` or `dotfiles` is not set:', function() { - assert(!nm.any('.a', '*.md')); - assert(!nm.any('.ba', '.a')); - assert(!nm.any('.a.md', 'a/b/c/*.md')); - assert(!nm.any('.ab', '*.*')); - assert(!nm.any('.md', 'a/b/c/*.md')); - assert(!nm.any('.txt', '.md')); - assert(!nm.any('.verb.txt', '*.md')); - assert(!nm.any('a/b/d/.md', 'a/b/c/*.md')); - }); - - it('should match file paths:', function() { - assert(nm.any('a/b/c/xyz.md', 'a/b/c/*.md')); - assert(nm.any('a/bb/c/xyz.md', 'a/*/c/*.md')); - assert(nm.any('a/bbbb/c/xyz.md', 'a/*/c/*.md')); - assert(nm.any('a/bb.bb/c/xyz.md', 'a/*/c/*.md')); - assert(nm.any('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md')); - assert(nm.any('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md')); - }); - - it('should return true when full file paths are matched:', function() { - assert(nm.any('a/.b', 'a/.*')); - assert(!nm.any('a/.b', 'a/')); - assert(!nm.any('a/b/z/.a', 'b/z')); - assert(nm.any('a/b/z/.a', 'a/*/z/.a')); - assert(nm.any('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); - assert(!nm.any('a/b/c/d/e/z/c.md', 'b/c/d/e')); - assert(nm.any('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); - }); - - it('question marks should not match slashes:', function() { - assert(!nm.any('aaa/bbb', 'aaa?bbb')); - }); - - it('should match path segments:', function() { - assert(nm.any('aaa', 'aaa')); - assert(!nm.any('aaa', 'aa')); - assert(nm.any('aaa/bbb', 'aaa/bbb')); - assert(nm.any('aaa/bbb', 'aaa/*')); - assert(!nm.any('aaa/bba/ccc', 'aaa/*')); - assert(nm.any('aaa/bba/ccc', 'aaa/**')); - assert(!nm.any('aaa/bba/ccc', 'aaa*')); - assert(!nm.any('aaa/bba/ccc', 'aaa**')); - assert(!nm.any('aaa/bba/ccc', 'aaa/*ccc')); - assert(nm.any('aaa/bba/ccc', 'aaa/**ccc')); - assert(!nm.any('aaa/bba/ccc', 'aaa/*z')); - assert(!nm.any('aaa/bba/ccc', 'aaa/**z')); - assert(nm.any('aaa/bbb', 'aaa[/]bbb')); - assert(!nm.any('aaa', '*/*/*')); - assert(!nm.any('aaa/bbb', '*/*/*')); - assert(nm.any('aaa/bba/ccc', '*/*/*')); - assert(!nm.any('aaa/bb/aa/rr', '*/*/*')); - assert(nm.any('abzzzejklhi', '*j*i')); - assert(nm.any('ab/zzz/ejkl/hi', '*/*z*/*/*i')); - assert(!nm.any('ab/zzz/ejkl/hi', '*/*jk*/*i')); - }); - - it('should return false when full file paths are not matched:', function() { - assert(!nm.any('a/b/z/.a', 'b/a')); - assert(!nm.any('a/.b', 'a/**/z/*.md')); - assert(!nm.any('a/b/z/.a', 'a/**/z/*.a')); - assert(!nm.any('a/b/z/.a', 'a/*/z/*.a')); - assert(!nm.any('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md')); - }); - - it('should match paths with leading `./`:', function() { - assert(!nm.any('./.a', 'a/**/z/*.md')); - assert(!nm.any('./a/b/z/.a', 'a/**/z/.a')); - assert(nm.any('./a/b/z/.a', './a/**/z/.a')); - assert(!nm.any('./a/b/c/d/e/z/c.md', 'a/**/z/*.md')); - assert(nm.any('./a/b/c/d/e/z/c.md', './a/**/z/*.md')); - assert(!nm.any('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md')); - assert(nm.any('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md')); - assert(!nm.any('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md')); - assert(nm.any('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md')); - assert(!nm.any('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md')); - }); -}); diff --git a/test/api.any.js b/test/api.any.js new file mode 100644 index 00000000..4f637888 --- /dev/null +++ b/test/api.any.js @@ -0,0 +1,239 @@ +'use strict'; + +require('mocha'); +var assert = require('assert'); +var mm = require('..'); + +describe('.any()', function() { + describe('empty patterns', function() { + it('should correctly handle empty patterns', function() { + assert(!mm.any('ab', '')); + assert(!mm.any('a', '')); + assert(!mm.any('.', '')); + assert(!mm.any('ab', [''])); + assert(!mm.any('a', [''])); + assert(!mm.any('.', [''])); + }); + }); + + describe('non-globs', function() { + it('should match literal paths', function() { + assert(!mm.any('aaa', 'aa')); + assert(mm.any('aaa', 'aaa')); + assert(mm.any('aaa/bbb', 'aaa/bbb')); + assert(mm.any('aaa/bbb', 'aaa[/]bbb')); + }); + }); + + describe('stars (single pattern)', function() { + it('should return true when full file paths are matched:', function() { + assert(mm.any('a/b/c/xyz.md', 'a/b/c/*.md')); + assert(mm.any('a/bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.any('a/bbbb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.any('a/bb.bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.any('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md')); + assert(mm.any('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md')); + assert(!mm.any('a/.b', 'a/')); + assert(!mm.any('a/b/c/d/e/z/c.md', 'b/c/d/e')); + assert(!mm.any('a/b/z/.a', 'b/z')); + assert(mm.any('a/.b', 'a/.*')); + assert(mm.any('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); + assert(mm.any('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.any('a/b/z/.a', 'a/*/z/.a')); + assert(mm.any('.', '.')); + assert(mm.any('/ab', '*/*')); + assert(mm.any('/ab', '/*')); + assert(mm.any('/ab', '/??')); + assert(mm.any('/ab', '/?b')); + assert(mm.any('/cd', '/*')); + assert(mm.any('a', 'a')); + assert(mm.any('ab', './*')); + assert(mm.any('ab/', './*/')); + assert(mm.any('a/b', '?/?')); + assert(mm.any('ab', '*')); + assert(mm.any('ab', 'ab')); + }); + + it('should return false when the path does not match the pattern', function() { + assert(!mm.any('/ab', '*/')); + assert(!mm.any('/ab', '*/a')); + assert(!mm.any('/ab', '/')); + assert(!mm.any('/ab', '/?')); + assert(!mm.any('/ab', '/a')); + assert(!mm.any('/ab', '?/?')); + assert(!mm.any('/ab', 'a/*')); + assert(!mm.any('a/b/c', 'a/*')); + assert(!mm.any('a/b/c', 'a/b')); + assert(!mm.any('ab', '*/*')); + assert(!mm.any('ab/', '*/*')); + assert(!mm.any('ab', '/a')); + assert(!mm.any('ab', 'a')); + assert(!mm.any('ab', 'b')); + assert(!mm.any('ab', 'c')); + assert(!mm.any('abcd', 'ab')); + assert(!mm.any('abcd', 'bc')); + assert(!mm.any('abcd', 'c')); + assert(!mm.any('abcd', 'cd')); + assert(!mm.any('abcd', 'd')); + assert(!mm.any('abcd', 'f')); + assert(!mm.any('ef', '/*')); + }); + + it('should match a path segment for each single star', function() { + assert(!mm.any('aaa', '*/*/*')); + assert(!mm.any('aaa/bb/aa/rr', '*/*/*')); + assert(!mm.any('aaa/bba/ccc', 'aaa*')); + assert(!mm.any('aaa/bba/ccc', 'aaa**')); + assert(!mm.any('aaa/bba/ccc', 'aaa/*')); + assert(!mm.any('aaa/bba/ccc', 'aaa/*ccc')); + assert(!mm.any('aaa/bba/ccc', 'aaa/*z')); + assert(!mm.any('aaa/bbb', '*/*/*')); + assert(!mm.any('ab/zzz/ejkl/hi', '*/*jk*/*i')); + assert(mm.any('aaa/bba/ccc', '*/*/*')); + assert(mm.any('aaa/bba/ccc', 'aaa/**')); + assert(mm.any('aaa/bbb', 'aaa/*')); + assert(mm.any('ab/zzz/ejkl/hi', '*/*z*/*/*i')); + assert(mm.any('abzzzejklhi', '*j*i')); + }); + + it('should regard non-exclusive double-stars as single stars', function() { + assert(!mm.any('aaa/bba/ccc', 'aaa/**ccc')); + assert(!mm.any('aaa/bba/ccc', 'aaa/**z')); + }); + + it('should return false when full file paths are not matched:', function() { + assert(!mm.any('a/b/z/.a', 'b/a')); + assert(!mm.any('a/.b', 'a/**/z/*.md')); + assert(!mm.any('a/b/z/.a', 'a/**/z/*.a')); + assert(!mm.any('a/b/z/.a', 'a/*/z/*.a')); + assert(!mm.any('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md')); + assert(!mm.any('a/b/d/xyz.md', 'a/b/**/c{d,e}/**/xyz.md')); + assert(!mm.any('a/b/c/xyz.md', 'a/b/**/c{d,e}/**/xyz.md')); + }); + }); + + describe('stars (multiple patterns)', function() { + it('should return true when any of the patterns match', function() { + assert(mm.any('.', ['.', 'foo'])); + assert(mm.any('a', ['a', 'foo'])); + assert(mm.any('ab', ['ab', 'foo'])); + assert(mm.any('ab', ['./*', 'foo', 'bar'])); + assert(mm.any('ab', ['*', 'foo', 'bar'])); + assert(mm.any('ab', ['*b', 'foo', 'bar'])); + assert(mm.any('ab', ['a*', 'foo', 'bar'])); + }); + + it('should return false when none of the patterns match', function() { + assert(!mm.any('/ab', ['/a', 'foo'])); + assert(!mm.any('/ab', ['?/?', 'foo', 'bar'])); + assert(!mm.any('/ab', ['a/*', 'foo', 'bar'])); + assert(!mm.any('a/b/c', ['a/b', 'foo'])); + assert(!mm.any('ab', ['*/*', 'foo', 'bar'])); + assert(!mm.any('ab', ['/a', 'foo', 'bar'])); + assert(!mm.any('ab', ['a', 'foo'])); + assert(!mm.any('ab', ['b', 'foo'])); + assert(!mm.any('ab', ['c', 'foo', 'bar'])); + assert(!mm.any('abcd', ['ab', 'foo'])); + assert(!mm.any('abcd', ['bc', 'foo'])); + assert(!mm.any('abcd', ['c', 'foo'])); + assert(!mm.any('abcd', ['cd', 'foo'])); + assert(!mm.any('abcd', ['d', 'foo'])); + assert(!mm.any('abcd', ['f', 'foo', 'bar'])); + assert(!mm.any('ef', ['/*', 'foo', 'bar'])); + }); + }); + + describe('file extensions', function() { + it('should match files that contain the given extension:', function() { + assert(mm.any('.c.md', '.*.md')); + assert(mm.any('a/b/c.md', '**/*.md')); + assert(mm.any('a/b/c.md', 'a/*/*.md')); + assert(mm.any('c.md', '*.md')); + }); + + it('should not match files that do not contain the given extension:', function() { + assert(!mm.any('.c.md', '*.md')); + assert(!mm.any('.c.md', '.c.')); + assert(!mm.any('.c.md', '.md')); + assert(!mm.any('.md', '*.md')); + assert(!mm.any('.md', '.m')); + assert(!mm.any('a/b/c.md', '*.md')); + assert(!mm.any('a/b/c.md', '.md')); + assert(!mm.any('a/b/c.md', 'a/*.md')); + assert(!mm.any('a/b/c/c.md', '*.md')); + assert(!mm.any('a/b/c/c.md', 'c.js')); + }); + }); + + describe('dot files', function() { + it('should match dotfiles when a dot is explicitly defined in the pattern:', function() { + assert(mm.any('.a', '.a')); + assert(mm.any('.ab', '.*')); + assert(mm.any('.ab', '.a*')); + assert(mm.any('.b', '.b*')); + assert(mm.any('.md', '.md')); + assert(mm.any('a/.c.md', 'a/.c.md')); + assert(mm.any('a/b/c/.xyz.md', 'a/b/c/.*.md')); + assert(mm.any('a/b/c/d.a.md', 'a/b/c/*.md')); + }); + + it('should match leading `./` when `**` is in the pattern', function() { + assert(mm.any('./a', 'a')); + assert(mm.any('.ab', '.*')); + assert(mm.any('.ab', '.a*')); + assert(mm.any('.b', '.b*')); + assert(mm.any('.md', '.md')); + assert(mm.any('a/.c.md', 'a/.c.md')); + assert(mm.any('a/b/c/.xyz.md', 'a/b/c/.*.md')); + assert(mm.any('a/b/c/d.a.md', 'a/b/c/*.md')); + }); + + it('should not match dotfiles when a dot is not defined in the pattern:', function() { + assert(!mm.any('.abc', '.a')); + assert(!mm.any('.c.md', '*.md')); + assert(!mm.any('a/.c.md', '*.md')); + }); + + it('should match dotfiles when `dot` is set:', function() { + assert(!mm.any('a/b/c/.xyz.md', '.*.md', {dot: true})); + assert(mm.any('.c.md', '*.md', {dot: true})); + assert(mm.any('.c.md', '.*', {dot: true})); + assert(mm.any('a/b/c/.xyz.md', '**/*.md', {dot: true})); + assert(mm.any('a/b/c/.xyz.md', '**/.*.md', {dot: true})); + assert(mm.any('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true})); + assert(mm.any('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true})); + }); + + it('should not match dotfiles when `dot` is not set:', function() { + assert(!mm.any('.a', '*.md')); + assert(!mm.any('.ba', '.a')); + assert(!mm.any('.a.md', 'a/b/c/*.md')); + assert(!mm.any('.ab', '*.*')); + assert(!mm.any('.md', 'a/b/c/*.md')); + assert(!mm.any('.txt', '.md')); + assert(!mm.any('.verb.txt', '*.md')); + assert(!mm.any('a/b/d/.md', 'a/b/c/*.md')); + }); + }); + + describe('qmarks', function() { + it('question marks should not match slashes:', function() { + assert(!mm.any('aaa/bbb', 'aaa?bbb')); + }); + }); + + describe('dot-slash', function() { + it('should match paths with leading `./`:', function() { + assert(!mm.any('./.a', 'a/**/z/*.md')); + assert(!mm.any('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md')); + assert(!mm.any('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md')); + assert(mm.any('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.any('./a/b/c/d/e/z/c.md', './a/**/z/*.md')); + assert(mm.any('./a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.any('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.any('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md')); + assert(mm.any('./a/b/z/.a', './a/**/z/.a')); + assert(mm.any('./a/b/z/.a', 'a/**/z/.a')); + }); + }); +}); diff --git a/test/contains.js b/test/api.contains.js similarity index 56% rename from test/contains.js rename to test/api.contains.js index 03ec67a1..7f8b6e41 100644 --- a/test/contains.js +++ b/test/api.contains.js @@ -1,23 +1,11 @@ 'use strict'; +var path = require('path'); +var sep = path.sep; var assert = require('assert'); var mm = require('..'); describe('.contains()', function() { - describe('error handling', function() { - it('should throw on invalid filepath:', function() { - assert.throws(function() { - mm.contains(); - }, /expected filepath to be a string/); - }); - - it('should throw on invalid pattern:', function() { - assert.throws(function() { - mm.contains('', {}); - }, /expected pattern to be a string/); - }); - }); - describe('patterns', function() { it('should correctly deal with empty patterns', function() { assert(!mm.contains('ab', '')); @@ -65,22 +53,21 @@ describe('.contains()', function() { assert(!mm.contains('ab', '/a')); assert(!mm.contains('/ab', 'a/*')); assert(!mm.contains('ef', '/*')); - assert(!mm.contains('ab', './*')); }); it('should match files that contain the given extension:', function() { - assert(mm.contains('.md', '.m')); + assert(mm.contains('ab', './*')); + assert(mm.contains('.c.md', '*.md')); assert(mm.contains('.c.md', '.*.md')); - assert(mm.contains('c.md', '*.md')); - assert(mm.contains('a/b/c.md', '.md')); - assert(mm.contains('a/b/c.md', 'a/*/*.md')); - assert(mm.contains('a/b/c.md', '**/*.md')); - assert(mm.contains('c.md', '*.md')); - assert(mm.contains('.c.md', '.md')); assert(mm.contains('.c.md', '.c.')); + assert(mm.contains('.c.md', '.md')); + assert(mm.contains('.md', '.m')); + assert(mm.contains('a/b/c.md', '**/*.md')); assert(mm.contains('a/b/c.md', '*.md')); + assert(mm.contains('a/b/c.md', '.md')); + assert(mm.contains('a/b/c.md', 'a/*/*.md')); assert(mm.contains('a/b/c/c.md', '*.md')); - assert(mm.contains('.c.md', '*.md')); + assert(mm.contains('c.md', '*.md')); }); it('should not match files that do not contain the given extension:', function() { @@ -95,20 +82,20 @@ describe('.contains()', function() { assert(mm.contains('.ab', '.a*')); assert(mm.contains('.abc', '.a')); assert(mm.contains('.b', '.b*')); - assert(mm.contains('.md', '.md')); assert(mm.contains('.c.md', '*.md')); + assert(mm.contains('.md', '.md')); + assert(mm.contains('a/.c.md', '*.md')); assert(mm.contains('a/.c.md', 'a/.c.md')); assert(mm.contains('a/b/c/.xyz.md', 'a/b/c/.*.md')); - assert(mm.contains('a/.c.md', '*.md')); assert(mm.contains('a/b/c/d.a.md', 'a/b/c/*.md')); }); it('should match dotfiles when `dot` or `dotfiles` is set:', function() { - assert(mm.contains('a/b/c/.xyz.md', '.*.md', {dot: true})); assert(mm.contains('.c.md', '*.md', {dot: true})); assert(mm.contains('.c.md', '.*', {dot: true})); assert(mm.contains('a/b/c/.xyz.md', '**/*.md', {dot: true})); assert(mm.contains('a/b/c/.xyz.md', '**/.*.md', {dot: true})); + assert(mm.contains('a/b/c/.xyz.md', '.*.md', {dot: true})); assert(mm.contains('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true})); assert(mm.contains('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true})); }); @@ -143,21 +130,22 @@ describe('.contains()', function() { assert(mm.contains('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); }); - it('question marks should not match slashes:', function() { - assert(!mm.contains('aaa/bbb', 'aaa?bbb')); - }); - it('should match path segments:', function() { assert(mm.contains('aaa', 'aaa')); assert(mm.contains('aaa', 'aa')); assert(mm.contains('aaa/bbb', 'aaa/bbb')); assert(mm.contains('aaa/bbb', 'aaa/*')); - assert(mm.contains('aaa/bba/ccc', 'aaa/*')); - assert(mm.contains('aaa/bba/ccc', 'aaa/**')); + assert(mm.contains('aaa/bba/ccc', '**/*/ccc')); + assert(mm.contains('aaa/bba/ccc', '*/*a')); assert(mm.contains('aaa/bba/ccc', 'aaa*')); assert(mm.contains('aaa/bba/ccc', 'aaa**')); + assert(mm.contains('aaa/bba/ccc', 'aaa/*')); + assert(mm.contains('aaa/bba/ccc', 'aaa/**')); + assert(mm.contains('aaa/bba/ccc', 'aaa/*/ccc')); + assert(mm.contains('aaa/bba/ccc', 'bb')); + assert(mm.contains('aaa/bba/ccc', 'bb*')); assert(!mm.contains('aaa/bba/ccc', 'aaa/*ccc')); - assert(mm.contains('aaa/bba/ccc', 'aaa/**ccc')); + assert(!mm.contains('aaa/bba/ccc', 'aaa/**ccc')); assert(!mm.contains('aaa/bba/ccc', 'aaa/*z')); assert(!mm.contains('aaa/bba/ccc', 'aaa/**z')); assert(mm.contains('aaa/bbb', 'aaa[/]bbb')); @@ -191,4 +179,120 @@ describe('.contains()', function() { assert(!mm.contains('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md')); }); }); + + describe('windows paths', function() { + beforeEach(function() { + path.sep = '\\'; + }); + afterEach(function() { + path.sep = sep; + }); + + it('should match with common glob patterns', function() { + assert(mm.contains('a\\b\\c', 'a/*')); + assert(mm.contains('\\ab', '/a')); + assert(mm.contains('\\ab', '/*')); + assert(mm.contains('\\cd', '/*')); + assert(mm.contains('\\ab', '*/a')); + assert(mm.contains('\\ab', '*/')); + assert(mm.contains('\\ab', '*/*')); + assert(mm.contains('\\ab', '/')); + assert(mm.contains('\\ab', '/??')); + assert(mm.contains('\\ab', '/?b')); + assert(mm.contains('\\ab', '/?')); + assert(mm.contains('a\\b', '?/?')); + }); + + it('should match files that contain the given extension:', function() { + assert(mm.contains('a\\b\\c.md', '**/*.md')); + assert(mm.contains('a\\b\\c.md', '*.md')); + assert(mm.contains('a\\b\\c.md', '.md')); + assert(mm.contains('a\\b\\c.md', 'a/*/*.md')); + assert(mm.contains('a\\b\\c\\c.md', '*.md')); + }); + + it('should match dotfiles when `dot` or `dotfiles` is set:', function() { + assert(mm.contains('a\\b\\c\\.xyz.md', '.*.md', {unixify: true, dot: true})); + assert(mm.contains('a\\b\\c\\.xyz.md', '**/*.md', {unixify: true, dot: true})); + assert(mm.contains('a\\b\\c\\.xyz.md', '**/.*.md', {unixify: true, dot: true})); + assert(mm.contains('a\\b\\c\\.xyz.md', 'a/b/c/*.md', {unixify: true, dot: true})); + assert(mm.contains('a\\b\\c\\.xyz.md', 'a/b/c/.*.md', {unixify: true, dot: true})); + }); + + it('should not match dotfiles when `dot` or `dotfiles` is not set:', function() { + assert(!mm.contains('a\\b\\d\\.md', 'a/b/c/*.md')); + }); + + it('should match file paths:', function() { + assert(mm.contains('a\\b\\c\\xyz.md', 'a/b/c/*.md')); + assert(mm.contains('a\\bb\\c\\xyz.md', 'a/*/c/*.md')); + assert(mm.contains('a\\bbbb\\c\\xyz.md', 'a/*/c/*.md')); + assert(mm.contains('a\\bb.bb\\c\\xyz.md', 'a/*/c/*.md')); + assert(mm.contains('a\\bb.bb\\aa\\bb\\aa\\c\\xyz.md', 'a/**/c/*.md')); + assert(mm.contains('a\\bb.bb\\aa\\b.b\\aa\\c\\xyz.md', 'a/**/c/*.md')); + }); + + it('should return true when full file paths are matched:', function() { + assert(mm.contains('a\\.b', 'a/.*')); + assert(mm.contains('a\\.b', 'a/')); + assert(mm.contains('a\\b\\z\\.a', 'b/z')); + assert(mm.contains('a\\b\\z\\.a', 'a/*/z/.a')); + assert(mm.contains('a\\b\\c\\d\\e\\z\\c.md', 'a/**/z/*.md')); + assert(mm.contains('a\\b\\c\\d\\e\\z\\c.md', 'b/c/d/e')); + assert(mm.contains('a\\b\\c\\d\\e\\j\\n\\p\\o\\z\\c.md', 'a/**/j/**/z/*.md')); + }); + + it('should match path segments:', function() { + assert(mm.contains('aaa\\bbb', 'aaa/bbb')); + assert(mm.contains('aaa\\bbb', 'aaa/*')); + assert(mm.contains('aaa\\bba\\ccc', '**/*/ccc')); + assert(mm.contains('aaa\\bba\\ccc', '*/*a')); + assert(mm.contains('aaa\\bba\\ccc', 'aaa*')); + assert(mm.contains('aaa\\bba\\ccc', 'aaa**')); + assert(mm.contains('aaa\\bba\\ccc', 'aaa/*')); + assert(mm.contains('aaa\\bba\\ccc', 'aaa/**')); + assert(mm.contains('aaa\\bba\\ccc', 'aaa/*/ccc')); + assert(mm.contains('aaa\\bba\\ccc', 'bb')); + assert(mm.contains('aaa\\bba\\ccc', 'bb*')); + assert(mm.contains('aaa\\bbb', 'aaa[/]bbb')); + assert(mm.contains('aaa\\bbb', 'aaa[\\\\/]bbb')); + assert(!mm.contains('aaa\\bba\\ccc', 'aaa/*ccc')); + assert(!mm.contains('aaa\\bba\\ccc', 'aaa/**ccc')); + assert(!mm.contains('aaa\\bba\\ccc', 'aaa/*z')); + assert(!mm.contains('aaa\\bba\\ccc', 'aaa/**z')); + assert(!mm.contains('\\aaa', '*/*/*')); + assert(!mm.contains('aaa\\bbb', '*/*/*')); + assert(mm.contains('aaa\\bba\\ccc', '*/*/*')); + assert(mm.contains('aaa\\bb\\aa\\rr', '*/*/*')); + assert(mm.contains('ab\\zzz\\ejkl\\hi', '*/*z*/*/*i')); + assert(mm.contains('ab\\zzz\\ejkl\\hi', '*/*jk*/*i')); + }); + + it('should return false when full file paths are not matched:', function() { + assert(!mm.contains('a\\b\\z\\.a', 'b/a')); + assert(!mm.contains('a\\.b', 'a/**/z/*.md')); + assert(!mm.contains('a\\b\\z\\.a', 'a/**/z/*.a')); + assert(!mm.contains('a\\b\\z\\.a', 'a/*/z/*.a')); + assert(!mm.contains('a\\b\\c\\j\\e\\z\\c.txt', 'a/**/j/**/z/*.md')); + }); + + it('should match dotfiles when a dot is explicitly defined in the pattern:', function() { + assert(mm.contains('a\\.c.md', 'a/.c.md')); + assert(mm.contains('a\\b\\c\\.xyz.md', 'a/b/c/.*.md')); + assert(mm.contains('a\\.c.md', '*.md')); + assert(mm.contains('a\\b\\c\\d.a.md', 'a/b/c/*.md')); + }); + + it('should match paths with leading `./`:', function() { + assert(!mm.contains('.\\.a', 'a/**/z/*.md')); + assert(!mm.contains('.\\a\\b\\c\\d\\e\\z\\c.md', './a/**/j/**/z/*.md')); + assert(mm.contains('.\\a\\b\\c\\d\\e\\j\\n\\p\\o\\z\\c.md', './a/**/j/**/z/*.md')); + assert(mm.contains('.\\a\\b\\c\\d\\e\\z\\c.md', './a/**/z/*.md')); + assert(mm.contains('.\\a\\b\\c\\d\\e\\z\\c.md', 'a/**/z/*.md')); + assert(mm.contains('.\\a\\b\\c\\j\\e\\z\\c.md', './a/**/j/**/z/*.md')); + assert(mm.contains('.\\a\\b\\c\\j\\e\\z\\c.md', 'a/**/j/**/z/*.md')); + assert(mm.contains('.\\a\\b\\z\\.a', './a/**/z/.a')); + assert(mm.contains('.\\a\\b\\z\\.a', 'a/**/z/.a')); + }); + }); }); diff --git a/test/api.isMatch.js b/test/api.isMatch.js new file mode 100644 index 00000000..cce2708d --- /dev/null +++ b/test/api.isMatch.js @@ -0,0 +1,317 @@ +'use strict'; + +var assert = require('assert'); +var mm = require('..'); + +describe('.isMatch():', function() { + describe('error handling:', function() { + it('should throw on bad args', function() { + assert.throws(function() { + mm.isMatch({}); + }, /expected pattern to be a string or regex/); + }); + }); + + describe('matching:', function() { + it('should escape plus signs to match string literals', function() { + assert(mm.isMatch('a+b/src/glimini.js', 'a+b/src/*.js')); + assert(mm.isMatch('+b/src/glimini.js', '+b/src/*.js')); + assert(mm.isMatch('coffee+/src/glimini.js', 'coffee+/src/*.js')); + assert(mm.isMatch('coffee+/src/glimini.js', 'coffee+/src/*.js')); + assert(mm.isMatch('coffee+/src/glimini.js', 'coffee+/src/*')); + }); + + it('should not escape plus signs that follow brackets', function() { + assert(mm.isMatch('a', '[a]+')); + assert(mm.isMatch('aa', '[a]+')); + assert(mm.isMatch('aaa', '[a]+')); + assert(mm.isMatch('az', '[a-z]+')); + assert(mm.isMatch('zzz', '[a-z]+')); + }); + + it('should support stars following brackets', function() { + assert(mm.isMatch('a', '[a]*')); + assert(mm.isMatch('aa', '[a]*')); + assert(mm.isMatch('aaa', '[a]*')); + assert(mm.isMatch('az', '[a-z]*')); + assert(mm.isMatch('zzz', '[a-z]*')); + }); + + it('should not escape plus signs that follow parens', function() { + assert(mm.isMatch('a', '(a)+')); + assert(mm.isMatch('ab', '(a|b)+')); + assert(mm.isMatch('aa', '(a)+')); + assert(mm.isMatch('aaab', '(a|b)+')); + assert(mm.isMatch('aaabbb', '(a|b)+')); + }); + + it('should support stars following parens', function() { + assert(mm.isMatch('a', '(a)*')); + assert(mm.isMatch('ab', '(a|b)*')); + assert(mm.isMatch('aa', '(a)*')); + assert(mm.isMatch('aaab', '(a|b)*')); + assert(mm.isMatch('aaabbb', '(a|b)*')); + }); + + it('should not match slashes with single stars', function() { + assert(!mm.isMatch('a/b', '(a)*')); + assert(!mm.isMatch('a/b', '[a]*')); + assert(!mm.isMatch('a/b', 'a*')); + assert(!mm.isMatch('a/b', '(a|b)*')); + }); + + it('should not match dots with stars by default', function() { + assert(!mm.isMatch('.a', '(a)*')); + assert(!mm.isMatch('.a', '*[a]*')); + assert(!mm.isMatch('.a', '*[a]')); + assert(!mm.isMatch('.a', '*a*')); + assert(!mm.isMatch('.a', '*a')); + assert(!mm.isMatch('.a', '*(a|b)')); + }); + + it('should correctly deal with empty globs', function() { + assert(!mm.isMatch('ab', '')); + assert(!mm.isMatch('a', '')); + assert(!mm.isMatch('.', '')); + }); + + it('should match with non-glob patterns', function() { + assert(mm.isMatch('.', '.')); + assert(mm.isMatch('/a', '/a')); + assert(!mm.isMatch('/ab', '/a')); + assert(mm.isMatch('a', 'a')); + assert(!mm.isMatch('ab', '/a')); + assert(!mm.isMatch('ab', 'a')); + assert(mm.isMatch('ab', 'ab')); + assert(!mm.isMatch('abcd', 'cd')); + assert(!mm.isMatch('abcd', 'bc')); + assert(!mm.isMatch('abcd', 'ab')); + }); + + it('should match file names', function() { + assert(mm.isMatch('a.b', 'a.b')); + assert(mm.isMatch('a.b', '*.b')); + assert(mm.isMatch('a.b', 'a.*')); + assert(mm.isMatch('a.b', '*.*')); + assert(mm.isMatch('a-b.c-d', 'a*.c*')); + assert(mm.isMatch('a-b.c-d', '*b.*d')); + assert(mm.isMatch('a-b.c-d', '*.*')); + assert(mm.isMatch('a-b.c-d', '*.*-*')); + assert(mm.isMatch('a-b.c-d', '*-*.*-*')); + assert(mm.isMatch('a-b.c-d', '*.c-*')); + assert(mm.isMatch('a-b.c-d', '*.*-d')); + assert(mm.isMatch('a-b.c-d', 'a-*.*-d')); + assert(mm.isMatch('a-b.c-d', '*-b.c-*')); + assert(mm.isMatch('a-b.c-d', '*-b*c-*')); + + // false + assert(!mm.isMatch('a-b.c-d', '*-bc-*')); + }); + + it('should match with common glob patterns', function() { + assert(mm.isMatch('/ab', '/*')); + assert(mm.isMatch('/cd', '/*')); + assert(!mm.isMatch('ef', '/*')); + assert(mm.isMatch('ab', './*')); + assert(mm.isMatch('ab/', './*/')); + assert(!mm.isMatch('ab', './*/')); + assert(mm.isMatch('ab', '*')); + assert(mm.isMatch('ab', 'ab')); + }); + + it('should exactly match leading slash', function() { + assert(!mm.isMatch('ef', '/*')); + assert(mm.isMatch('/ef', '/*')); + }); + + it('should match files with the given extension', function() { + assert(!mm.isMatch('.md', '*.md')); + assert(mm.isMatch('.md', '.md')); + assert(!mm.isMatch('.c.md', '*.md')); + assert(mm.isMatch('.c.md', '.*.md')); + assert(mm.isMatch('c.md', '*.md')); + assert(mm.isMatch('c.md', '*.md')); + assert(!mm.isMatch('a/b/c/c.md', '*.md')); + assert(!mm.isMatch('a/b/c.md', 'a/*.md')); + assert(mm.isMatch('a/b/c.md', 'a/*/*.md')); + assert(mm.isMatch('a/b/c.md', '**/*.md')); + assert(mm.isMatch('a/b/c.js', 'a/**/*.*')); + }); + + it('should match wildcards', function() { + assert(!mm.isMatch('a/b/c/z.js', '*.js')); + assert(!mm.isMatch('a/b/z.js', '*.js')); + assert(!mm.isMatch('a/z.js', '*.js')); + assert(mm.isMatch('z.js', '*.js')); + + assert(mm.isMatch('z.js', 'z*.js')); + assert(mm.isMatch('a/z.js', 'a/z*.js')); + assert(mm.isMatch('a/z.js', '*/z*.js')); + }); + + it('should match globstars', function() { + assert(mm.isMatch('a/b/c/z.js', '**/*.js')); + assert(mm.isMatch('a/b/z.js', '**/*.js')); + assert(mm.isMatch('a/z.js', '**/*.js')); + assert(mm.isMatch('a/b/c/d/e/z.js', 'a/b/**/*.js')); + assert(mm.isMatch('a/b/c/d/z.js', 'a/b/**/*.js')); + assert(mm.isMatch('a/b/c/z.js', 'a/b/c/**/*.js')); + assert(mm.isMatch('a/b/c/z.js', 'a/b/c**/*.js')); + assert(mm.isMatch('a/b/c/z.js', 'a/b/**/*.js')); + assert(mm.isMatch('a/b/z.js', 'a/b/**/*.js')); + + assert(!mm.isMatch('a/z.js', 'a/b/**/*.js')); + assert(!mm.isMatch('z.js', 'a/b/**/*.js')); + + // issue #23 + assert(!mm.isMatch('zzjs', 'z*.js')); + assert(!mm.isMatch('zzjs', '*z.js')); + + // issue #24 + assert(mm.isMatch('a', '**')); + assert(!mm.isMatch('a', 'a/**')); + assert(mm.isMatch('a/', '**')); + assert(mm.isMatch('a/b/c/d', '**')); + assert(mm.isMatch('a/b/c/d/', '**')); + assert(mm.isMatch('a/b/c/d/', '**/**')); + assert(mm.isMatch('a/b/c/d/', '**/b/**')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**/')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**/c/**/')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**/c/**/d/')); + assert(!mm.isMatch('a/b/c/d/', 'a/b/**/f')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/**/*.*')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/*.*')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/c/**/d/*.*')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/d/**/*.*')); + assert(mm.isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*')); + assert(mm.isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*')); + + // https://github.com/jonschlinkert/micromatch/issues/15 + assert(mm.isMatch('z.js', 'z*')); + assert(mm.isMatch('z.js', '**/z*')); + assert(mm.isMatch('z.js', '**/z*.js')); + assert(mm.isMatch('z.js', '**/*.js')); + assert(mm.isMatch('foo', '**/foo')); + + assert(mm.isMatch('a/b-c/z.js', 'a/b-*/**/z.js')); + assert(mm.isMatch('a/b-c/d/e/z.js', 'a/b-*/**/z.js')); + }); + + it('should match slashes', function() { + assert(!mm.isMatch('bar/baz/foo', '*/foo')); + assert(!mm.isMatch('deep/foo/bar', '**/bar/*')); + assert(!mm.isMatch('deep/foo/bar/baz/x', '*/bar/**')); + assert(!mm.isMatch('foo', 'foo/**')); + assert(!mm.isMatch('foo/bar', 'foo?bar')); + assert(!mm.isMatch('foo/bar/baz', '**/bar*')); + assert(!mm.isMatch('foo/bar/baz', '**/bar**')); + assert(!mm.isMatch('foo/baz/bar', 'foo**bar')); + assert(!mm.isMatch('foo/baz/bar', 'foo*bar')); + assert(mm.isMatch('a/b/j/c/z/x.md', 'a/**/j/**/z/*.md')); + assert(mm.isMatch('a/j/z/x.md', 'a/**/j/**/z/*.md')); + assert(mm.isMatch('bar/baz/foo', '**/foo')); + assert(mm.isMatch('deep/foo/bar/', '**/bar/**')); + assert(mm.isMatch('deep/foo/bar/baz', '**/bar/*')); + assert(mm.isMatch('deep/foo/bar/baz/', '**/bar/*')); + assert(mm.isMatch('deep/foo/bar/baz/', '**/bar/**')); + assert(mm.isMatch('deep/foo/bar/baz/x', '**/bar/*/*')); + assert(mm.isMatch('foo/b/a/z/bar', 'foo/**/**/bar')); + assert(mm.isMatch('foo/b/a/z/bar', 'foo/**/bar')); + assert(mm.isMatch('foo/bar', 'foo/**/**/bar')); + assert(mm.isMatch('foo/bar', 'foo/**/bar')); + assert(mm.isMatch('foo/bar', 'foo[/]bar')); + assert(mm.isMatch('foo/bar/baz/x', '*/bar/**')); + assert(mm.isMatch('foo/baz/bar', 'foo/**/**/bar')); + assert(mm.isMatch('foo/baz/bar', 'foo/**/bar')); + assert(mm.isMatch('foobazbar', 'foo**bar')); + assert(mm.isMatch('XXX/foo', '**/foo')); + }); + + it('question marks should not match slashes', function() { + assert(!mm.isMatch('aaa/bbb', 'aaa?bbb')); + }); + + it('should not match dotfiles when `dot` or `dotfiles` are not set', function() { + assert(!mm.isMatch('.c.md', '*.md')); + assert(!mm.isMatch('a/.c.md', '*.md')); + assert(mm.isMatch('a/.c.md', 'a/.c.md')); + assert(!mm.isMatch('.a', '*.md')); + assert(!mm.isMatch('.verb.txt', '*.md')); + assert(mm.isMatch('a/b/c/.xyz.md', 'a/b/c/.*.md')); + assert(mm.isMatch('.md', '.md')); + assert(!mm.isMatch('.txt', '.md')); + assert(mm.isMatch('.md', '.md')); + assert(mm.isMatch('.a', '.a')); + assert(mm.isMatch('.b', '.b*')); + assert(mm.isMatch('.ab', '.a*')); + assert(mm.isMatch('.ab', '.*')); + assert(!mm.isMatch('.ab', '*.*')); + assert(!mm.isMatch('.md', 'a/b/c/*.md')); + assert(!mm.isMatch('.a.md', 'a/b/c/*.md')); + assert(mm.isMatch('a/b/c/d.a.md', 'a/b/c/*.md')); + assert(!mm.isMatch('a/b/d/.md', 'a/b/c/*.md')); + }); + + it('should match dotfiles when `dot` or `dotfiles` is set', function() { + assert(mm.isMatch('.c.md', '*.md', {dot: true})); + assert(mm.isMatch('.c.md', '.*', {dot: true})); + assert(mm.isMatch('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true})); + assert(mm.isMatch('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true})); + }); + + it('should match file paths', function() { + assert(mm.isMatch('a/b/c/xyz.md', 'a/b/c/*.md')); + assert(mm.isMatch('a/bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.isMatch('a/bbbb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.isMatch('a/bb.bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.isMatch('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md')); + assert(mm.isMatch('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md')); + }); + + it('should match full file paths', function() { + assert(!mm.isMatch('a/.b', 'a/**/z/*.md')); + assert(mm.isMatch('a/.b', 'a/.*')); + assert(!mm.isMatch('a/b/z/.a', 'a/**/z/*.a')); + assert(!mm.isMatch('a/b/z/.a', 'a/*/z/*.a')); + assert(mm.isMatch('a/b/z/.a', 'a/*/z/.a')); + assert(mm.isMatch('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.isMatch('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); + assert(!mm.isMatch('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md')); + }); + + it('should match paths with leading `./` when pattern has `./`', function() { + assert(mm.isMatch('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/z/*.md')); + assert(mm.isMatch('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.isMatch('./a/b/z/.a', './a/**/z/.a')); + // sanity checks + assert(!mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md')); + assert(!mm.isMatch('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md')); + }); + + it('should match paths with leading `./`', function() { + assert(!mm.isMatch('./.a', '*.a')); + assert(!mm.isMatch('./.a', './*.a')); + assert(!mm.isMatch('./.a', 'a/**/z/*.md')); + assert(!mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md')); + assert(!mm.isMatch('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md')); + assert(!mm.isMatch('a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.isMatch('./.a', './.a')); + assert(mm.isMatch('./a/b/c.md', 'a/**/*.md')); + assert(mm.isMatch('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.isMatch('./a/b/c/d/e/z/c.md', '**/*.md')); + assert(mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/z/*.md')); + assert(mm.isMatch('./a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.isMatch('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md')); + assert(mm.isMatch('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md')); + assert(mm.isMatch('./a/b/z/.a', './a/**/z/.a')); + assert(mm.isMatch('./a/b/z/.a', 'a/**/z/.a')); + assert(mm.isMatch('.a', './.a')); + assert(mm.isMatch('a/b/c.md', './a/**/*.md')); + assert(mm.isMatch('a/b/c.md', 'a/**/*.md')); + assert(mm.isMatch('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.isMatch('a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md')); + }); + }); +}); diff --git a/test/api.js b/test/api.js new file mode 100644 index 00000000..292bef63 --- /dev/null +++ b/test/api.js @@ -0,0 +1,153 @@ +'use strict'; + +var path = require('path'); +var sep = path.sep; +var mm = require('./support/match'); + +describe('micromatch', function() { + describe('posix paths', function() { + it('should return an array of matches for a literal string', function() { + mm(['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c'], '(a/b)', ['a/b']); + mm(['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c'], 'a/b', ['a/b']); + }); + + it('should return an array of matches for an array of literal strings', function() { + mm(['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c'], ['(a/b)', 'a/c'], ['a/b', 'a/c']); + mm(['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c'], ['a/b', 'b/b'], ['a/b', 'b/b']); + }); + + it('should support regex logical or', function() { + mm(['a/a', 'a/b', 'a/c'], ['a/(a|c)'], ['a/a', 'a/c']); + mm(['a/a', 'a/b', 'a/c'], ['a/(a|b|c)', 'a/b'], ['a/a', 'a/b', 'a/c']); + }); + + it('should support regex ranges', function() { + mm(['a/a', 'a/b', 'a/c'], 'a/[b-c]', ['a/b', 'a/c']); + mm(['a/a', 'a/b', 'a/c', 'a/x/y', 'a/x'], 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + }); + + it('should support single globs (*)', function() { + var fixtures = ['a', 'b', 'a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a', 'x/y', 'z/z']; + mm(fixtures, ['*'], ['a', 'b']); + mm(fixtures, ['*/*'], ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); + mm(fixtures, ['*/*/*'], ['a/a/a', 'a/a/b']); + mm(fixtures, ['*/*/*/*'], ['a/a/a/a']); + mm(fixtures, ['*/*/*/*/*'], ['a/a/a/a/a']); + mm(fixtures, ['a/*'], ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, ['a/*/*'], ['a/a/a', 'a/a/b']); + mm(fixtures, ['a/*/*/*'], ['a/a/a/a']); + mm(fixtures, ['a/*/*/*/*'], ['a/a/a/a/a']); + mm(fixtures, ['a/*/a'], ['a/a/a']); + mm(fixtures, ['a/*/b'], ['a/a/b']); + }); + + it('should support globstars (**)', function() { + var fixtures = ['a', 'a/', 'a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']; + mm(fixtures, ['*'], ['a', 'a/']); + mm(fixtures, ['*/'], ['a/']); + mm(fixtures, ['*/*'], ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, ['**'], fixtures); + mm(fixtures, ['**/a'], ['a', 'a/', 'a/a']); + mm(fixtures, ['a/*'], ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, ['a/**'], ['a/', 'a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + mm(fixtures, ['a/**/*'], ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + mm(fixtures, ['a/**/**/*'], ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + mm(['a/b/foo/bar/baz.qux'], 'a/b/**/bar/**/*.*', ['a/b/foo/bar/baz.qux']); + mm(['a/b/bar/baz.qux'], 'a/b/**/bar/**/*.*', ['a/b/bar/baz.qux']); + }); + + it('should support negation patterns', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + mm(fixtures, ['!a/b'], ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, ['*/*', '!a/b', '!*/c'], ['a/a', 'b/a', 'b/b']); + mm(fixtures, ['!a/b', '!*/c'], ['a/a', 'b/a', 'b/b']); + mm(fixtures, ['!a/b', '!a/c'], ['a/a', 'b/a', 'b/b', 'b/c']); + mm(fixtures, ['!a/(b)'], ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, ['!(a/b)'], ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + }); + + it('should work with file extensions', function() { + var fixtures = ['a.txt', 'a/b.txt', 'a/x/y.txt', 'a/x/y/z']; + mm(fixtures, ['a/**/*.txt'], ['a/b.txt', 'a/x/y.txt']); + mm(fixtures, ['a/*.txt'], ['a/b.txt']); + mm(fixtures, ['a*.txt'], ['a.txt']); + mm(fixtures, ['*.txt'], ['a.txt']); + }); + }); + + describe('windows paths', function() { + beforeEach(function() { + path.sep = '\\'; + }); + afterEach(function() { + path.sep = sep; + }); + + it('should return an array of matches for a literal string', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + mm(fixtures, '(a/b)', ['a/b']); + mm(fixtures, 'a/b', ['a/b']); + }); + + it('should return an array of matches for an array of literal strings', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + mm(fixtures, ['(a/b)', 'a/c'], ['a/b', 'a/c']); + mm(fixtures, ['a/b', 'b/b'], ['a/b', 'b/b']); + }); + + it('should support regex logical or', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c']; + mm(fixtures, ['a/(a|c)'], ['a/a', 'a/c']); + mm(fixtures, ['a/(a|b|c)', 'a/b'], ['a/a', 'a/b', 'a/c']); + }); + + it('should support regex ranges', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x\\y', 'a\\x']; + mm(fixtures, 'a/[b-c]', ['a/b', 'a/c']); + mm(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + }); + + it('should support single globs (*)', function() { + var fixtures = ['a', 'b', 'a\\a', 'a\\b', 'a\\c', 'a\\x', 'a\\a\\a', 'a\\a\\b', 'a\\a\\a\\a', 'a\\a\\a\\a\\a', 'x\\y', 'z\\z']; + mm(fixtures, ['*'], ['a', 'b']); + mm(fixtures, ['*/*'], ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); + mm(fixtures, ['*/*/*'], ['a/a/a', 'a/a/b']); + mm(fixtures, ['*/*/*/*'], ['a/a/a/a']); + mm(fixtures, ['*/*/*/*/*'], ['a/a/a/a/a']); + mm(fixtures, ['a/*'], ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, ['a/*/*'], ['a/a/a', 'a/a/b']); + mm(fixtures, ['a/*/*/*'], ['a/a/a/a']); + mm(fixtures, ['a/*/*/*/*'], ['a/a/a/a/a']); + mm(fixtures, ['a/*/a'], ['a/a/a']); + mm(fixtures, ['a/*/b'], ['a/a/b']); + }); + + it('should support globstars (**)', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x', 'a\\x\\y', 'a\\x\\y\\z']; + var expected = ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']; + mm(fixtures, ['a/**'], expected); + mm(fixtures, ['a/**/*'], expected); + mm(fixtures, ['a/**/**/*'], expected); + }); + + it('should work with file extensions', function() { + var fixtures = ['a.txt', 'a\\b.txt', 'a\\x\\y.txt', 'a\\x\\y\\z']; + mm(fixtures, ['a/**/*.txt'], ['a/b.txt', 'a/x/y.txt']); + mm(fixtures, ['a/*/*.txt'], ['a/x/y.txt']); + mm(fixtures, ['a/*.txt'], ['a/b.txt']); + mm(fixtures, ['a*.txt'], ['a.txt']); + mm(fixtures, ['a.txt'], ['a.txt']); + }); + + it('should support negation patterns', function() { + var fixtures = ['a', 'a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + mm(fixtures, ['!a/b'], ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, ['*/*', '!a/b', '!*/c'], ['a/a', 'b/a', 'b/b']); + mm(fixtures, ['!*/c'], ['a', 'a/a', 'a/b', 'b/a', 'b/b']); + mm(fixtures, ['!a/b', '!*/c'], ['a', 'a/a', 'b/a', 'b/b']); + mm(fixtures, ['!a/b', '!a/c'], ['a', 'a/a', 'b/a', 'b/b', 'b/c']); + mm(fixtures, ['!a/(b)'], ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, ['!(a/b)'], ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + }); + }); +}); diff --git a/test/api.match.js b/test/api.match.js new file mode 100644 index 00000000..5d6f28f8 --- /dev/null +++ b/test/api.match.js @@ -0,0 +1,69 @@ +'use strict'; + +var match = require('./support/match'); + +describe('.match method', function() { + describe('posix paths', function() { + it('should return an array of matches for a literal string', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + match(fixtures, '(a/b)', ['a/b']); + match(fixtures, 'a/b', ['a/b']); + }); + + it('should support regex logical or', function() { + var fixtures = ['a/a', 'a/b', 'a/c']; + match(fixtures, 'a/(a|c)', ['a/a', 'a/c']); + match(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); + }); + + it('should support regex ranges', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'a/x/y', 'a/x']; + match(fixtures, 'a/[b-c]', ['a/b', 'a/c']); + match(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + }); + + it('should support negation patterns', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + match(fixtures, '!*/*', []); + match(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); + match(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); + match(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + match(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + match(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); + match(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); + match(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + }); + }); + + describe('unix paths', function() { + it('should return an array of matches for a literal string', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + match(fixtures, '(a/b)', ['a/b']); + match(fixtures, 'a/b', ['a/b']); + }); + + it('should support regex logical or', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c']; + match(fixtures, 'a/(a|c)', ['a/a', 'a/c']); + match(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); + }); + + it('should support regex ranges', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x\\y', 'a\\x']; + match(fixtures, 'a/[b-c]', ['a/b', 'a/c']); + match(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + }); + + it('should support negation patterns', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + match(fixtures, '!*/*', []); + match(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); + match(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); + match(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + match(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + match(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); + match(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); + match(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + }); + }); +}); diff --git a/test/api.matchKeys.js b/test/api.matchKeys.js new file mode 100644 index 00000000..a27c4a74 --- /dev/null +++ b/test/api.matchKeys.js @@ -0,0 +1,40 @@ +'use strict'; + +var assert = require('assert'); +var mm = require('..'); + +describe('.matchKeys method', function() { + describe('error handling', function() { + it('should throw when the first argument is not an object', function() { + assert.throws(function() { + mm.matchKeys(); + }, /expected the first argument to be an object/); + + assert.throws(function() { + mm.matchKeys('foo'); + }, /expected the first argument to be an object/); + + assert.throws(function() { + mm.matchKeys(['foo']); + }, /expected the first argument to be an object/); + }); + }); + + describe('match object keys', function() { + it('should return a new object with only keys that match the given glob pattern', function() { + assert.deepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, '*'), {a: 'a', b: 'b', c: 'c'}); + assert.deepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, 'a'), {a: 'a'}); + assert.deepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, '[a-b]'), {a: 'a', b: 'b'}); + assert.deepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, '(a|c)'), {a: 'a', c: 'c'}); + assert.notDeepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, 'a'), {b: 'b'}); + }); + + it('should return a new object with only keys that match a regex:', function() { + assert.deepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /.*/), {a: 'a', b: 'b', c: 'c'}); + assert.deepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /a/), {a: 'a'}); + assert.deepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /[a-b]/), {a: 'a', b: 'b'}); + assert.deepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /(a|c)/), {a: 'a', c: 'c'}); + assert.notDeepEqual(mm.matchKeys({a: 'a', b: 'b', c: 'c'}, /a/), {b: 'b'}); + }); + }); +}); diff --git a/test/api.not.js b/test/api.not.js new file mode 100644 index 00000000..5a85e99e --- /dev/null +++ b/test/api.not.js @@ -0,0 +1,121 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var argv = require('yargs-parser')(process.argv.slice(2)); +var matcher = argv.mm ? require('minimatch') : require('..'); +var compare = require('./support/compare'); +var sep = path.sep; + +function match(arr, pattern, expected, options) { + var actual = matcher.not(arr, pattern, options); + expected.sort(compare); + actual.sort(compare); + assert.deepEqual(actual, expected); +} + +describe('.not method', function() { + describe('posix paths', function() { + it('should return an array of matches for a literal string', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + match(fixtures, '(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + match(fixtures, 'a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + }); + + it('should support regex logical or', function() { + var fixtures = ['a/a', 'a/b', 'a/c']; + match(fixtures, 'a/(a|c)', ['a/b']); + match(fixtures, 'a/(a|b|c)', []); + }); + + it('should support regex ranges', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'a/x/y', 'a/x']; + match(fixtures, 'a/[b-c]', ['a/a', 'a/x/y', 'a/x']); + match(fixtures, 'a/[a-z]', ['a/x/y']); + }); + + it('should support globs (*)', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']; + match(fixtures, 'a/*', ['a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + match(fixtures, 'a/*/a', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + match(fixtures, 'a/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a/a', 'a/a/a/a/a']); + match(fixtures, 'a/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a/a']); + match(fixtures, 'a/*/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a']); + }); + + it('should support globstars (**)', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']; + match(fixtures, 'a/**', []); + match(fixtures, 'a/**/*', []); + match(fixtures, 'a/**/**/*', []); + }); + + it('should support negation patterns', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + match(fixtures, '!a/b', ['a/b']); + match(fixtures, '!a/(b)', ['a/b']); + match(fixtures, '!(a/b)', ['a/b']); + }); + }); + + describe('windows paths', function() { + beforeEach(function() { + path.sep = '\\'; + }); + afterEach(function() { + path.sep = sep; + }); + + it('should return an array of matches for a literal string', function() { + var fixtures = ['a', 'a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + match(fixtures, '(a/b)', ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + match(fixtures, 'a/b', ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + }); + + it('should support regex logical or', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c']; + match(fixtures, 'a/(a|c)', ['a/b']); + match(fixtures, 'a/(a|b|c)', []); + }); + + it('should support regex ranges', function() { + var fixtures = ['.\\a\\a', 'a\\a', 'a\\b', 'a\\c', 'a\\x\\y', 'a\\x']; + match(fixtures, '[a-c]/[a-c]', ['a/x', 'a/x/y']); + match(fixtures, 'a/[b-c]', ['a/a', 'a/x', 'a/x/y']); + match(fixtures, 'a/[a-z]', ['a/x/y']); + }); + + it('should support globs (*)', function() { + var fixtures = ['a\\a', 'a/a', 'a\\b', '.\\a\\b', 'a\\c', 'a\\x', 'a\\a\\a', 'a\\a\\b', 'a\\a\\a\\a', 'a\\a\\a\\a\\a']; + match(fixtures, 'a/*', ['a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + match(fixtures, 'a/*/a', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + match(fixtures, 'a/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a/a', 'a/a/a/a/a']); + match(fixtures, 'a/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a/a']); + match(fixtures, 'a/*/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a']); + }); + + it('should support globstars (**)', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x', 'a\\x\\y', 'a\\x\\y\\z']; + var expected = ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']; + match(fixtures, '*', expected); + match(fixtures, '**', []); + match(fixtures, '*/*', ['a/x/y', 'a/x/y/z']); + match(fixtures, 'a/**', []); + match(fixtures, 'a/x/**', ['a/a', 'a/b', 'a/c', 'a/x']); + match(fixtures, 'a/**/*', []); + match(fixtures, 'a/**/**/*', []); + }); + + it('should support negation patterns', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + var expected = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + match(fixtures, '!**', expected); + match(fixtures, '!*/*', expected); + match(fixtures, '!*', []); + match(fixtures, '!a/b', ['a/b']); + match(fixtures, '!a/(b)', ['a/b']); + match(fixtures, '!(a/b)', ['a/b']); + }); + }); +}); + diff --git a/test/bash.js b/test/bash.js new file mode 100644 index 00000000..c5bc5697 --- /dev/null +++ b/test/bash.js @@ -0,0 +1,218 @@ +'use strict'; + +require('mocha'); +var assert = require('assert'); +var mm = require('./support/match'); + +/** + * Heads up! In these tests, `mm` is a custom function that can + * be either `micromatch` or `minimatch` if the `--mm` flag is passed + */ + +// from the Bash 4.3 specification/unit tests +var fixtures = ['a', 'b', 'c', 'd', 'abc', 'abd', 'abe', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'Beware', 'bdir/', '*', '\\*']; + +describe('bash options and features:', function() { + describe('failglob:', function() { + it('should throw an error when no matches are found:', function() { + assert.throws(function() { + require('..').match(fixtures, '\\^', {failglob: true}); + }, /no matches found for/); + }); + }); + + // $echo a/{1..3}/b + describe('bash', function() { + it('should handle "regular globbing":', function() { + mm(fixtures, 'a*', ['a', 'abc', 'abd', 'abe']); + mm(fixtures, '\\a*', ['a', 'abc', 'abd', 'abe']); + }); + + it('should match directories:', function() { + mm(fixtures, 'b*/', ['bdir/']); + }); + + it('should use quoted characters as literals:', function() { + mm(fixtures, '\\*', {nonull: true}, ['*', '\\*']); + mm(fixtures, '\\^', {nonull: true}, ['\\^']); + mm(fixtures, '\\^', []); + + mm(fixtures, 'a\\*', {nonull: true}, ['a\\*']); + mm(fixtures, 'a\\*', ['a*'], {nonull: true, unescape: true}); + mm(fixtures, 'a\\*', []); + + mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['a\\*', '*', '\\*']); + mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*']); + mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*']); + mm(fixtures, ['a\\*', '\\*'], ['*', '\\*']); + + mm(fixtures, ['a\\*'], {nonull: true}, ['a\\*']); + mm(fixtures, ['a\\*'], []); + + mm(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a\\*', '*q*']); + mm(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); + + mm(fixtures, '"*"*', {nonull: true}, ['"*"*']); + mm(fixtures, '"*"*', []); + + mm(fixtures, '\\**', ['*']); // `*` is in the fixtures array + }); + + it('should work for escaped paths/dots:', function() { + mm(fixtures, '"\\.\\./*/"', {nonull: true}, ['"\\.\\./*/"']); + mm(fixtures, '"\\.\\./*/"', {nonull: true, unescape: true}, ['"../*/"']); + mm(fixtures, 's/\\..*//', {nonull: true}, ['s/\\..*//']); + }); + + it('Pattern from Larry Wall\'s Configure that caused bash to blow up:', function() { + mm(fixtures, '"/^root:/{s/^[^:]*:[^:]*:\\([^:]*\\).*"\'$\'"/\\1/"', {nonull: true}, ['"/^root:/{s/^[^:]*:[^:]*:\\([^:]*\\).*"\'$\'"/\\1/"']); + mm(fixtures, '[a-c]b*', ['abc', 'abd', 'abe', 'bb', 'cb']); + }); + + it('should support character classes', function() { + var f = fixtures.slice(); + f.push('baz', 'bzz', 'BZZ', 'beware', 'BewAre'); + mm(f, '[a-y]*[^c]', ['abd', 'abe', 'baz', 'beware', 'bzz', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); + mm(f, 'a*[^c]', ['abd', 'abe']); + mm(['a-b', 'aXb'], 'a[X-]b', ['a-b', 'aXb']); + mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '\\*']); + mm(['a*b/ooo'], 'a\\*b/*', ['a*b/ooo']); + mm(['a*b/ooo'], 'a\\*?/*', ['a*b/ooo']); + mm(f, 'a[b]c', ['abc']); + mm(f, 'a["b"]c', ['abc']); + mm(f, 'a[\\\\b]c', ['abc']); + mm(f, 'a[b-d]c', ['abc']); + mm(f, 'a?c', ['abc']); + mm(['a-b'], 'a[]-]b', ['a-b']); + mm(['man/man1/bash.1'], '*/man*/bash.*', ['man/man1/bash.1']); + }); + + it('should support basic wildmatch (brackets) features', function() { + assert(!mm.isMatch('aab', 'a[]-]b')); + assert(!mm.isMatch('ten', '[ten]')); + assert(!mm.isMatch('ten', 't[!a-g]n')); + assert(mm.isMatch(']', ']')); + assert(mm.isMatch('a-b', 'a[]-]b')); + assert(mm.isMatch('a]b', 'a[]-]b')); + assert(mm.isMatch('a]b', 'a[]]b')); + assert(mm.isMatch('aab', 'a[\\]a\\-]b')); + assert(mm.isMatch('ten', 't[a-g]n')); + assert(mm.isMatch('ton', 't[!a-g]n')); + assert(mm.isMatch('ton', 't[^a-g]n')); + }); + + it('should support Extended slash-matching features', function() { + assert(!mm.isMatch('foo/bar', 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r')); + assert(mm.isMatch('foo/bar', 'foo[/]bar')); + assert(mm.isMatch('foo-bar', 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r')); + }); + + it('should match braces', function() { + assert(mm.isMatch('foo{}baz', 'foo[{a,b}]+baz')); + }); + + it('should match parens', function() { + assert(mm.isMatch('foo(bar)baz', 'foo[bar()]+baz')); + }); + + it('should match escaped characters', function() { + assert(!mm.isMatch('', '\\')); + assert(!mm.isMatch('XXX/\\', '[A-Z]+/\\')); + assert(mm.isMatch('\\', '\\')); + assert(mm.isMatch('XXX/\\', '[A-Z]+/\\\\')); + assert(mm.isMatch('[ab]', '\\[ab]')); + assert(mm.isMatch('[ab]', '[\\[:]ab]')); + }); + + it('should match brackets', function() { + assert(!mm.isMatch(']', '[!]-]')); + assert(mm.isMatch('a', '[!]-]')); + assert(mm.isMatch('[ab]', '[[]ab]')); + }); + + it('tests with multiple `*\'s:', function() { + mm(['bbc', 'abc', 'bbd'], 'a**c', ['abc']); + mm(['bbc', 'abc', 'bbd'], 'a***c', ['abc']); + mm(['bbc', 'abc', 'bbc'], 'a*****?c', ['abc']); + mm(['bbc', 'abc'], '?*****??', ['bbc', 'abc']); + mm(['bbc', 'abc'], '*****??', ['bbc', 'abc']); + mm(['bbc', 'abc'], '?*****?c', ['bbc', 'abc']); + mm(['bbc', 'abc', 'bbd'], '?***?****c', ['bbc', 'abc']); + mm(['bbc', 'abc'], '?***?****?', ['bbc', 'abc']); + mm(['bbc', 'abc'], '?***?****', ['bbc', 'abc']); + mm(['bbc', 'abc'], '*******c', ['bbc', 'abc']); + mm(['bbc', 'abc'], '*******?', ['bbc', 'abc']); + mm(['abcdecdhjk'], 'a*cd**?**??k', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a**?**cd**?**??k', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a**?**cd**?**??k***', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a**?**cd**?**??***k', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a**?**cd**?**??***k**', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a****c**?**??*****', ['abcdecdhjk']); + }); + + it('none of these should output anything:', function() { + mm(['abc'], '??**********?****?', []); + mm(['abc'], '??**********?****c', []); + mm(['abc'], '?************c****?****', []); + mm(['abc'], '*c*?**', []); + mm(['abc'], 'a*****c*?**', []); + mm(['abc'], 'a********???*******', []); + mm(['a'], '[]', []); + mm(['['], '[abc', []); + }); + }); + + describe('wildmat', function() { + it('Basic wildmat features', function() { + assert(!mm.isMatch('foo', '*f')); + assert(!mm.isMatch('foo', '??')); + assert(!mm.isMatch('foo', 'bar')); + assert(!mm.isMatch('foobar', 'foo\\*bar')); + assert(mm.isMatch('', '')); + assert(mm.isMatch('?a?b', '\\??\\?b')); + assert(mm.isMatch('aaaaaaabababab', '*ab')); + assert(mm.isMatch('f\\oo', 'f\\oo')); + assert(mm.isMatch('foo', '*')); + assert(mm.isMatch('foo', '*foo*')); + assert(mm.isMatch('foo', '???')); + assert(mm.isMatch('foo', 'f*')); + assert(mm.isMatch('foo', 'foo')); + assert(mm.isMatch('foo*', 'foo\\*', {unixify: false})); + assert(mm.isMatch('foobar', '*ob*a*r*')); + }); + + it('should support recursion', function() { + assert(!mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(!mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(!mm.isMatch('ab/cXd/efXg/hi', '*X*i')); + assert(!mm.isMatch('ab/cXd/efXg/hi', '*Xg*i')); + assert(!mm.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz', '**/*a*b*g*n*t')); + assert(!mm.isMatch('foo', '*/*/*')); + assert(!mm.isMatch('foo', 'fo')); + assert(!mm.isMatch('foo/bar', '*/*/*')); + assert(!mm.isMatch('foo/bar', 'foo?bar')); + assert(!mm.isMatch('foo/bb/aa/rr', '*/*/*')); + assert(!mm.isMatch('foo/bba/arr', 'foo*')); + assert(!mm.isMatch('foo/bba/arr', 'foo**')); + assert(!mm.isMatch('foo/bba/arr', 'foo/*')); + assert(!mm.isMatch('foo/bba/arr', 'foo/**arr')); + assert(!mm.isMatch('foo/bba/arr', 'foo/**z')); + assert(!mm.isMatch('foo/bba/arr', 'foo/*arr')); + assert(!mm.isMatch('foo/bba/arr', 'foo/*z')); + assert(!mm.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*')); + assert(mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(mm.isMatch('ab/cXd/efXg/hi', '**/*X*/**/*i')); + assert(mm.isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i')); + assert(mm.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt', '**/*a*b*g*n*t')); + assert(mm.isMatch('abcXdefXghi', '*X*i')); + assert(mm.isMatch('foo', 'foo')); + assert(mm.isMatch('foo/bar', 'foo/*')); + assert(mm.isMatch('foo/bar', 'foo/bar')); + assert(mm.isMatch('foo/bar', 'foo[/]bar')); + assert(mm.isMatch('foo/bb/aa/rr', '**/**/**')); + assert(mm.isMatch('foo/bba/arr', '*/*/*')); + assert(mm.isMatch('foo/bba/arr', 'foo/**')); + assert(mm.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*', {unixify: false})); + }); + }); +}); diff --git a/test/bash/dotglob.txt b/test/bash/dotglob.txt new file mode 100644 index 00000000..02244187 --- /dev/null +++ b/test/bash/dotglob.txt @@ -0,0 +1,23 @@ +f a/b/.x **/.x/** +f .x **/.x/** +f .x/ **/.x/** +f .x/a **/.x/** +f .x/a/b **/.x/** +f .x/.x **/.x/** +f a/.x **/.x/** + +t a/b/.x/c **/.x/** +t a/b/.x/c/d **/.x/** +t a/b/.x/c/d/e **/.x/** +t a/b/.x/ **/.x/** +t a/.x/b **/.x/** +t a/.x/b/.x/c **/.x/** + +t .bashrc ?bashrc +t .b/ *.* +t .bar.baz/ *.* +t .bar *.* +f .bar !.*.* + +t .bar.baz/ .*.*/ +t .bar.baz/ .*.* diff --git a/test/bash/glob.txt b/test/bash/glob.txt new file mode 100644 index 00000000..e939d496 --- /dev/null +++ b/test/bash/glob.txt @@ -0,0 +1,78 @@ +f a/b/.x **/.x/** +f .x **/.x/** +f .x/ **/.x/** +f .x/a **/.x/** +f .x/a/b **/.x/** +f .x/.x **/.x/** +f a/.x **/.x/** + +t a/b/.x/c **/.x/** +t a/b/.x/c/d **/.x/** +t a/b/.x/c/d/e **/.x/** +t a/b/.x/ **/.x/** +t a/.x/b **/.x/** +t a/.x/b/.x/c **/.x/** + +t a/c/b a/*/b +t a/.d/b a/*/b +t a/./b a/*/b +t a/../b a/*/b + +t ab ab** +t abcdef ab** +t abef ab** +t abcfef ab** + +f ab ab***ef +t abcdef ab***ef +t abef ab***ef +t abcfef ab***ef + +t .bashrc ?bashrc + +f abbc ab?bc +f abc ab?bc + +t a.a [a-d]*.[a-b] +t a.b [a-d]*.[a-b] +t c.a [a-d]*.[a-b] +t a.a.a [a-d]*.[a-b] + +f a.a !*.[a-b] +f a.b !*.[a-b] +f a.a.a !*.[a-b] +f c.a !*.[a-b] +f d.a.d !*.[a-b] +f a.bb !*.[a-b] +f a.ccc !*.[a-b] +f c.ccc !*.[a-b] + +f a.a !*.[a-b]* +f a.b !*.[a-b]* +f a.a.a !*.[a-b]* +f c.a !*.[a-b]* +f d.a.d !*.[a-b]* +f a.bb !*.[a-b]* +f a.ccc !*.[a-b]* +f c.ccc !*.[a-b]* + +f a.a !*[a-b].[a-b]* +f a.b !*[a-b].[a-b]* +f a.a.a !*[a-b].[a-b]* +f c.a !*[a-b].[a-b]* +f d.a.d !*[a-b].[a-b]* +f a.bb !*[a-b].[a-b]* +f a.ccc !*[a-b].[a-b]* +f c.ccc !*[a-b].[a-b]* + +t abd [a-y]*[^c] +t abe [a-y]*[^c] +t bb [a-y]*[^c] +t bcd [a-y]*[^c] +t ca [a-y]*[^c] +t cb [a-y]*[^c] +t dd [a-y]*[^c] +t de [a-y]*[^c] +t bdir/ [a-y]*[^c] + +f abd **/* diff --git a/test/bash/globstar.txt b/test/bash/globstar.txt new file mode 100644 index 00000000..e17c6884 --- /dev/null +++ b/test/bash/globstar.txt @@ -0,0 +1,30 @@ +f a.js **/*.js +t a/a.js **/*.js +t a/a/b.js **/*.js + +f a/b/z.js a/b/**/*.js +t a/b/c/z.js a/b/**/*.js + +f foo.md **/*.md +t foo/bar.md **/*.md + +f foo/bar foo/**/bar +t foo/bar foo/**bar + +t ab/a/d **/* +t ab/b **/* +t a/b/c/d/a.js **/* +t a/b/c.js **/* +t a/b/c.txt **/* +t a/b/.js/c.txt **/* +f a.js **/* +f za.js **/* +f ab **/* +f a.b **/* + +f foo/ foo/**/ +f foo/bar foo/**/ +f foo/bazbar foo/**/ +f foo/barbar foo/**/ +f foo/bar/baz/qux foo/**/ +t foo/bar/baz/qux/ foo/**/ diff --git a/test/braces.js b/test/braces.js new file mode 100644 index 00000000..c987c02e --- /dev/null +++ b/test/braces.js @@ -0,0 +1,349 @@ +/*! + * braces + * + * Copyright (c) 2014-2016, Jon Schlinkert. + * Licensed under the MIT License + */ + +'use strict'; + +var extend = require('extend-shallow'); +var mm = require('..'); + +function optimize(pattern, options) { + return mm.braces(pattern, extend({optimize: true}, options)); +} + +describe('optimized', function() { + describe('sets', function() { + describe('invalid sets', function() { + it('should handle invalid sets:', function() { + optimize('{0..10,braces}', ['(0..10|braces)']); + optimize('{1..10,braces}', ['(1..10|braces)']); + }); + }); + + describe('escaping', function() { + it('should not expand escaped braces', function() { + optimize('\\{a,b,c,d,e}', ['{a,b,c,d,e}']); + optimize('a/b/c/{x,y\\}', ['a/b/c/{x,y}']); + optimize('a/\\{x,y}/cde', ['a/{x,y}/cde']); + optimize('abcd{efgh', ['abcd{efgh']); + optimize('{abc}', ['{abc}']); + optimize('{x,y,\\{a,b,c\\}}', ['(x|y|\\{a|b|c\\})']); + optimize('{x,y,{a,b,c\\}}', ['\\{x,y,(a|b|c\\})']); + optimize('{x,y,{abc},trie}', ['(x|y|\\{abc\\}|trie)']); + optimize('{x\\,y,\\{abc\\},trie}', ['(x,y|\\{abc\\}|trie)']); + }); + + it('should handle spaces', function() { + // Bash 4.3 says the following should be equivalent to `foo|(1|2)|bar`, + // That makes sense in Bash, since ' ' is a separator, but not here. + optimize('foo {1,2} bar', ['foo (1|2) bar']); + }); + + it('should handle empty braces', function() { + optimize('{ }', ['\\{ \\}']); + optimize('{', ['\\{']); + optimize('{}', ['\\{\\}']); + optimize('}', ['\\}']); + }); + + it('should escape braces when only one value is defined', function() { + optimize('a{b}c', ['a\\{b\\}c']); + optimize('a/b/c{d}e', ['a/b/c\\{d\\}e']); + }); + + it('should not expand braces in sets with es6/bash-like variables', function() { + optimize('abc/${ddd}/xyz', ['abc/\\$\\{ddd\\}/xyz']); + optimize('a${b}c', ['a\\$\\{b\\}c']); + optimize('a/{${b},c}/d', ['a/(\\$\\{b\\}|c)/d']); + optimize('a${b,d}/{foo,bar}c', ['a\\$\\{b,d\\}/(foo|bar)c']); + }); + + it('should not expand escaped commas.', function() { + optimize('a{b\\,c\\,d}e', ['a\\{b,c,d\\}e']); + optimize('a{b\\,c}d', ['a\\{b,c\\}d']); + optimize('{abc\\,def}', ['\\{abc,def\\}']); + optimize('{abc\\,def,ghi}', ['(abc,def|ghi)']); + optimize('a/{b,c}/{x\\,y}/d/e', ['a/(b|c)/\\{x,y\\}/d/e']); + }); + + it('should return sets with escaped commas', function() { + optimize('a/{b,c}/{x\\,y}/d/e', ['a/(b|c)/\\{x,y\\}/d/e']); + }); + + it('should not expand escaped braces.', function() { + optimize('{a,b\\}c,d}', ['(a|b\\}c|d)']); + optimize('\\{a,b,c,d,e}', ['\\{a,b,c,d,e\\}']); + optimize('a/{z,\\{a,b,c,d,e}/d', ['a/(z|\\{a|b|c|d|e)/d']); + optimize('a/\\{b,c}/{d,e}/f', ['a/\\{b,c\\}/(d|e)/f']); + optimize('./\\{x,y}/{a..z..3}/', ['./\\{x,y\\}/(a|d|g|j|m|p|s|v|y)/']); + }); + + it('should not expand escaped braces or commas.', function() { + optimize('{x\\,y,\\{abc\\},trie}', ['(x,y|\\{abc\\}|trie)']); + }); + }); + + describe('set expansion', function() { + it('should support sequence brace operators', function() { + optimize('/usr/{ucb/{ex,edit},lib/{ex,how_ex}}', ['/usr/(ucb/(ex|edit)|lib/(ex|how_ex))']); + optimize('ff{c,b,a}', ['ff(c|b|a)']); + optimize('f{d,e,f}g', ['f(d|e|f)g']); + optimize('x{{0..10},braces}y', ['x(([0-9]|10)|braces)y']); + optimize('{1..10}', ['([1-9]|10)']); + optimize('{a,b,c}', ['(a|b|c)']); + optimize('{braces,{0..10}}', ['(braces|([0-9]|10))']); + optimize('{l,n,m}xyz', ['(l|n|m)xyz']); + optimize('{{0..10},braces}', ['(([0-9]|10)|braces)']); + optimize('{{1..10..2},braces}', ['((1|3|5|7|9)|braces)']); + optimize('{{1..10},braces}', ['(([1-9]|10)|braces)']); + }); + + it('should expand multiple sets', function() { + optimize('a/{a,b}/{c,d}/e', ['a/(a|b)/(c|d)/e']); + optimize('a{b,c}d{e,f}g', ['a(b|c)d(e|f)g']); + optimize('a/{x,y}/c{d,e}f.{md,txt}', ['a/(x|y)/c(d|e)f.(md|txt)']); + }); + + it('should expand nested sets', function() { + optimize('{a,b}{{a,b},a,b}', ['(a|b)((a|b)|a|b)']); + optimize('a{b,c{d,e}f}g', ['a(b|c(d|e)f)g']); + optimize('a{{x,y},z}b', ['a((x|y)|z)b']); + optimize('f{x,y{g,z}}h', ['f(x|y(g|z))h']); + optimize('a{b,c}{d,e}/hx/z', ['a(b|c)(d|e)/hx/z']); + optimize('a{b,c{d,e},h}x/z', ['a(b|c(d|e)|h)x/z']); + optimize('a{b,c{d,e},h}x{y,z}', ['a(b|c(d|e)|h)x(y|z)']); + optimize('a{b,c{d,e},{f,g}h}x{y,z}', ['a(b|c(d|e)|(f|g)h)x(y|z)']); + optimize('a-{b{d,e}}-c', ['a-\\{b(d|e)\\}-c']); + }); + + it('should expand not modify non-brace characters', function() { + optimize('a/b/{d,e}/*.js', ['a/b/(d|e)/*.js']); + optimize('a/**/c/{d,e}/f*.js', ['a/**/c/(d|e)/f*.js']); + optimize('a/**/c/{d,e}/f*.{md,txt}', ['a/**/c/(d|e)/f*.(md|txt)']); + }); + }); + + describe('commas', function() { + it('should work with leading and trailing commas.', function() { + optimize('a{b,}c', ['a(b|)c']); + optimize('a{,b}c', ['a(|b)c']); + }); + }); + + describe('spaces', function() { + it('should handle spaces', function() { + optimize('0{1..9} {10..20}', ['0([1-9]) (1[0-9]|20)']); + optimize('a{ ,c{d, },h}x', ['a( |c(d| )|h)x']); + optimize('a{ ,c{d, },h} ', ['a( |c(d| )|h) ']); + + // see https://github.com/jonschlinkert/micromatch/issues/66 + optimize('/Users/tobiasreich/Sites/aaa/bbb/ccc 2016/src/**/[^_]*.{html,ejs}', ['/Users/tobiasreich/Sites/aaa/bbb/ccc 2016/src/**/[^_]*.(html|ejs)']); + }); + }); + }); + + /** + * Ranges + */ + + describe('ranges', function() { + describe('escaping / invalid ranges', function() { + it('should not try to expand ranges with decimals', function() { + optimize('{1.1..2.1}', ['\\{1.1..2.1\\}']); + optimize('{1.1..~2.1}', ['\\{1.1..~2.1\\}']); + }); + + it('should escape invalid ranges:', function() { + optimize('{1..0f}', ['{1..0f}']); + optimize('{1..10..ff}', ['{1..10..ff}']); + optimize('{1..10.f}', ['{1..10.f}']); + optimize('{1..10f}', ['{1..10f}']); + optimize('{1..20..2f}', ['{1..20..2f}']); + optimize('{1..20..f2}', ['{1..20..f2}']); + optimize('{1..2f..2}', ['{1..2f..2}']); + optimize('{1..ff..2}', ['{1..ff..2}']); + optimize('{1..ff}', ['{1..ff}']); + optimize('{1..f}', ['([1-f])']); + optimize('{1.20..2}', ['{1.20..2}']); + }); + + it('weirdly-formed brace expansions -- fixed in post-bash-3.1', function() { + optimize('a-{b{d,e}}-c', ['a-\\{b(d|e)\\}-c']); + optimize('a-{bdef-{g,i}-c', ['a-\\{bdef-(g|i)-c']); + }); + + it('should not expand quoted strings.', function() { + optimize('{"klklkl"}{1,2,3}', ['\\{klklkl\\}(1|2|3)']); + optimize('{"x,x"}', ['\\{x,x\\}']); + }); + + it('should escaped outer braces in nested non-sets', function() { + optimize('{a-{b,c,d}}', ['{a-(b|c|d)}']); + optimize('{a,{a-{b,c,d}}}', ['(a|{a-(b|c|d)})']); + }); + + it('should escape imbalanced braces', function() { + optimize('a-{bdef-{g,i}-c', ['a-\\{bdef-(g|i)-c']); + optimize('abc{', ['abc\\{']); + optimize('{abc{', ['\\{abc\\{']); + optimize('{abc', ['\\{abc']); + optimize('}abc', ['\\}abc']); + optimize('ab{c', ['ab\\{c']); + optimize('{{a,b}', ['\\{(a|b)']); + optimize('{a,b}}', ['(a|b)\\}']); + optimize('abcd{efgh', ['abcd\\{efgh']); + optimize('a{b{c{d,e}f}g}h', ['a(b(c(d|e)f)g)h']); + optimize('f{x,y{{g,z}}h}', ['f(x|y((g|z))h)']); + optimize('z{a,b},c}d', ['z(a|b),c\\}d']); + optimize('a{b{c{d,e}f{x,y{{g}h', ['a\\{b\\{c(d|e)f\\{x,y\\{\\{g\\}h']); + optimize('f{x,y{{g}h', ['f\\{x,y\\{\\{g\\}h']); + optimize('f{x,y{{g}}h', ['f{x,y{{g}}h']); + optimize('a{b{c{d,e}f{x,y{}g}h', ['a{b{c(d|e)f(x|y{}g)h']); + optimize('f{x,y{}g}h', ['f(x|y\\{\\}g)h']); + optimize('z{a,b{,c}d', ['z\\{a,b(|c)d']); + }); + }); + + describe('positive numeric ranges', function() { + it('should expand numeric ranges', function() { + optimize('a{0..3}d', ['a([0-3])d']); + optimize('x{10..1}y', ['x([1-9]|10)y']); + optimize('x{3..3}y', ['x3y']); + optimize('{1..10}', ['([1-9]|10)']); + optimize('{1..3}', ['([1-3])']); + optimize('{1..9}', ['([1-9])']); + optimize('{10..1}', ['([1-9]|10)']); + optimize('{10..1}y', ['([1-9]|10)y']); + optimize('{3..3}', ['3']); + optimize('{5..8}', ['([5-8])']); + }); + }); + + describe('negative ranges', function() { + it('should expand ranges with negative numbers', function() { + optimize('{-1..-10}', ['(-[1-9]|-10)']); + optimize('{-10..-1}', ['(-[1-9]|-10)']); + optimize('{-20..0}', ['(-[1-9]|-1[0-9]|-20|0)']); + optimize('{0..-5}', ['(-[1-5]|0)']); + optimize('{9..-4}', ['(-[1-4]|[0-9])']); + }); + }); + + describe('alphabetical ranges', function() { + it('should expand alphabetical ranges', function() { + optimize('0{1..9}/{10..20}', ['0([1-9])/(1[0-9]|20)']); + optimize('0{a..d}0', ['0([a-d])0']); + optimize('a/{b..d}/e', ['a/([b-d])/e']); + optimize('{1..f}', ['([1-f])']); + optimize('{a..A}', ['([A-a])']); + optimize('{A..a}', ['([A-a])']); + optimize('{a..e}', ['([a-e])']); + optimize('{A..E}', ['([A-E])']); + optimize('{a..f}', ['([a-f])']); + optimize('{a..z}', ['([a-z])']); + optimize('{E..A}', ['([A-E])']); + optimize('{f..1}', ['([1-f])']); + optimize('{f..a}', ['([a-f])']); + optimize('{f..f}', ['f']); + }); + + it('should expand multiple ranges:', function() { + optimize('a/{b..d}/e/{f..h}', ['a/([b-d])/e/([f-h])']); + }); + }); + + describe('combo', function() { + it('should expand numerical ranges - positive and negative', function() { + optimize('{-10..10}', ['(-[1-9]|-?10|[0-9])']); + }); + }); + + // HEADS UP! If you're using the `--mm` flag minimatch freezes on these + describe('large numbers', function() { + it('should expand large numbers', function() { + optimize('{2147483645..2147483649}', ['(214748364[5-9])']); + optimize('{214748364..2147483649}', ['(21474836[4-9]|2147483[7-9][0-9]|214748[4-9][0-9]{2}|214749[0-9]{3}|2147[5-9][0-9]{4}|214[8-9][0-9]{5}|21[5-9][0-9]{6}|2[2-9][0-9]{7}|[3-9][0-9]{8}|1[0-9]{9}|20[0-9]{8}|21[0-3][0-9]{7}|214[0-6][0-9]{6}|2147[0-3][0-9]{5}|21474[0-7][0-9]{4}|214748[0-2][0-9]{3}|2147483[0-5][0-9]{2}|21474836[0-4][0-9])']); + }); + }); + + describe('steps > positive ranges', function() { + it('should expand ranges using steps:', function() { + optimize('{1..10..1}', ['([1-9]|10)']); + optimize('{1..10..2}', ['(1|3|5|7|9)']); + optimize('{1..20..20}', ['1']); + optimize('{1..20..20}', ['1']); + optimize('{1..20..20}', ['1']); + optimize('{1..20..2}', ['(1|3|5|7|9|11|13|15|17|19)']); + optimize('{10..0..2}', ['(10|8|6|4|2|0)']); + optimize('{10..1..2}', ['(10|8|6|4|2)']); + optimize('{100..0..5}', ['(100|95|90|85|80|75|70|65|60|55|50|45|40|35|30|25|20|15|10|5|0)']); + optimize('{2..10..1}', ['([2-9]|10)']); + optimize('{2..10..2}', ['(2|4|6|8|10)']); + optimize('{2..10..3}', ['(2|5|8)']); + optimize('{a..z..2}', ['(a|c|e|g|i|k|m|o|q|s|u|w|y)']); + }); + + it('should expand positive ranges with negative steps:', function() { + optimize('{10..0..-2}', ['(10|8|6|4|2|0)']); + }); + }); + + describe('steps > negative ranges', function() { + it('should expand negative ranges using steps:', function() { + optimize('{-1..-10..-2}', ['(-(1|3|5|7|9))']); + optimize('{-1..-10..2}', ['(-(1|3|5|7|9))']); + optimize('{-10..-2..2}', ['(-(10|8|6|4|2))']); + optimize('{-2..-10..1}', ['(-[2-9]|-10)']); + optimize('{-2..-10..2}', ['(-(2|4|6|8|10))']); + optimize('{-2..-10..3}', ['(-(2|5|8))']); + optimize('{-50..-0..5}', ['(0|-(50|45|40|35|30|25|20|15|10|5))']); + optimize('{-9..9..3}', ['(0|3|6|9|-(9|6|3))']); + optimize('{10..1..-2}', ['(10|8|6|4|2)']); + optimize('{100..0..-5}', ['(100|95|90|85|80|75|70|65|60|55|50|45|40|35|30|25|20|15|10|5|0)']); + }); + }); + + describe('steps > alphabetical ranges', function() { + it('should expand alpha ranges with steps', function() { + optimize('{a..e..2}', ['(a|c|e)']); + optimize('{E..A..2}', ['(E|C|A)']); + optimize('{a..z}', ['([a-z])']); + optimize('{a..z..2}', ['(a|c|e|g|i|k|m|o|q|s|u|w|y)']); + optimize('{z..a..-2}', ['(z|x|v|t|r|p|n|l|j|h|f|d|b)']); + }); + + it('should expand alpha ranges with negative steps', function() { + optimize('{z..a..-2}', ['(z|x|v|t|r|p|n|l|j|h|f|d|b)']); + }); + }); + + describe('padding', function() { + it('unwanted zero-padding -- fixed post-bash-4.0', function() { + optimize('{10..0..2}', ['(10|8|6|4|2|0)']); + optimize('{10..0..-2}', ['(10|8|6|4|2|0)']); + optimize('{-50..-0..5}', ['(0|-(50|45|40|35|30|25|20|15|10|5))']); + }); + }); + }); + + describe('integration', function() { + it('should work with dots in file paths', function() { + optimize('../{1..3}/../foo', ['../([1-3])/../foo']); + optimize('../{2..10..2}/../foo', ['../(2|4|6|8|10)/../foo']); + optimize('../{1..3}/../{a,b,c}/foo', ['../([1-3])/../(a|b|c)/foo']); + optimize('./{a..z..3}/', ['./(a|d|g|j|m|p|s|v|y)/']); + optimize('./{"x,y"}/{a..z..3}/', ['./\\{x,y\\}/(a|d|g|j|m|p|s|v|y)/']); + }); + + it('should expand a complex combination of ranges and sets:', function() { + optimize('a/{x,y}/{1..5}c{d,e}f.{md,txt}', ['a/(x|y)/([1-5])c(d|e)f.(md|txt)']); + }); + + it('should expand complex sets and ranges in `bash` mode:', function() { + optimize('a/{x,{1..5},y}/c{d}e', ['a/(x|([1-5])|y)/c\\{d\\}e']); + }); + }); +}); diff --git a/test/brackets.js b/test/brackets.js index cba27362..18e69ad1 100644 --- a/test/brackets.js +++ b/test/brackets.js @@ -4,239 +4,298 @@ require('mocha'); var assert = require('assert'); var argv = require('yargs-parser')(process.argv.slice(2)); var minimatch = require('minimatch'); -var brackets = require('..'); +var nm = require('nanomatch'); +var mm = require('..'); -var matcher = argv.mm ? minimatch : brackets; -var isMatch = argv.mm ? minimatch : brackets.isMatch.bind(matcher); +var matcher = argv.mm ? minimatch : mm; +var isMatch = argv.mm ? minimatch : mm.isMatch.bind(matcher); -function match(arr, pattern, expected, options) { - var actual = matcher.match(arr, pattern, options); - assert.deepEqual(actual.sort(), expected.sort()); +function match(fixtures, pattern, expected, msg) { + var actual = matcher.match(fixtures, pattern).sort(alphaSort); + expected.sort(alphaSort); + assert.deepEqual(actual, expected, pattern + ' ' + (msg || '')); } -describe('POSIX brackets', function() { - it('should support POSIX.2 character classes', function() { - assert(isMatch('e', '[[:xdigit:]]')); - assert(isMatch('a', '[[:alpha:]123]')); - assert(isMatch('1', '[[:alpha:]123]')); - assert(isMatch('9', '[![:alpha:]]')); - }); - - it('should create the equivalent regex character classes for POSIX expressions:', function() { - assert.equal(brackets('foo[[:lower:]]bar').output, 'foo[a-z]bar'); - assert.equal(brackets('foo[[:lower:][:upper:]]bar').output, 'foo[a-zA-Z]bar'); - assert.equal(brackets('[[:alpha:]123]').output, '[a-zA-Z123]'); - assert.equal(brackets('[[:lower:]]').output, '[a-z]'); - assert.equal(brackets('[![:lower:]]').output, '[^a-z]'); - assert.equal(brackets('[[:digit:][:upper:][:space:]]').output, '[0-9A-Z \\t\\r\\n\\v\\f]+'); - assert.equal(brackets('[[:xdigit:]]').output, '[A-Fa-f0-9]'); - assert.equal(brackets('[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]').output, '[a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9\\x21-\\x7Ea-z\\x20-\\x7E\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~ \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]+'); - assert.equal(brackets('[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]').output, '[^a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9a-z \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]+'); - assert.equal(brackets('[a-c[:digit:]x-z]').output, '[a-c0-9x-z]'); - }); - - it('should support regex character classes:', function() { - var arr = ['a c', 'a1c', 'a123c', 'a.c', 'a.xy.zc', 'a.zc', 'abbbbc', 'abbbc', 'abbc', 'abc', 'abq', 'axy zc', 'axy', 'axy.zc', 'axyzc']; - match(arr, 'a[a-z]+c', ['abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc'], 'Should match word characters'); - match(['abc', 'abd'], 'a[bc]d', ['abd'], 'Should match character classes'); - match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]e', ['ace'], 'Should match character class alphabetical ranges'); - match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]', ['ac'], 'Should match character class alphabetical ranges'); - match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[-c]', ['a-', 'ac'], 'Should match character classes with leading dashes'); - match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[c-]', ['a-', 'ac'], 'Should match character classes with trailing dashes'); - match(['a]c', 'abd', 'ace', 'ac', 'a-'], 'a[]]c', ['a]c'], 'Should match bracket literals in character classes'); - match(['a]', 'abd', 'ace', 'ac', 'a-'], 'a]', ['a]'], 'Should match bracket literals'); - match(['a]', 'acd', 'aed', 'ac', 'a-'], 'a[^bc]d', ['aed'], 'Should negation patterns in character classes'); - match(['adc', 'a-c'], 'a[^-b]c', ['adc'], 'Should match negated dashes in character classes'); - match(['adc', 'a]c'], 'a[^]b]c', ['adc'], 'Should match negated brackets in character classes'); - match(['01234', '0123e456', '0123e45g78'], '[\\de]+', ['01234', '0123e456'], 'Should match alpha-numeric characters in character classes'); - match(['01234', '0123e456', '0123e45g78'], '[\\de]*', ['01234', '0123e456'], 'Should match alpha-numeric characters in character classes'); - match(['01234', '0123e456', '0123e45g78'], '[e\\d]+', ['01234', '0123e456'], 'Should match alpha-numeric characters in character classes'); - }); - - it('should not create an invalid posix character class:', function() { - assert.equal(matcher('[:al:]').output, '[al]'); - assert.equal(matcher('[abc[:punct:][0-9]').output, '[abc\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~[0-9]'); - }); - - it('should return `true` when the pattern matches:', function() { - assert(isMatch('a', '[[:lower:]]')); - assert(isMatch('A', '[[:upper:]]')); - assert(isMatch('A', '[[:digit:][:upper:][:space:]]')); - assert(isMatch('1', '[[:digit:][:upper:][:space:]]')); - assert(isMatch(' ', '[[:digit:][:upper:][:space:]]')); - assert(isMatch('5', '[[:xdigit:]]')); - assert(isMatch('f', '[[:xdigit:]]')); - assert(isMatch('D', '[[:xdigit:]]')); - assert(isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); - assert(isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); - assert(isMatch('.', '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); - assert(isMatch('5', '[a-c[:digit:]x-z]')); - assert(isMatch('b', '[a-c[:digit:]x-z]')); - assert(isMatch('y', '[a-c[:digit:]x-z]')); - }); - - it('should return `false` when the pattern does not match:', function() { - assert(!isMatch('A', '[[:lower:]]')); - assert(isMatch('A', '[![:lower:]]')); - assert(!isMatch('a', '[[:upper:]]')); - assert(!isMatch('a', '[[:digit:][:upper:][:space:]]')); - assert(!isMatch('.', '[[:digit:][:upper:][:space:]]')); - assert(!isMatch('.', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); - assert(!isMatch('q', '[a-c[:digit:]x-z]')); - }); -}); +function alphaSort(a, b) { + a = String(a).toLowerCase(); + b = String(b).toLowerCase(); + return a > b ? 1 : a < b ? -1 : 0; +} -describe('.makeRe()', function() { - it('should make a regular expression for the given pattern:', function() { - assert.deepEqual(matcher.makeRe('[[:alpha:]123]'), /^(?:[a-zA-Z123])$/); - assert.deepEqual(matcher.makeRe('[![:lower:]]'), /^(?:[^a-z])$/); - }); -}); +function create(pattern, options) { + return mm.create(pattern, options).map(function(obj) { + return obj.output; + }).join('|'); +} -describe('.match()', function() { - it('should return an array of matching strings:', function() { - assert.deepEqual(matcher.match(['a1B', 'a1b'], '[[:alpha:]][[:digit:]][[:upper:]]'), ['a1B']); - assert.deepEqual(matcher.match(['.', 'a', '!'], '[[:digit:][:punct:][:space:]]'), ['.', '!']); +describe('brackets', function() { + describe('main export', function() { + it('should create the equivalent regex character classes for POSIX expressions:', function() { + assert.equal(create('foo[[:lower:]]bar'), 'foo[a-z]bar'); + assert.equal(create('foo[[:lower:][:upper:]]bar'), 'foo[a-zA-Z]bar'); + assert.equal(create('[[:alpha:]123]'), '[a-zA-Z123]'); + assert.equal(create('[[:lower:]]'), '[a-z]'); + assert.equal(create('[![:lower:]]'), '[^a-z]'); + assert.equal(create('[[:digit:][:upper:][:space:]]'), '[0-9A-Z \\t\\r\\n\\v\\f]'); + assert.equal(create('[[:xdigit:]]'), '[A-Fa-f0-9]'); + assert.equal(create('[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]'), '[a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9\\x21-\\x7Ea-z\\x20-\\x7E \\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~ \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]'); + assert.equal(create('[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]'), '[^a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9a-z \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]'); + assert.equal(create('[a-c[:digit:]x-z]'), '[a-c0-9x-z]'); + assert.equal(create('[_[:alpha:]][_[:alnum:]][_[:alnum:]]*'), '[_a-zA-Z][_a-zA-Z0-9][_a-zA-Z0-9]*?\\/?', []); + }); + }); + + describe('.match', function() { + it('should support POSIX.2 character classes', function() { + match(['e'], '[[:xdigit:]]', [ 'e' ]); + match(['a', '1', '5', 'A'], '[[:alpha:]123]', [ '1', 'a', 'A' ]); + match(['9', 'A', 'b'], '[![:alpha:]]', ['9']); + match(['9', 'A', 'b'], '[^[:alpha:]]', ['9']); + match(['9', 'a', 'B'], '[[:digit:]]', ['9']); + match(['a', 'b', 'A'], '[:alpha:]', ['a'], 'not a valid posix bracket, but valid char class'); + match(['a', 'b', 'A'], '[[:alpha:]]', [ 'a', 'A', 'b' ]); + match(['a', 'aa', 'aB', 'a7'], '[[:lower:][:lower:]]', ['a']); + match(['a', '7', 'aa', 'aB', 'a7'], '[[:lower:][:digit:]]', [ '7', 'a' ]); + }); + + it('should match word characters', function() { + var fixtures = ['a c', 'a1c', 'a123c', 'a.c', 'a.xy.zc', 'a.zc', 'abbbbc', 'abbbc', 'abbc', 'abc', 'abq', 'axy zc', 'axy', 'axy.zc', 'axyzc']; + match(fixtures, 'a[a-z]+c', ['abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc']); + }); + + it('should match character classes', function() { + match(['abc', 'abd'], 'a[bc]d', ['abd']); + }); + + it('should match character class alphabetical ranges', function() { + match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]e', ['ace']); + match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]', ['ac']); + }); + + it('should match character classes with leading dashes', function() { + match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[-c]', ['a-', 'ac']); + }); + + it('should match character classes with trailing dashes', function() { + match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[c-]', ['a-', 'ac']); + }); + + it('should match bracket literals', function() { + match(['a]c', 'abd', 'ace', 'ac', 'a-'], 'a[]]c', ['a]c']); + }); + + it('should match bracket literals', function() { + match(['a]', 'abd', 'ace', 'ac', 'a-'], 'a]', ['a]']); + }); + + it('should negation patterns', function() { + match(['a]', 'acd', 'aed', 'ac', 'a-'], 'a[^bc]d', ['aed']); + }); + + it('should match negated dashes', function() { + match(['adc', 'a-c'], 'a[^-b]c', ['adc']); + }); + + it('should match negated brackets', function() { + match(['adc', 'a]c'], 'a[^]b]c', ['adc']); + }); + + it('should match alpha-numeric characters', function() { + match(['01234', '0123e456', '0123e45g78'], '[\\de]+', ['01234', '0123e456']); + match(['01234', '0123e456', '0123e45g78'], '[\\de]*', ['01234', '0123e456']); + match(['01234', '0123e456', '0123e45g78'], '[e\\d]+', ['01234', '0123e456']); + }); + + it('should not create an invalid posix character class:', function() { + assert.equal(create('[:al:]'), '[:al:]'); + assert.equal(create('[abc[:punct:][0-9]'), '[abc\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~\\[0-9]'); + }); + + it('should return `true` when the pattern matches:', function() { + assert(isMatch('a', '[[:lower:]]')); + assert(isMatch('A', '[[:upper:]]')); + assert(isMatch('A', '[[:digit:][:upper:][:space:]]')); + assert(isMatch('1', '[[:digit:][:upper:][:space:]]')); + assert(isMatch(' ', '[[:digit:][:upper:][:space:]]')); + assert(isMatch('5', '[[:xdigit:]]')); + assert(isMatch('f', '[[:xdigit:]]')); + assert(isMatch('D', '[[:xdigit:]]')); + assert(isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); + assert(isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); + assert(isMatch('.', '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); + assert(isMatch('5', '[a-c[:digit:]x-z]')); + assert(isMatch('b', '[a-c[:digit:]x-z]')); + assert(isMatch('y', '[a-c[:digit:]x-z]')); + }); + + it('should return `false` when the pattern does not match:', function() { + assert(!isMatch('A', '[[:lower:]]')); + assert(isMatch('A', '[![:lower:]]')); + assert(!isMatch('a', '[[:upper:]]')); + assert(!isMatch('a', '[[:digit:][:upper:][:space:]]')); + assert(!isMatch('.', '[[:digit:][:upper:][:space:]]')); + assert(!isMatch('.', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); + assert(!isMatch('q', '[a-c[:digit:]x-z]')); + }); + }); + + describe('.makeRe()', function() { + it('should make a regular expression for the given pattern:', function() { + assert.deepEqual(matcher.makeRe('[[:alpha:]123]'), /^(?:[a-zA-Z123])$/); + assert.deepEqual(matcher.makeRe('[![:lower:]]'), /^(?:[^a-z])$/); + }); + }); + + describe('.match()', function() { + it('should return an array of matching strings:', function() { + assert.deepEqual(matcher.match(['a1B', 'a1b'], '[[:alpha:]][[:digit:]][[:upper:]]'), ['a1B']); + assert.deepEqual(matcher.match(['.', 'a', '!'], '[[:digit:][:punct:][:space:]]'), ['.', '!']); + }); + }); + + describe('POSIX: From the test suite for the POSIX.2 (BRE) pattern matching code:', function() { + it('First, test POSIX.2 character classes', function() { + assert(isMatch('e', '[[:xdigit:]]')); + assert(isMatch('1', '[[:xdigit:]]')); + assert(isMatch('a', '[[:alpha:]123]')); + assert(isMatch('1', '[[:alpha:]123]')); + }); + + it('should match using POSIX.2 negation patterns', function() { + assert(isMatch('9', '[![:alpha:]]')); + assert(isMatch('9', '[^[:alpha:]]')); + }); + + it('should match word characters', function() { + assert(isMatch('A', '[[:word:]]')); + assert(isMatch('B', '[[:word:]]')); + assert(isMatch('a', '[[:word:]]')); + assert(isMatch('b', '[[:word:]]')); + }); + + it('should match digits with word class', function() { + assert(isMatch('1', '[[:word:]]')); + assert(isMatch('2', '[[:word:]]')); + }); + + it('should not digits', function() { + assert(isMatch('1', '[[:digit:]]')); + assert(isMatch('2', '[[:digit:]]')); + }); + + it('should not match word characters with digit class', function() { + assert(!isMatch('a', '[[:digit:]]')); + assert(!isMatch('A', '[[:digit:]]')); + }); + + it('should match uppercase alpha characters', function() { + assert(isMatch('A', '[[:upper:]]')); + assert(isMatch('B', '[[:upper:]]')); + }); + + it('should not match lowercase alpha characters', function() { + assert(!isMatch('a', '[[:upper:]]')); + assert(!isMatch('b', '[[:upper:]]')); + }); + + it('should not match digits with upper class', function() { + assert(!isMatch('1', '[[:upper:]]')); + assert(!isMatch('2', '[[:upper:]]')); + }); + + it('should match lowercase alpha characters', function() { + assert(isMatch('a', '[[:lower:]]')); + assert(isMatch('b', '[[:lower:]]')); + }); + + it('should not match uppercase alpha characters', function() { + assert(!isMatch('A', '[[:lower:]]')); + assert(!isMatch('B', '[[:lower:]]')); + }); + + it('should match one lower and one upper character', function() { + assert(isMatch('aA', '[[:lower:]][[:upper:]]')); + assert(!isMatch('AA', '[[:lower:]][[:upper:]]')); + assert(!isMatch('Aa', '[[:lower:]][[:upper:]]')); + }); + + it('should match hexidecimal digits', function() { + assert(isMatch('ababab', '[[:xdigit:]]*')); + assert(isMatch('020202', '[[:xdigit:]]*')); + assert(isMatch('900', '[[:xdigit:]]*')); + }); + + it('should match punctuation characters (\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~)', function() { + assert(isMatch('!', '[[:punct:]]')); + assert(isMatch('?', '[[:punct:]]')); + assert(isMatch('#', '[[:punct:]]')); + assert(isMatch('&', '[[:punct:]]')); + assert(isMatch('@', '[[:punct:]]')); + assert(isMatch('+', '[[:punct:]]')); + assert(isMatch('*', '[[:punct:]]')); + assert(isMatch(':', '[[:punct:]]')); + assert(isMatch('=', '[[:punct:]]')); + assert(isMatch('|', '[[:punct:]]')); + assert(isMatch('|++', '[[:punct:]]*')); + }); + + it('should only match one character', function() { + assert(!isMatch('?*+', '[[:punct:]]')); + }); + + it('should only match zero or more characters', function() { + assert(isMatch('?*+', '[[:punct:]]*')); + assert(isMatch('', '[[:punct:]]*')); + }); + + it('invalid character class expressions are just characters to be matched', function() { + match(['a'], '[:al:]', ['a']); + match(['a'], '[[:al:]', ['a']); + match(['!'], '[abc[:punct:][0-9]', ['!']); + }); + + it('should match the start of a valid sh identifier', function() { + assert(isMatch('PATH', '[_[:alpha:]]*')); + }); + + it('should match the first two characters of a valid sh identifier', function() { + assert(isMatch('PATH', '[_[:alpha:]][_[:alnum:]]*')); + }); + + /** + * Some of these tests (and their descriptions) were ported directly + * from the Bash 4.3 unit tests. + */ + + it('how about A?', function() { + match(['9'], '[[:digit:]]', ['9']); + match(['X'], '[[:digit:]]', []); + match(['aB'], '[[:lower:]][[:upper:]]', ['aB']); + match(['a', '3', 'aa', 'a3', 'abc'], '[[:alpha:][:digit:]]', ['3', 'a']); + match(['a', 'b'], '[[:alpha:]\\]', [], []); + }); + + it('OK, what\'s a tab? is it a blank? a space?', function() { + assert(isMatch('\t', '[[:blank:]]')); + assert(isMatch('\t', '[[:space:]]')); + assert(isMatch(' ', '[[:space:]]')); + }); + + it('let\'s check out characters in the ASCII range', function() { + assert(!isMatch('\\377', '[[:ascii:]]')); + assert(!isMatch('9', '[1[:alpha:]123]')); + }); + + it('punctuation', function() { + assert(!isMatch(' ', '[[:punct:]]')); + }); + + it('graph', function() { + assert(isMatch('A', '[[:graph:]]')); + assert(!isMatch('\b', '[[:graph:]]')); + assert(!isMatch('\n', '[[:graph:]]')); + assert(isMatch('\s', '[[:graph:]]')); + }); }); }); -describe('POSIX: From the test suite for the POSIX.2 (BRE) pattern matching code:', function() { - it('First, test POSIX.2 character classes', function() { - assert(isMatch('e', '[[:xdigit:]]')); - assert(isMatch('1', '[[:xdigit:]]')); - assert(isMatch('a', '[[:alpha:]123]')); - assert(isMatch('1', '[[:alpha:]123]')); - }); - - it('should match using POSIX.2 negation patterns', function() { - assert(isMatch('9', '[![:alpha:]]')); - assert(isMatch('9', '[^[:alpha:]]')); - }); - - it('should match word characters', function() { - assert(isMatch('A', '[[:word:]]')); - assert(isMatch('B', '[[:word:]]')); - assert(isMatch('a', '[[:word:]]')); - assert(isMatch('b', '[[:word:]]')); - }); - - it('should match digits with word class', function() { - assert(isMatch('1', '[[:word:]]')); - assert(isMatch('2', '[[:word:]]')); - }); - - it('should not digits', function() { - assert(isMatch('1', '[[:digit:]]')); - assert(isMatch('2', '[[:digit:]]')); - }); - - it('should not match word characters with digit class', function() { - assert(!isMatch('a', '[[:digit:]]')); - assert(!isMatch('A', '[[:digit:]]')); - }); - - it('should match uppercase alpha characters', function() { - assert(isMatch('A', '[[:upper:]]')); - assert(isMatch('B', '[[:upper:]]')); - }); - - it('should not match lowercase alpha characters', function() { - assert(!isMatch('a', '[[:upper:]]')); - assert(!isMatch('b', '[[:upper:]]')); - }); - - it('should not match digits with upper class', function() { - assert(!isMatch('1', '[[:upper:]]')); - assert(!isMatch('2', '[[:upper:]]')); - }); - - it('should match lowercase alpha characters', function() { - assert(isMatch('a', '[[:lower:]]')); - assert(isMatch('b', '[[:lower:]]')); - }); - - it('should not match uppercase alpha characters', function() { - assert(!isMatch('A', '[[:lower:]]')); - assert(!isMatch('B', '[[:lower:]]')); - }); - - it('should match one lower and one upper character', function() { - assert(isMatch('aA', '[[:lower:]][[:upper:]]')); - assert(!isMatch('AA', '[[:lower:]][[:upper:]]')); - assert(!isMatch('Aa', '[[:lower:]][[:upper:]]')); - }); - - it('should match hexidecimal digits', function() { - assert(isMatch('ababab', '[[:xdigit:]]*')); - assert(isMatch('020202', '[[:xdigit:]]*')); - assert(isMatch('900', '[[:xdigit:]]*')); - }); - - it('should match punctuation characters (\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~)', function() { - assert(isMatch('!', '[[:punct:]]')); - assert(isMatch('?', '[[:punct:]]')); - assert(isMatch('#', '[[:punct:]]')); - assert(isMatch('&', '[[:punct:]]')); - assert(isMatch('@', '[[:punct:]]')); - assert(isMatch('+', '[[:punct:]]')); - assert(isMatch('*', '[[:punct:]]')); - assert(isMatch(':', '[[:punct:]]')); - assert(isMatch('=', '[[:punct:]]')); - assert(isMatch('|', '[[:punct:]]')); - assert(isMatch('|++', '[[:punct:]]*')); - }); - - it('should only match one character', function() { - assert(!isMatch('?*+', '[[:punct:]]')); - }); - - it('should only match zero or more characters', function() { - assert(isMatch('?*+', '[[:punct:]]*')); - assert(isMatch('', '[[:punct:]]*')); - }); - - it('invalid character class expressions are just characters to be matched', function() { - assert(isMatch('a', '[:al:]')); - assert(isMatch('a', '[[:al:]')); - assert(isMatch('!', '[abc[:punct:][0-9]')); - }); - - it('should match the start of a valid sh identifier', function() { - assert(isMatch('PATH', '[_[:alpha:]]*')); - }); - - it('should match the first two characters of a valid sh identifier', function() { - assert(isMatch('PATH', '[_[:alpha:]][_[:alnum:]]*')); - }); - - it('how about A?', function() { - assert(isMatch('9', '[[:digit:]]')); - assert(!isMatch('X', '[[:digit:]]')); - assert(isMatch('aB', '[[:lower:]][[:upper:]]')); - assert.equal(brackets('[_[:alpha:]][_[:alnum:]][_[:alnum:]]*').output, '[_a-zA-Z][_a-zA-Z0-9][_a-zA-Z0-9]*?'); - assert(isMatch('a3', '[[:alpha:][:digit:]]')); - assert(!isMatch('a', '[[:alpha:]\\]')); - }); - - it('OK, what\'s a tab? is it a blank? a space?', function() { - assert(isMatch('\t', '[[:blank:]]')); - assert(isMatch('\t', '[[:space:]]')); - assert(isMatch(' ', '[[:space:]]')); - }); - - it('let\'s check out characters in the ASCII range', function() { - assert(!isMatch('\\377', '[[:ascii:]]')); - assert(!isMatch('9', '[1[:alpha:]123]')); - }); - - it('punctuation', function() { - assert(!isMatch(' ', '[[:punct:]]')); - }); - - it('graph', function() { - assert(isMatch('A', '[[:graph:]]')); - assert(!isMatch('\b', '[[:graph:]]')); - assert(!isMatch('\n', '[[:graph:]]')); - assert(isMatch('\s', '[[:graph:]]')); - }); -}); diff --git a/test/dotfiles.js b/test/dotfiles.js index 4bd1ef21..0ba44406 100644 --- a/test/dotfiles.js +++ b/test/dotfiles.js @@ -1,85 +1,131 @@ 'use strict'; var assert = require('assert'); -var mm = require('..'); +var mm = require('./support/match'); describe('dotfiles', function() { - describe('file name', function() { + describe('file name matching', function() { it('should not match a dot when the dot is not explicitly defined', function() { - assert(!mm.isMatch('.bashrc', '*bashrc')); - assert(!mm.isMatch('.bashrc', '?bashrc')); + assert(!mm.isMatch('.dot', '*dot')); + assert(!mm.isMatch('.dot', '?dot')); + }); + + it('should match with double dots', function() { + var fixtures = ['a/../a', 'ab/../ac', '../a', 'a', '../../b', '../c', '../c/d']; + mm(fixtures, '../*', ['../a', '../c']); + mm(fixtures, '*/../*', ['a/../a', 'ab/../ac']); + mm(fixtures, '**/../*', ['a/../a', 'ab/../ac', '../a', '../c']); + }); + + it('should not match a dot when the dot is not explicitly defined', function() { + var fixtures = ['a/b/.x', '.x', '.x/', '.x/a', '.x/a/b', '.x/.x', 'a/.x', 'a/b/.x/c', 'a/b/.x/c/d', 'a/b/.x/c/d/e', 'a/b/.x/', 'a/.x/b', 'a/.x/b/.x/c']; + mm(fixtures, '**/.x/**', ['.x/', '.x/a', '.x/a/b', 'a/b/.x/c', 'a/b/.x/c/d', 'a/b/.x/c/d/e', 'a/b/.x/', 'a/.x/b']); }); it('should match a dot when the dot is explicitly defined', function() { - assert(mm.isMatch('.bashrc', '[.]bashrc')); - assert(mm.isMatch('.bashrc', '.[b]ashrc')); - assert(mm.isMatch('.bashrc', '.bashr*')); - assert(!mm.isMatch('.bashrc', '.ba?hrc')); + // first one is from minimatch tests + var fixtures = ['a/b/.x/c', 'a/b/.x/c/d', 'a/b/.x/c/d/e', 'a/b/.x', 'a/b/.x/', 'a/.x/b', '.x', '.x/', '.x/a', '.x/a/b', 'a/.x/b/.x/c', '.x/.x']; + var expected = ['.x/', '.x/a', '.x/a/b', 'a/.x/b', 'a/b/.x/', 'a/b/.x/c', 'a/b/.x/c/d', 'a/b/.x/c/d/e']; + + mm(fixtures, '**/.x/**', expected); + mm('/.dot', '/[.]dot', ['/.dot']); + mm('.dot', '[.]dot', ['.dot']); + mm('.dot', '.[d]ot', ['.dot']); + mm('.dot', '.dot*', ['.dot']); + mm('.dot', '.d?t', ['.dot']); + + assert(!mm.isMatch('.bar.baz', '.*.*/')); + assert(mm.isMatch('.bar.baz/', '.*.*')); + assert(mm.isMatch('.bar.baz', '.*.*')); + assert(mm.isMatch('.bar.baz', '.*.baz')); + assert(mm.isMatch('.bar.baz/', '.*.*/')); + assert(mm.isMatch('.dot', '.*ot')); + assert(mm.isMatch('.dot', '.[d]ot')); + assert(mm.isMatch('.dot.foo.bar', '.*ot.*.*')); + assert(mm.isMatch('.dotfile.js', '.*.js')); + assert(mm.isMatch('/.dot', '**/.[d]ot')); + assert(mm.isMatch('/.dot', '**/.dot*')); + assert(mm.isMatch('/.dot', '**/[.]dot')); + assert(mm.isMatch('/.dot', '*/[.]dot')); + assert(mm.isMatch('/.dot', '/[.]dot')); + assert(mm.isMatch('a/.dot', '**/.[d]ot')); + assert(mm.isMatch('a/.dot', '*/.[d]ot')); + assert(mm.isMatch('a/.dot', '*/.dot*')); + assert(mm.isMatch('a/.dot', '*/[.]dot')); + assert(mm.isMatch('a/b/.dot', '**/.[d]ot')); + assert(mm.isMatch('a/b/.dot', '**/.dot*')); + assert(mm.isMatch('a/b/.dot', '**/[.]dot')); + assert(mm.isMatch('a/b/.dot', '.dot', {matchBase: true})); + assert(mm.isMatch('a/b/.dot', '[.]dot', {matchBase: true})); }); }); describe('multiple directories', function() { it('should not match a dot when the dot is not explicitly defined', function() { - assert(!mm.isMatch('/.bashrc', '**/*bashrc')); - assert(!mm.isMatch('/.bashrc', '**/?bashrc')); - assert(!mm.isMatch('/.bashrc', '*/*bashrc')); - assert(!mm.isMatch('/.bashrc', '*/?bashrc')); - assert(!mm.isMatch('/.bashrc', '/*bashrc')); - assert(!mm.isMatch('/.bashrc', '/?bashrc')); - assert(!mm.isMatch('a/.bashrc', '*/*bashrc')); - assert(!mm.isMatch('a/.bashrc', '*/?bashrc')); - assert(!mm.isMatch('a/b/.bashrc', '**/*bashrc')); - assert(!mm.isMatch('a/b/.bashrc', '**/?bashrc')); - assert(mm.isMatch('/.bashrc', '**/[.]bashrc')); - assert(mm.isMatch('/.bashrc', '*/[.]bashrc')); - assert(mm.isMatch('/.bashrc', '/[.]bashrc')); - assert(mm.isMatch('a/.bashrc', '*/[.]bashrc')); - assert(mm.isMatch('a/b/.bashrc', '**/[.]bashrc')); - }); + assert(!mm.isMatch('.dot', '**/*dot')); + assert(!mm.isMatch('.dot', '**/?dot')); + assert(!mm.isMatch('.dot', '*/*dot')); + assert(!mm.isMatch('.dot', '*/?dot')); + assert(!mm.isMatch('.dot', '/*dot')); + assert(!mm.isMatch('.dot', '/?dot')); + assert(!mm.isMatch('/.dot', '**/*dot')); + assert(!mm.isMatch('/.dot', '**/?dot')); + assert(!mm.isMatch('/.dot', '*/*dot')); + assert(!mm.isMatch('/.dot', '*/?dot')); + assert(!mm.isMatch('/.dot', '/*dot')); + assert(!mm.isMatch('/.dot', '/?dot')); + assert(!mm.isMatch('a/.dot', '*/*dot')); + assert(!mm.isMatch('a/.dot', '*/?dot')); + assert(!mm.isMatch('a/b/.dot', '**/*dot')); + assert(!mm.isMatch('a/b/.dot', '**/?dot')); - it('should match a dot when the dot is explicitly defined', function() { - assert(mm.isMatch('/.bashrc', '**/.[b]ashrc')); - assert(mm.isMatch('/.bashrc', '**/.bashr*')); - assert(mm.isMatch('a/.bashrc', '*/.[b]ashrc')); - assert(mm.isMatch('a/.bashrc', '*/.bashr*')); - assert(mm.isMatch('a/b/.bashrc', '**/.[b]ashrc')); - assert(mm.isMatch('a/b/.bashrc', '**/.bashr*')); + // related https://github.com/jonschlinkert/micromatch/issues/63 + assert(!mm.isMatch('/aaa/bbb/.git', '/aaa/bbb/**')); + assert(!mm.isMatch('aaa/bbb/.git', 'aaa/bbb/**')); + assert(!mm.isMatch('/aaa/bbb/ccc/.git', '/aaa/bbb/**')); }); }); describe('options.dot', function() { it('should match dotfiles when `options.dot` is true', function() { - assert(mm.isMatch('.bashrc', '*bashrc', {dot: true})); - assert(mm.isMatch('.bashrc', '[.]bashrc', {dot: true})); - assert(mm.isMatch('.bashrc', '?bashrc', {dot: true})); - - assert(mm.isMatch('a/b/.bashrc', '*bashrc', {dot: true, matchBase: true})); - assert(mm.isMatch('a/b/.bashrc', '[.]bashrc', {dot: true, matchBase: true})); - assert(mm.isMatch('a/b/.bashrc', '?bashrc', {dot: true, matchBase: true})); + assert(mm.isMatch('.dotfile.js', '.*.js', {dot: true})); + assert(mm.isMatch('.dot', '*dot', {dot: true})); + assert(mm.isMatch('.dot', '?dot', {dot: true})); + assert(mm.isMatch('.dot', '[.]dot', {dot: true})); + assert(mm.isMatch('/a/b/.dot', '**/*dot', {dot: true})); + assert(mm.isMatch('/a/b/.dot', '**/.[d]ot', {dot: true})); + assert(mm.isMatch('/a/b/.dot', '**/?dot', {dot: true})); + assert(mm.isMatch('/a/b/.dot', '**/[.]dot', {dot: false})); + assert(mm.isMatch('/a/b/.dot', '**/[.]dot', {dot: true})); + assert(mm.isMatch('a/b/.dot', '**/*dot', {dot: true})); + assert(mm.isMatch('a/b/.dot', '**/.[d]ot', {dot: true})); + assert(mm.isMatch('a/b/.dot', '**/?dot', {dot: true})); + assert(mm.isMatch('a/b/.dot', '**/[.]dot', {dot: false})); + assert(mm.isMatch('a/b/.dot', '**/[.]dot', {dot: true})); + }); - assert(mm.isMatch('a/b/.bashrc', '**/*bashrc', {dot: true})); - assert(mm.isMatch('a/b/.bashrc', '**/.[b]ashrc', {dot: true})); - assert(mm.isMatch('a/b/.bashrc', '**/[.]bashrc', {dot: true})); - assert(mm.isMatch('a/b/.bashrc', '**/?bashrc', {dot: true})); + it('should match dotfiles when `.dot` and `.matchBase` both defined', function() { + assert(mm.isMatch('a/b/.dot', '*dot', {dot: true, matchBase: true})); + assert(mm.isMatch('a/b/.dot', '[.]dot', {dot: true, matchBase: true})); + assert(mm.isMatch('a/b/.dot', '[.]dot', {dot: false, matchBase: true})); + assert(mm.isMatch('a/b/.dot', '?dot', {dot: true, matchBase: true})); }); it('should not match dotfiles when `options.dot` is false', function() { - assert(mm.isMatch('a/b/.bashrc', '[.]bashrc', {dot: false, matchBase: true})); - assert(mm.isMatch('a/b/.bashrc', '**/[.]bashrc', {dot: false})); - - assert(!mm.isMatch('a/b/.bashrc', '*bashrc', {dot: false, matchBase: true})); - assert(!mm.isMatch('a/b/.bashrc', '?bashrc', {dot: false, matchBase: true})); + assert(!mm.isMatch('a/b/.dot', '**/*dot', {dot: false})); + assert(!mm.isMatch('a/b/.dot', '**/?dot', {dot: false})); + }); - assert(!mm.isMatch('a/b/.bashrc', '**/*bashrc', {dot: false})); - assert(!mm.isMatch('a/b/.bashrc', '**/?bashrc', {dot: false})); + it('should not match dotfiles when `.dot` is false and `.matchBase` is true', function() { + assert(!mm.isMatch('a/b/.dot', '*dot', {dot: false, matchBase: true})); + assert(!mm.isMatch('a/b/.dot', '?dot', {dot: false, matchBase: true})); }); - }); - describe('options.dot', function() { - it('should match a dot `options.dot` is true', function() { - assert(mm.isMatch('.bashrc', '*bashrc', {dot: true})); - assert(mm.isMatch('.bashrc', '[.]bashrc', {dot: true})); - assert(mm.isMatch('.bashrc', '?bashrc', {dot: true})); + it('should not match dotfiles when `.dot` is not defined and a dot is not in the glob pattern', function() { + assert(!mm.isMatch('a/b/.dot', '*dot', {matchBase: true})); + assert(!mm.isMatch('a/b/.dot', '?dot', {matchBase: true})); + assert(!mm.isMatch('a/b/.dot', '**/*dot')); + assert(!mm.isMatch('a/b/.dot', '**/?dot')); }); }); }); diff --git a/test/extglobs.js b/test/extglobs.js index 19c41c2a..469b4992 100644 --- a/test/extglobs.js +++ b/test/extglobs.js @@ -3,14 +3,17 @@ var assert = require('assert'); var argv = require('yargs-parser')(process.argv.slice(2)); var minimatch = require('minimatch'); -var micromatch = require('..');; +var micromatch = require('..'); +var extglob = require('extglob'); +var nm = require('nanomatch'); var matcher = argv.mm ? minimatch : micromatch; var isMatch = argv.mm ? minimatch : micromatch.isMatch; function match(arr, pattern, expected, options) { - var actual = matcher.match(arr, pattern, options); - assert.deepEqual(actual.sort(), expected.sort(), micromatch.makeRe(pattern)); + var actual = matcher.match(arr, pattern, options).sort(); + expected.sort(); + assert.deepEqual(actual, expected, micromatch.makeRe(pattern)); } /** @@ -22,22 +25,16 @@ describe('extglobs', function() { assert.equal(typeof matcher, 'function'); }); - it('should throw on imbalanced sets when `options.strict` is true', function() { + it('should throw on imbalanced sets when `options.strictErrors` is true', function() { assert.throws(function() { - isMatch('a((b', 'a(b', {strict: true}); + isMatch('a((b', 'a(b', {strictErrors: true}); }, 'row:1 col:2 missing opening parens: "a(b"'); assert.throws(function() { - isMatch('a((b', 'a(*b', {strict: true}); + isMatch('a((b', 'a(*b', {strictErrors: true}); }, 'row:1 col:2 missing opening parens: "a(*b"'); }); - it.skip('Bash 4.3 disagrees!', function() { - match(['foo'], '*(!(foo))', ['foo']); - match(['foo', 'bar', 'baz', 'foobar'], '!(foo)*', ['foo', 'bar', 'baz', 'foobar']); - match(['moo.cow', 'mad.moo.cow'], '!(*.*).!(*.*)', ['moo.cow']); - }); - it('should match extglobs ending with statechar', function() { // from minimatch tests assert(!isMatch('ax', 'a?(b*)')); @@ -45,6 +42,7 @@ describe('extglobs', function() { }); it('should match extended globs:', function() { + match(['a.js.js', 'a.md.js'], '*.*(js).js', ['a.js.js']); match(['a/z', 'a/b'], 'a/!(z)', ['a/b']); match(['c/z/v'], 'c/z/v', ['c/z/v']); match(['c/a/v'], 'c/!(z)/v', ['c/a/v']); @@ -88,7 +86,7 @@ describe('extglobs', function() { it('should work with globs', function() { var arr = ['123abc', 'ab', 'abab', 'abcdef', 'accdef', 'abcfefg', 'abef', 'abcfef', 'abd', 'acd']; match(arr, 'ab*(e|f)', ['ab', 'abef']); - match(arr, 'ab?*(e|f)', ['ab', 'abef']); + match(arr, 'ab?*(e|f)', ['abd', 'abef', 'abcfef']); match(arr, 'ab*d+(e|f)', ['abcdef']); match(arr, 'ab**(e|f)', ['ab', 'abab', 'abcdef', 'abcfefg', 'abcfef', 'abef', 'abd']); match(arr, 'ab*+(e|f)', ['abcdef', 'abcfef', 'abef']); @@ -135,7 +133,7 @@ describe('extglobs', function() { match(['abd', 'acd', 'ac', 'ab'], 'a!(@(b|B))', ['acd', 'abd', 'ac']); match(['abd', 'acd'], 'a!(@(b|B))d', ['acd']); match(['abd', 'acd'], 'a[b*(foo|bar)]d', ['abd']); - // match(['abcx', 'abcz', 'bbc'], '[a*(]*z', ['abcz']); + match(['abcx', 'abcz', 'bbc', 'aaz', 'aaaz'], '[a*(]*z', ['aaz', 'aaaz', 'abcz']); }); it('simple kleene star tests', function() { @@ -143,7 +141,7 @@ describe('extglobs', function() { assert(isMatch('foo', '*(a|b\\[)|f*')); }); - it('this doesn\'t work in bash either (per bash extglob.tests notes)', function() { + it('this doesn\'t work in bash either (per bash micromatch.tests notes)', function() { assert(!isMatch('*(a|b[)', '*(a|b\\[)')); assert(isMatch('*(a|b[)', '\\*\\(a\\|b\\[\\)')); }); @@ -151,46 +149,26 @@ describe('extglobs', function() { it('should support multiple exclusion patterns in one extglob:', function() { var arr = ['a.a', 'a.b', 'a.c', 'a.c.d', 'c.c', 'a.', 'd.d', 'e.e', 'f.f', 'a.abcd']; match(arr, '*.(a|b|@(ab|a*@(b))*(c)d)', ['a.a', 'a.b', 'a.abcd']); - match(arr, '!(*.a|*.b|*.c)', ['a.', 'd.d', 'e.e', 'f.f']); + match(arr, '!(*.a|*.b|*.c)', ['a.', 'a.c.d', 'd.d', 'e.e', 'f.f']); match(arr, '*!(.a|.b|.c)', arr); match(arr, '*.!(a|b|c)', ['a.c.d', 'a.', 'd.d', 'e.e', 'f.f']); }); it('should correctly match empty parens', function() { - var arr = ['def', 'ef']; - match(arr, '()ef', ['ef']); + match(['def', 'ef'], '()ef', ['ef']); }); it('should match escaped parens', function() { var arr = ['a(b', 'a\\(b', 'a((b', 'a((((b', 'ab']; match(arr, 'a(b', ['a(b']); - match(arr, 'a\\(b', ['a(b']); + match(arr, 'a\\(b', ['a(b', 'a\\(b']); match(arr, 'a(*b', ['a(b', 'a((b', 'a((((b']); }); it('should match escaped backslashes', function() { match(['a(b', 'a\\(b', 'a((b', 'a((((b', 'ab'], 'a\\\\(b', ['a\\(b']); match(['a\\b', 'a/b', 'ab'], 'a/b', ['a/b']); - match(['a\\b', 'a/b', 'ab'], 'a\\\\b', ['a\\b']); - }); - - // these are not extglobs, and do not need to pass. these tests will be moved to `expand-brackets` - it('should match common regex patterns', function() { - var arr = ['a c', 'a1c', 'a123c', 'a.c', 'a.xy.zc', 'a.zc', 'abbbbc', 'abbbc', 'abbc', 'abc', 'abq', 'axy zc', 'axy', 'axy.zc', 'axyzc']; - - match(arr, 'ab*c', ['abbbbc', 'abbbc', 'abbc', 'abc']); - match(arr, 'ab+bc', ['abbbbc', 'abbbc', 'abbc']); - match(arr, 'ab?bc', ['abbc', 'abc']); - match(arr, '^abc$', ['abc']); - match(arr, 'a.c', ['a.c']); - match(arr, 'a.*c', ['a.c', 'a.xy.zc', 'a.zc']); - match(arr, 'a*c', ['a c', 'a.c', 'a1c', 'a123c', 'abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc', 'axy zc', 'axy.zc', 'a.xy.zc', 'a.zc']); - match(arr, 'a\\w+c', ['a1c', 'a123c', 'abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc'], 'Should match word characters'); - match(arr, 'a\\W+c', ['a.c', 'a c'], 'Should match non-word characters'); - match(arr, 'a\\d+c', ['a1c', 'a123c'], 'Should match numbers'); - match(['foo@#$%123ASD #$$%^&', 'foo!@#$asdfl;', '123'], '\\d+', ['123']); - match(['a123c', 'abbbc'], 'a\\D+c', ['abbbc'], 'Should match non-numbers'); - match(['foo', ' foo '], '(f|o)+\\b', ['foo'], 'Should match word boundaries'); + match(['a\\z', 'a/z', 'az'], 'a\\z', ['a/z']); }); }); @@ -240,9 +218,14 @@ describe('bash', function() { }); it('should support exclusions', function() { + match(['foob', 'foobb', 'foo', 'bar', 'baz', 'foobar'], '!(foo)b*', ['bar', 'baz']); + // Bash 4.3 says this should match `foo` too. Probably a bug in Bash since this is correct. + match(['foo', 'bar', 'baz', 'foobar'], '*(!(foo))', ['bar', 'baz', 'foobar']); + // Bash 4.3 says this should match `foo` and `foobar` too, probably a bug in Bash since this is correct. + match(['foo', 'bar', 'baz', 'foobar'], '!(foo)*', ['bar', 'baz']); + match(['moo.cow', 'moo', 'cow'], '!(*.*)', ['moo', 'cow']); match(['moo.cow', 'moo', 'cow'], '!(*.*).', []); - match(['foob', 'foobb'], '!(foo)b*', []); assert(!isMatch('f', '!(f)')); assert(!isMatch('f', '+(!(f))')); assert(!isMatch('f', '*(!(f))')); @@ -329,4 +312,68 @@ describe('bash', function() { match(['zoot'], '@(!(z*)|*x)', []); match(['zoox'], '@(!(z*)|*x)', ['zoox']); }); + + it('should support basic wildmatch features', function() { + assert(!isMatch('foo', '*f')); + assert(!isMatch('foo', '??')); + assert(!isMatch('foo', 'bar')); + assert(!isMatch('foobar', 'foo\\*bar')); + assert(!isMatch('abc', '\\a\\b\\c')); + assert(isMatch('', '')); + assert(isMatch('?a?b', '\\??\\?b')); + assert(isMatch('aaaaaaabababab', '*ab')); + assert(isMatch('\\x\\y\\z', '\\x\\y\\z')); + assert(isMatch('/x/y/z', '/x/y/z')); + assert(isMatch('f\\oo', 'f\\oo')); + assert(isMatch('foo', '*')); + assert(isMatch('foo', '*foo*')); + assert(isMatch('foo', '???')); + assert(isMatch('foo', 'f*')); + assert(isMatch('foo', 'foo')); + assert(isMatch('foo*', 'foo\\*', {unixify: false})); + assert(isMatch('foobar', '*ob*a*r*')); + }); + + it('Test recursion and the abort code', function() { + assert(isMatch('-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(!isMatch('-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(!isMatch('-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*', {unixify: false})); + assert(!isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*')); + assert(isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt', '**/*a*b*g*n*t')); + assert(!isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz', '**/*a*b*g*n*t')); + assert(!isMatch('foo', '*/*/*')); + assert(!isMatch('foo/bar', '*/*/*')); + assert(isMatch('foo/bba/arr', '*/*/*')); + assert(!isMatch('foo/bb/aa/rr', '*/*/*')); + assert(isMatch('foo/bb/aa/rr', '**/**/**')); + assert(isMatch('abcXdefXghi', '*X*i')); + assert(!isMatch('ab/cXd/efXg/hi', '*X*i')); + assert(isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i')); + assert(isMatch('ab/cXd/efXg/hi', '**/*X*/**/*i')); + }); + + it('Test pathName option', function() { + assert(!isMatch('ab/cXd/efXg/hi', '*Xg*i')); + assert(!isMatch('foo', '*/*/*')); + assert(!isMatch('foo', 'fo')); + assert(!isMatch('foo/bar', '*/*/*')); + assert(!isMatch('foo/bar', 'foo?bar')); + assert(!isMatch('foo/bb/aa/rr', '*/*/*')); + assert(!isMatch('foo/bba/arr', 'foo*')); + assert(!isMatch('foo/bba/arr', 'foo**')); + assert(!isMatch('foo/bba/arr', 'foo/*')); + assert(!isMatch('foo/bba/arr', 'foo/**arr')); + assert(!isMatch('foo/bba/arr', 'foo/**z')); + assert(!isMatch('foo/bba/arr', 'foo/*arr')); + assert(!isMatch('foo/bba/arr', 'foo/*z')); + assert(isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i')); + assert(isMatch('abcXdefXghi', '*X*i')); + assert(isMatch('foo', 'foo')); + assert(isMatch('foo/bar', 'foo/*')); + assert(isMatch('foo/bar', 'foo/bar')); + assert(isMatch('foo/bar', 'foo[/]bar')); + assert(isMatch('foo/bba/arr', '*/*/*')); + assert(isMatch('foo/bba/arr', 'foo/**')); + }); }); diff --git a/test/fixtures/a/b/c/d/e/z.js b/test/fixtures/a/b/c/d/e/z.js deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/a/b/c/d/z.js b/test/fixtures/a/b/c/d/z.js deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/a/b/c/z.js b/test/fixtures/a/b/c/z.js deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/a/b/z.js b/test/fixtures/a/b/z.js deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/a/z.js b/test/fixtures/a/z.js deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/ax b/test/fixtures/ax deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/b b/test/fixtures/b deleted file mode 100644 index e69de29b..00000000 diff --git a/test/fixtures/dotglob.txt b/test/fixtures/dotglob.txt new file mode 100644 index 00000000..67a8c882 --- /dev/null +++ b/test/fixtures/dotglob.txt @@ -0,0 +1,19 @@ +f a/b/.x **/.x/** +f .x **/.x/** +t .x/ **/.x/** +t .x/a **/.x/** +t .x/a/b **/.x/** +f .x/.x **/.x/** +f a/.x **/.x/** + +t a/b/.x/c **/.x/** +t a/b/.x/c/d **/.x/** +t a/b/.x/c/d/e **/.x/** +t a/b/.x/ **/.x/** +t a/.x/b **/.x/** +f a/.x/b/.x/c **/.x/** + +f .bashrc ?bashrc + +t .bar.baz/ .*.* +t .bar.baz .*.* diff --git a/test/fixtures/glob.txt b/test/fixtures/glob.txt new file mode 100644 index 00000000..e00a917a --- /dev/null +++ b/test/fixtures/glob.txt @@ -0,0 +1,81 @@ +f a/b/.x **/.x/** +f .x **/.x/** +t .x/ **/.x/** +t .x/a **/.x/** +t .x/a/b **/.x/** +f .x/.x **/.x/** +f a/.x **/.x/** + +t a/b/.x/c **/.x/** +t a/b/.x/c/d **/.x/** +t a/b/.x/c/d/e **/.x/** +t a/b/.x/ **/.x/** +t a/.x/b **/.x/** +f a/.x/b/.x/c **/.x/** + +t a/c/b a/*/b +f a/.d/b a/*/b +f a/./b a/*/b +f a/../b a/*/b + +t ab ab** +t abcdef ab** +t abef ab** +t abcfef ab** + +f ab ab***ef +t abcdef ab***ef +t abef ab***ef +t abcfef ab***ef + +f .bashrc ?bashrc + +f abbc ab?bc +f abc ab?bc + +t a.a [a-d]*.[a-b] +t a.b [a-d]*.[a-b] +t c.a [a-d]*.[a-b] +f a.a.a [a-d]*.[a-b] +t a.a.a [a-d]*.[a-b]*.[a-b] + +t a.a *.[a-b] +t a.b *.[a-b] +t a.a.a *.[a-b] +t c.a *.[a-b] +f d.a.d *.[a-b] +f a.bb *.[a-b] +f a.ccc *.[a-b] +f c.ccc *.[a-b] + +t a.a *.[a-b]* +t a.b *.[a-b]* +t a.a.a *.[a-b]* +t c.a *.[a-b]* +f d.a.d *.[a-b]* +f d.a.d *.[a-b]*.[a-b]* +t d.a.d *.[a-d]*.[a-d]* +t a.bb *.[a-b]* +f a.ccc *.[a-b]* +f c.ccc *.[a-b]* + +t a.a *[a-b].[a-b]* +t a.b *[a-b].[a-b]* +t a.a.a *[a-b].[a-b]* +f c.a *[a-b].[a-b]* +f d.a.d *[a-b].[a-b]* +t a.bb *[a-b].[a-b]* +f a.ccc *[a-b].[a-b]* +f c.ccc *[a-b].[a-b]* + +t abd [a-y]*[^c] +t abe [a-y]*[^c] +t bb [a-y]*[^c] +t bcd [a-y]*[^c] +t ca [a-y]*[^c] +t cb [a-y]*[^c] +t dd [a-y]*[^c] +t de [a-y]*[^c] +t bdir/ [a-y]*[^c] + +t abd **/* diff --git a/test/fixtures/globstar.txt b/test/fixtures/globstar.txt new file mode 100644 index 00000000..b3867594 --- /dev/null +++ b/test/fixtures/globstar.txt @@ -0,0 +1,30 @@ +t a.js **/*.js +t a/a.js **/*.js +t a/a/b.js **/*.js + +t a/b/z.js a/b/**/*.js +t a/b/c/z.js a/b/**/*.js + +t foo.md **/*.md +t foo/bar.md **/*.md + +t foo/bar foo/**/bar +t foo/bar foo/**bar + +t ab/a/d **/* +t ab/b **/* +t a/b/c/d/a.js **/* +t a/b/c.js **/* +t a/b/c.txt **/* +f a/b/.js/c.txt **/* +t a.js **/* +t za.js **/* +t ab **/* +t a.b **/* + +t foo/ foo/**/ +f foo/bar foo/**/ +f foo/bazbar foo/**/ +f foo/barbar foo/**/ +f foo/bar/baz/qux foo/**/ +t foo/bar/baz/qux/ foo/**/ diff --git a/test/fixtures/patterns.js b/test/fixtures/patterns.js new file mode 100644 index 00000000..8c7d0d27 --- /dev/null +++ b/test/fixtures/patterns.js @@ -0,0 +1,268 @@ +'use strict'; + +/** + * HEADS UP! Only tests for unsupported extglob features are commented out. + * + * The contents of this file was copied (and modified) from: + * minimatch v3.0.3, ISC LICENSE, Copyright (c) Isaac Z. Schlueter and Contributors + * https://github.com/isaacs/minimatch + */ + +var fixtures = ['a', 'b', 'c', 'd', 'abc', 'abd', 'abe', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/', 'bdir/cfile']; + +module.exports = [ + 'http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test', + ['a*', ['a', 'abc', 'abd', 'abe']], + ['X*', ['X*'], {nonull: true}], + + 'allow null glob expansion', + ['X*', []], + + 'micromatch has same results as Bash. Minimatch does this differently', + ['\\*', ['\\*'], {nonull: true}], + ['\\**', ['\\**'], {nonull: true}], + ['\\*\\*', ['\\*\\*'], {nonull: true}], + + ['b*/', ['bdir/']], + ['c*', ['c', 'ca', 'cb']], + ['**', fixtures], + + ['\\.\\./*/', ['\\.\\./*/'], {nonull: true}], + ['s/\\..*//', ['s/\\..*//'], {nonull: true}], + + 'legendary larry crashes bashes', + ['/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/', + ['/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/'], {nonull: true, bash: {skip: true}}], + ['/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\u0001/', + ['/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\u0001/'], {nonull: true, bash: {skip: true}}], + + /** + * Character classes + */ + + 'character classes', + ['[a-c]b*', ['abc', 'abd', 'abe', 'bb', 'cb']], + ['[a-y]*[^c]', ['abd', 'abe', 'bb', 'bcd', 'bdir/', 'ca', 'cb', 'dd', 'de']], + ['a*[^c]', ['abd', 'abe']], + function() { + fixtures.push('a-b', 'aXb'); + }, + ['a[X-]b', ['a-b', 'aXb']], + function() { + fixtures.push('.x', '.y'); + }, + ['[^a-c]*', ['d', 'dd', 'de']], + function() { + fixtures.push('a*b/', 'a*b/ooo', 'ab/ooo'); + }, + + 'trailing slashes', + ['a*b/*', ['ab/ooo', 'a*b/ooo']], + ['a*?/*', ['ab/ooo', 'a*b/ooo']], + ['a\\*b/*', ['a*b/ooo']], + ['a\\*?/*', ['a*b/ooo']], + ['*\\\\!*', [], {null: true}, ['echo !7']], + ['*\\!*', ['echo !7'], null, ['echo !7']], + ['*.\\*', ['r.*'], null, ['r.*']], + ['a[b]c', ['abc']], + ['a[\\\\b]c', ['abc']], + ['a?c', ['abc']], + ['a\\*c', [], {null: true}, ['abc']], + ['', [''], { null: true }, ['']], + + /** + * Bash tests + */ + + 'http://www.opensource.apple.com/source/bash/bash-23/bash/tests/glob-test', + function() { + fixtures.push('man/', 'man/man1/', 'man/man1/bash.1'); + }, + ['*/man*/bash.*', ['man/man1/bash.1']], + ['man/man1/bash.1', ['man/man1/bash.1']], + ['a***c', ['abc'], null, ['abc']], + ['a*****?c', ['abc'], null, ['abc']], + ['?*****??', ['abc'], null, ['abc']], + ['*****??', ['abc'], null, ['abc']], + ['?*****?c', ['abc'], null, ['abc']], + ['?***?****c', ['abc'], null, ['abc']], + ['?***?****?', ['abc'], null, ['abc']], + ['?***?****', ['abc'], null, ['abc']], + ['*******c', ['abc'], null, ['abc']], + ['*******?', ['abc'], null, ['abc']], + ['a*cd**?**??k', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a**?**cd**?**??k', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a**?**cd**?**??k***', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a**?**cd**?**??***k', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a**?**cd**?**??***k**', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a****c**?**??*****', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['[-abc]', ['-'], null, ['-']], + ['[abc-]', ['-'], null, ['-']], + ['\\', ['\\'], null, ['\\']], + ['[\\\\]', ['\\'], null, ['\\']], + ['[[]', ['['], null, ['[']], + ['[', ['['], null, ['[']], + ['[*', ['[abc'], null, ['[abc']], + + 'a right bracket shall lose its special meaning and represent itself in a bracket expression if it occurs first in the list. -- POSIX.2 2.8.3.2', + ['[]]', [']'], null, [']']], + ['[]-]', [']'], null, [']']], + ['[a-\z]', ['p'], null, ['p']], + ['??**********?****?', [], { null: true }, ['abc']], + ['??**********?****c', [], { null: true }, ['abc']], + ['?************c****?****', [], { null: true }, ['abc']], + ['*c*?**', [], { null: true }, ['abc']], + ['a*****c*?**', [], { null: true }, ['abc']], + ['a********???*******', [], { null: true }, ['abc']], + ['[]', [], { null: true }, ['a']], + ['[abc', [], { null: true }, ['[']], + + 'nocase tests', + ['XYZ', ['xYz'], { nocase: true, null: true }, + ['xYz', 'ABC', 'IjK']], + [ + 'ab*', + ['ABC'], + { nocase: true, null: true }, + ['xYz', 'ABC', 'IjK'] + ], + [ + '[ia]?[ck]', + ['ABC', 'IjK'], + { nocase: true, null: true }, + ['xYz', 'ABC', 'IjK'] + ], + + 'braces: onestar/twostar', + ['{/*,*}', [], {null: true}, ['/asdf/asdf/asdf']], + // ['{/?,*}', ['/a', 'bb'], {null: true}, ['/a', '/b/b', '/a/b/c', 'bb']], + + 'dots should not match unless requested', + ['**', ['a/b'], {}, ['a/b', 'a/.d', '.a/.d']], + + // .. and . can only match patterns starting with ., + // even when options.dot is set. + function() { + fixtures = ['a/./b', 'a/../b', 'a/c/b', 'a/.d/b']; + }, + ['a/*/b', ['a/c/b', 'a/.d/b'], {dot: true}], + ['a/*/b', ['a/c/b'], {dot: false}], + + ['a/.*/b', ['a/./b', 'a/../b', 'a/.d/b'], {dot: true}], + ['a/.*/b', ['a/./b', 'a/../b', 'a/.d/b'], {dot: false}], + + // this also tests that changing the options needs + // to change the cache key, even if the pattern is + // the same! + ['**', + ['a/b', 'a/.d', '.a/.d'], + { dot: true }, + [ '.a/.d', 'a/.d', 'a/b'] + ], + + // // 'paren sets cannot contain slashes', + // // ['*(a/b)', ['*(a/b)'], {nonull: true}, ['a/b']], + + // // brace sets trump all else. + // // + // // invalid glob pattern. fails on bash4 and bsdglob. + // // however, in this implementation, it's easier just + // // to do the intuitive thing, and let brace-expansion + // // actually come before parsing any extglob patterns, + // // like the documentation seems to say. + // // + // // XXX: if anyone complains about this, either fix it + // // or tell them to grow up and stop complaining. + // // + // // bash/bsdglob says this: + // // , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]] + // // but we do this instead: + // // ['*(a|{b),c)}', ['a', 'ab', 'ac'], {}, ['a', 'ab', 'ac', 'ad']], + + // test partial parsing in the presence of comment/negation chars + ['[!a*', ['[!ab'], {}, ['[!ab', '[ab']], + +// // crazy nested {,,} and *(||) tests. +// function() { +// fixtures = [ +// 'a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'bc', 'cb', 'bc,d', +// 'c,db', 'c,d', 'd)', '(b|c', '*(b|c', 'b|c', 'b|cc', 'cb|c', +// 'x(a|b|c)', 'x(a|c)', '(a|b|c)', '(a|c)' +// ]; +// }, +// ['*(a|{b,c})', ['a', 'b', 'c', 'ab', 'ac']], +// ['{a,*(b|c,d)}', ['a', '(b|c', '*(b|c', 'd)']], +// // a +// // *(b|c) +// // *(b|d) +// ['{a,*(b|{c,d})}', ['a', 'b', 'bc', 'cb', 'c', 'd']], +// ['*(a|{b|c,c})', ['a', 'b', 'c', 'ab', 'ac', 'bc', 'cb']], + +// // test various flag settings. +// [ +// '*(a|{b|c,c})', +// ['x(a|b|c)', 'x(a|c)', '(a|b|c)', '(a|c)'], +// { noext: true } +// ], + + ['a?b', ['acb', 'acb/'], {}, ['x/y/acb', 'acb', 'acb/', 'acb/d/e']], + ['a?b', ['x/y/acb', 'acb/', 'acb'], {matchBase: true}, ['x/y/acb', 'acb', 'acb/', 'acb/d/e']], + + // begin channelling Boole and deMorgan... + 'negation tests', + function() { + fixtures = ['d', 'e', '!ab', '!abc', 'a!b', '\\!a']; + }, + + // anything that is NOT a* matches. + ['!a*', ['\\!a', 'd', 'e', '!ab', '!abc']], + + // anything that IS !a* matches. + ['!a*', ['!ab', '!abc'], {nonegate: true}], + + // anything that IS a* matches + ['a*', ['a!b']], + + // anything that is NOT !a* matches + ['!\\!a*', ['a!b', 'd', 'e', '\\!a']], + + // negation nestled within a pattern + function() { + fixtures = [ + 'foo.js', + 'foo.bar', + 'foo.js.js', + 'blar.js', + 'foo.', + 'boo.js.boo' + ]; + }, + // last one is tricky! * matches foo, . matches ., and 'js.js' != 'js' + // copy bash 4.3 behavior on this. + + 'https://github.com/isaacs/minimatch/issues/5', + function() { + fixtures = [ + 'a/b/.x/c', 'a/b/.x/c/d', 'a/b/.x/c/d/e', 'a/b/.x', 'a/b/.x/', + 'a/.x/b', '.x', '.x/', '.x/a', '.x/a/b', 'a/.x/b/.x/c', '.x/.x' + ]; + }, + [ + '**/.x/**', + [ + '.x/', '.x/a', '.x/a/b', 'a/.x/b', 'a/b/.x/', 'a/b/.x/c', + 'a/b/.x/c/d', 'a/b/.x/c/d/e' + ] + ], + + 'https://github.com/isaacs/minimatch/issues/59', + ['[z-a]', []], + ['a/[2015-03-10T00:23:08.647Z]/z', []], + ['[a-0][a-\u0100]', []] +]; + +Object.defineProperty(module.exports, 'fixtures', { + get: function() { + return fixtures; + } +}); diff --git a/test/fixtures/z.js b/test/fixtures/z.js deleted file mode 100644 index e69de29b..00000000 diff --git a/test/globstars.js b/test/globstars.js index b7a6726f..4b06ee4e 100644 --- a/test/globstars.js +++ b/test/globstars.js @@ -1,20 +1,104 @@ 'use strict'; var assert = require('assert'); -var mm = require('..'); +var nm = require('./support/match'); describe('globstars', function() { - it('should match double star patterns', function() { - assert(!mm.isMatch('.gitignore', 'a/**/z/*.md')); - assert(!mm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/j/**/z/*.md')); - assert(!mm.isMatch('a/b/c/j/e/z/foo.txt', 'a/**/j/**/z/*.md')); - assert(!mm.isMatch('a/b/z/.dotfile', 'a/**/z/*.md')); - assert(!mm.isMatch('a/b/z/.dotfile.md', '**/c/.*.md')); - - assert(mm.isMatch('a/b/c/d/e/j/n/p/o/z/foo.md', 'a/**/j/**/z/*.md')); - assert(mm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/z/*.md')); - assert(mm.isMatch('a/b/c/j/e/z/foo.md', 'a/**/j/**/z/*.md')); - assert(mm.isMatch('a/b/z/.dotfile.md', '**/.*.md')); - assert(mm.isMatch('a/b/z/.dotfile.md', 'a/**/z/.*.md')); + it('should support globstars (**)', function() { + var fixtures = ['.a/a', 'a/a', 'a/.a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z', 'a/../a', 'ab/../ac', '../a', 'a', '../../b', '../c', '../c/d']; + + nm(fixtures, '**', ['a', 'a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + nm(fixtures, '**/**', ['a', 'a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + nm(fixtures, '**/', []); + nm(fixtures, '**/**/*', ['a', 'a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + nm(fixtures, '**/**/x', ['a/x']); + nm(fixtures, '**/x', ['a/x']); + nm(fixtures, '**/x/*', ['a/x/y']); + nm(fixtures, '*/x/**', ['a/x/y', 'a/x/y/z']); + nm(fixtures, '**/x/**', ['a/x/y', 'a/x/y/z']); + nm(fixtures, '**/x/*/*', ['a/x/y/z']); + nm(fixtures, 'a/**', ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + nm(fixtures, 'a/**/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + nm(fixtures, 'a/**/**/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + nm(fixtures, 'b/**', []); + + assert(!nm.isMatch('a/b', 'a/**/')); + assert(!nm.isMatch('a/b/.js/c.txt', '**/*')); + assert(!nm.isMatch('a/b/c/d', 'a/**/')); + assert(!nm.isMatch('a/bb', 'a/**/')); + assert(!nm.isMatch('a/cb', 'a/**/')); + assert(nm.isMatch('a.b', '**/*')); + assert(nm.isMatch('a.js', '**/*')); + assert(nm.isMatch('a.js', '**/*.js')); + assert(nm.isMatch('a.md', '**/*.md')); + assert(nm.isMatch('a/', 'a/**/')); + assert(nm.isMatch('a/a.js', '**/*.js')); + assert(nm.isMatch('a/a/b.js', '**/*.js')); + assert(nm.isMatch('a/b', 'a/**/b')); + assert(nm.isMatch('a/b', 'a/**b')); + assert(nm.isMatch('a/b.md', '**/*.md')); + assert(nm.isMatch('a/b/c.js', '**/*')); + assert(nm.isMatch('a/b/c.txt', '**/*')); + assert(nm.isMatch('a/b/c/d/', 'a/**/')); + assert(nm.isMatch('a/b/c/d/a.js', '**/*')); + assert(nm.isMatch('a/b/c/z.js', 'a/b/**/*.js')); + assert(nm.isMatch('a/b/z.js', 'a/b/**/*.js')); + assert(nm.isMatch('ab', '**/*')); + assert(nm.isMatch('ab/a/d', '**/*')); + assert(nm.isMatch('ab/b', '**/*')); + assert(nm.isMatch('za.js', '**/*')); + }); + + it('should support multiple globstars in one pattern', function() { + assert(!nm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/j/**/z/*.md')); + assert(!nm.isMatch('a/b/c/j/e/z/foo.txt', 'a/**/j/**/z/*.md')); + assert(nm.isMatch('a/b/c/d/e/j/n/p/o/z/foo.md', 'a/**/j/**/z/*.md')); + assert(nm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/z/*.md')); + assert(nm.isMatch('a/b/c/j/e/z/foo.md', 'a/**/j/**/z/*.md')); + }); + + it('should match dotfiles', function() { + var fixtures = ['.gitignore', 'a/b/z/.dotfile', 'a/b/z/.dotfile.md', 'a/b/z/.dotfile.md', 'a/b/z/.dotfile.md']; + assert(!nm.isMatch('.gitignore', 'a/**/z/*.md')); + assert(!nm.isMatch('a/b/z/.dotfile', 'a/**/z/*.md')); + assert(!nm.isMatch('a/b/z/.dotfile.md', '**/c/.*.md')); + assert(nm.isMatch('a/b/z/.dotfile.md', '**/.*.md')); + assert(nm.isMatch('a/b/z/.dotfile.md', 'a/**/z/.*.md')); + nm(fixtures, 'a/**/z/.*.md', [ 'a/b/z/.dotfile.md' ]); + }); + + it('should match file extensions:', function() { + nm(['.md', 'a.md', 'a/b/c.md', '.txt'], '**/*.md', ['a.md', 'a/b/c.md']); + nm(['.md', 'a/b/.md'], '**/.md', ['.md', 'a/b/.md']); + }); + + it('should respect trailing slashes on paterns', function() { + var fixtures = ['a', 'a/', 'b', 'b/', 'a/a', 'a/a/', 'a/b', 'a/b/', 'a/c', 'a/c/', 'a/x', 'a/x/', 'a/a/a', 'a/a/b', 'a/a/b/', 'a/a/a/', 'a/a/a/a', 'a/a/a/a/', 'a/a/a/a/a', 'a/a/a/a/a/', 'x/y', 'z/z', 'x/y/', 'z/z/', 'a/b/c/.d/e/']; + nm(fixtures, '**/*/a/', ['a/a/', 'a/a/a/', 'a/a/a/a/', 'a/a/a/a/a/']); + nm(fixtures, '**/*/a/*/', ['a/a/a/', 'a/a/a/a/', 'a/a/a/a/a/', 'a/a/b/']); + nm(fixtures, '**/*/x/', ['a/x/']); + nm(fixtures, '**/*/*/*/*/', ['a/a/a/a/', 'a/a/a/a/a/']); + nm(fixtures, '**/*/*/*/*/*/', ['a/a/a/a/a/']); + nm(fixtures, '*a/a/*/', ['a/a/a/', 'a/a/b/']); + nm(fixtures, '**a/a/*/', ['a/a/a/', 'a/a/b/']); + nm(fixtures, '**/a/*/*/', ['a/a/a/', 'a/a/b/', 'a/a/a/a/', 'a/a/a/a/a/']); + nm(fixtures, '**/a/*/*/*/', ['a/a/a/a/', 'a/a/a/a/a/']); + nm(fixtures, '**/a/*/*/*/*/', ['a/a/a/a/a/']); + nm(fixtures, '**/a/*/a/', ['a/a/a/', 'a/a/a/a/', 'a/a/a/a/a/']); + nm(fixtures, '**/a/*/b/', ['a/a/b/']); + }); + + it('should match literal globstars when escaped', function() { + var fixtures = ['.md', '**a.md', '**.md', '.md', '**']; + nm(fixtures, '\\*\\**.md', ['**a.md', '**.md']); + nm(fixtures, '\\*\\*.md', ['**.md']); + }); + + // related to https://github.com/isaacs/minimatch/issues/67 + it('should work consistently with `makeRe` and matcher functions', function() { + var re = nm.makeRe('node_modules/foobar/**/*.bar'); + assert(re.test('node_modules/foobar/foo.bar')); + assert(nm.isMatch('node_modules/foobar/foo.bar', 'node_modules/foobar/**/*.bar')); + nm(['node_modules/foobar/foo.bar'], 'node_modules/foobar/**/*.bar', ['node_modules/foobar/foo.bar']); }); }); diff --git a/test/integration.js b/test/integration.js new file mode 100644 index 00000000..8ce277b2 --- /dev/null +++ b/test/integration.js @@ -0,0 +1,16 @@ +'use strict'; + +var assert = require('assert'); +var mm = require('..'); + +describe('globstars', function() { + it('with char classes', function() { + var fixtures = ['a.b', 'a,b', 'a:b', 'a-b', 'a;b', 'a b', 'a_b']; + assert.deepEqual(mm.match(fixtures, 'a[^[:alnum:]]b'), fixtures); + assert.deepEqual(mm.match(fixtures, 'a@([^[:alnum:]])b'), fixtures); + assert.deepEqual(mm.match(fixtures, 'a@([-.,:; _])b'), fixtures); + + assert.deepEqual(mm.match(fixtures, 'a@([^x])b'), ['a,b', 'a:b', 'a-b', 'a;b', 'a b', 'a_b']); + assert.deepEqual(mm.match(fixtures, 'a+([^[:alnum:]])b'), fixtures); + }); +}); diff --git a/test/isMatch.js b/test/isMatch.js deleted file mode 100644 index 8655d42a..00000000 --- a/test/isMatch.js +++ /dev/null @@ -1,251 +0,0 @@ -'use strict'; - -var assert = require('assert'); -var mm = require('..'); - -describe('.isMatch()', function() { - describe('errors:', function() { - it('should throw on undefined args:', function() { - assert.throws(function() { - mm.isMatch(); - }, /expected pattern to be a string/); - }); - - it('should throw on bad args:', function() { - assert.throws(function() { - mm.isMatch({}); - }, /expected pattern to be a string/); - }); - }); - - it('should escape plus signs to match string literals', function() { - assert(mm.isMatch('a+b/src/glimini.js', 'a+b/src/*.js')); - assert(mm.isMatch('+b/src/glimini.js', '+b/src/*.js')); - assert(mm.isMatch('coffee+/src/glimini.js', 'coffee+/src/*.js')); - assert(mm.isMatch('coffee+/src/glimini.js', 'coffee+/src/*.js')); - assert(mm.isMatch('coffee+/src/glimini.js', 'coffee+/src/*')); - }); - - it('should correctly deal with empty globs', function() { - assert(!mm.isMatch('ab', '')); - assert(!mm.isMatch('a', '')); - assert(!mm.isMatch('.', '')); - }); - - it('should match with non-glob patterns', function() { - assert(mm.isMatch('.', '.')); - assert(mm.isMatch('/a', '/a')); - assert(!mm.isMatch('/ab', '/a')); - assert(mm.isMatch('a', 'a')); - assert(!mm.isMatch('ab', '/a')); - assert(!mm.isMatch('ab', 'a')); - assert(mm.isMatch('ab', 'ab')); - assert(!mm.isMatch('abcd', 'cd')); - assert(!mm.isMatch('abcd', 'bc')); - assert(!mm.isMatch('abcd', 'ab')); - }); - - it('should match file names:', function() { - assert(mm.isMatch('a.b', 'a.b')); - assert(mm.isMatch('a.b', '*.b')); - assert(mm.isMatch('a.b', 'a.*')); - assert(mm.isMatch('a.b', '*.*')); - assert(mm.isMatch('a-b.c-d', 'a*.c*')); - assert(mm.isMatch('a-b.c-d', '*b.*d')); - assert(mm.isMatch('a-b.c-d', '*.*')); - assert(mm.isMatch('a-b.c-d', '*.*-*')); - assert(mm.isMatch('a-b.c-d', '*-*.*-*')); - assert(mm.isMatch('a-b.c-d', '*.c-*')); - assert(mm.isMatch('a-b.c-d', '*.*-d')); - assert(mm.isMatch('a-b.c-d', 'a-*.*-d')); - assert(mm.isMatch('a-b.c-d', '*-b.c-*')); - assert(mm.isMatch('a-b.c-d', '*-b*c-*')); - - // false - assert(!mm.isMatch('a-b.c-d', '*-bc-*')); - }); - - it('should match with common glob patterns', function() { - assert(mm.isMatch('/ab', '/*')); - assert(mm.isMatch('/cd', '/*')); - assert(!mm.isMatch('ef', '/*')); - assert(!mm.isMatch('ab', './*')); - assert(mm.isMatch('ab', '*')); - assert(mm.isMatch('ab', 'ab')); - }); - - it('should match files with the given extension:', function() { - assert(!mm.isMatch('.md', '*.md')); - assert(mm.isMatch('.md', '.md')); - assert(!mm.isMatch('.c.md', '*.md')); - assert(mm.isMatch('.c.md', '.*.md')); - assert(mm.isMatch('c.md', '*.md')); - assert(mm.isMatch('c.md', '*.md')); - assert(!mm.isMatch('a/b/c/c.md', '*.md')); - assert(!mm.isMatch('a/b/c.md', 'a/*.md')); - assert(mm.isMatch('a/b/c.md', 'a/*/*.md')); - assert(mm.isMatch('a/b/c.md', '**/*.md')); - assert(mm.isMatch('a/b/c.js', 'a/**/*.*')); - }); - - it('should match wildcards:', function() { - assert(!mm.isMatch('a/b/c/z.js', '*.js')); - assert(!mm.isMatch('a/b/z.js', '*.js')); - assert(!mm.isMatch('a/z.js', '*.js')); - assert(mm.isMatch('z.js', '*.js')); - - assert(mm.isMatch('z.js', 'z*.js')); - assert(mm.isMatch('a/z.js', 'a/z*.js')); - assert(mm.isMatch('a/z.js', '*/z*.js')); - }); - - it('should match globstars:', function() { - assert(mm.isMatch('a/b/c/z.js', '**/*.js')); - assert(mm.isMatch('a/b/z.js', '**/*.js')); - assert(mm.isMatch('a/z.js', '**/*.js')); - assert(mm.isMatch('a/b/c/d/e/z.js', 'a/b/**/*.js')); - assert(mm.isMatch('a/b/c/d/z.js', 'a/b/**/*.js')); - assert(mm.isMatch('a/b/c/z.js', 'a/b/c/**/*.js')); - assert(mm.isMatch('a/b/c/z.js', 'a/b/c**/*.js')); - assert(mm.isMatch('a/b/c/z.js', 'a/b/**/*.js')); - assert(mm.isMatch('a/b/z.js', 'a/b/**/*.js')); - - assert(!mm.isMatch('a/z.js', 'a/b/**/*.js')); - assert(!mm.isMatch('z.js', 'a/b/**/*.js')); - - // issue #23 - assert(!mm.isMatch('zzjs', 'z*.js')); - assert(!mm.isMatch('zzjs', '*z.js')); - - // issue #24 - assert(mm.isMatch('a', '**')); - assert(!mm.isMatch('a', 'a/**')); - assert(mm.isMatch('a/', '**')); - assert(mm.isMatch('a/b/c/d', '**')); - assert(mm.isMatch('a/b/c/d/', '**')); - assert(mm.isMatch('a/b/c/d/', '**/**')); - assert(mm.isMatch('a/b/c/d/', '**/b/**')); - assert(mm.isMatch('a/b/c/d/', 'a/b/**')); - assert(mm.isMatch('a/b/c/d/', 'a/b/**/')); - assert(mm.isMatch('a/b/c/d/', 'a/b/**/c/**/')); - assert(mm.isMatch('a/b/c/d/', 'a/b/**/c/**/d/')); - assert(!mm.isMatch('a/b/c/d/', 'a/b/**/f')); - assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/**/*.*')); - assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/*.*')); - assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/c/**/d/*.*')); - assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/d/**/*.*')); - assert(mm.isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*')); - assert(mm.isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*')); - - // issue #15 - assert(mm.isMatch('z.js', 'z*')); - assert(mm.isMatch('z.js', '**/z*')); - assert(mm.isMatch('z.js', '**/z*.js')); - assert(mm.isMatch('z.js', '**/*.js')); - assert(mm.isMatch('foo', '**/foo')); - - assert(mm.isMatch('a/b-c/z.js', 'a/b-*/**/z.js')); - assert(mm.isMatch('a/b-c/d/e/z.js', 'a/b-*/**/z.js')); - }); - - /** - * 1. micromatch differs from spec - * 2. minimatch differs from spec - * 3. both micromatch and minimatch differ from spec - */ - - it('Extended slash-matching features', function() { - assert(!mm.isMatch('foo/baz/bar', 'foo*bar')); - assert(!mm.isMatch('foo/baz/bar', 'foo**bar')); - assert(mm.isMatch('foobazbar', 'foo**bar')); // 3 - assert(mm.isMatch('foo/baz/bar', 'foo/**/bar')); - assert(mm.isMatch('foo/baz/bar', 'foo/**/**/bar')); - assert(mm.isMatch('foo/b/a/z/bar', 'foo/**/bar')); - assert(mm.isMatch('foo/b/a/z/bar', 'foo/**/**/bar')); - assert(mm.isMatch('foo/bar', 'foo/**/bar')); - assert(mm.isMatch('foo/bar', 'foo/**/**/bar')); - assert(!mm.isMatch('foo/bar', 'foo?bar')); - assert(mm.isMatch('foo/bar', 'foo[/]bar')); // 2 - assert(!mm.isMatch('foo', 'foo/**')); - assert(mm.isMatch('XXX/foo', '**/foo')); - assert(mm.isMatch('bar/baz/foo', '**/foo')); - assert(!mm.isMatch('bar/baz/foo', '*/foo')); - assert(!mm.isMatch('foo/bar/baz', '**/bar*')); - assert(mm.isMatch('deep/foo/bar/baz', '**/bar/*')); - assert(!mm.isMatch('deep/foo/bar/baz/', '**/bar/*')); - assert(mm.isMatch('deep/foo/bar/baz/', '**/bar/**')); - assert(!mm.isMatch('deep/foo/bar', '**/bar/*')); - assert(mm.isMatch('deep/foo/bar/', '**/bar/**')); - assert(!mm.isMatch('foo/bar/baz', '**/bar**')); - assert(mm.isMatch('foo/bar/baz/x', '*/bar/**')); - assert(!mm.isMatch('deep/foo/bar/baz/x', '*/bar/**')); - assert(mm.isMatch('deep/foo/bar/baz/x', '**/bar/*/*')); - assert(mm.isMatch('a/j/z/x.md', 'a/**/j/**/z/*.md')); - assert(mm.isMatch('a/b/j/c/z/x.md', 'a/**/j/**/z/*.md')); - }); - - it('question marks should not match slashes:', function() { - assert(!mm.isMatch('aaa/bbb', 'aaa?bbb')); - }); - - it('should not match dotfiles when `dot` or `dotfiles` are not set:', function() { - assert(!mm.isMatch('.c.md', '*.md')); - assert(!mm.isMatch('a/.c.md', '*.md')); - assert(mm.isMatch('a/.c.md', 'a/.c.md')); - assert(!mm.isMatch('.a', '*.md')); - assert(!mm.isMatch('.verb.txt', '*.md')); - assert(mm.isMatch('a/b/c/.xyz.md', 'a/b/c/.*.md')); - assert(mm.isMatch('.md', '.md')); - assert(!mm.isMatch('.txt', '.md')); - assert(mm.isMatch('.md', '.md')); - assert(mm.isMatch('.a', '.a')); - assert(mm.isMatch('.b', '.b*')); - assert(mm.isMatch('.ab', '.a*')); - assert(mm.isMatch('.ab', '.*')); - assert(!mm.isMatch('.ab', '*.*')); - assert(!mm.isMatch('.md', 'a/b/c/*.md')); - assert(!mm.isMatch('.a.md', 'a/b/c/*.md')); - assert(mm.isMatch('a/b/c/d.a.md', 'a/b/c/*.md')); - assert(!mm.isMatch('a/b/d/.md', 'a/b/c/*.md')); - }); - - it('should match dotfiles when `dot` or `dotfiles` is set:', function() { - assert(mm.isMatch('.c.md', '*.md', {dot: true})); - assert(mm.isMatch('.c.md', '.*', {dot: true})); - assert(mm.isMatch('a/b/c/.xyz.md', 'a/b/c/*.md', {dot: true})); - assert(mm.isMatch('a/b/c/.xyz.md', 'a/b/c/.*.md', {dot: true})); - }); - - it('should match file paths:', function() { - assert(mm.isMatch('a/b/c/xyz.md', 'a/b/c/*.md')); - assert(mm.isMatch('a/bb/c/xyz.md', 'a/*/c/*.md')); - assert(mm.isMatch('a/bbbb/c/xyz.md', 'a/*/c/*.md')); - assert(mm.isMatch('a/bb.bb/c/xyz.md', 'a/*/c/*.md')); - assert(mm.isMatch('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md')); - assert(mm.isMatch('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md')); - }); - - it('should match full file paths:', function() { - assert(!mm.isMatch('a/.b', 'a/**/z/*.md')); - assert(mm.isMatch('a/.b', 'a/.*')); - assert(!mm.isMatch('a/b/z/.a', 'a/**/z/*.a')); - assert(!mm.isMatch('a/b/z/.a', 'a/*/z/*.a')); - assert(mm.isMatch('a/b/z/.a', 'a/*/z/.a')); - assert(mm.isMatch('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); - assert(mm.isMatch('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); - assert(!mm.isMatch('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md')); - }); - - it('should match paths with leading `./`:', function() { - assert(!mm.isMatch('./.a', 'a/**/z/*.md')); - assert(!mm.isMatch('./a/b/z/.a', 'a/**/z/.a')); - assert(mm.isMatch('./a/b/z/.a', './a/**/z/.a')); - assert(!mm.isMatch('./a/b/c/d/e/z/c.md', 'a/**/z/*.md')); - assert(mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/z/*.md')); - assert(!mm.isMatch('./a/b/c/d/e/z/c.md', './a/**/j/**/z/*.md')); - assert(mm.isMatch('./a/b/c/j/e/z/c.md', './a/**/j/**/z/*.md')); - assert(!mm.isMatch('./a/b/c/j/e/z/c.md', 'a/**/j/**/z/*.md')); - assert(mm.isMatch('./a/b/c/d/e/j/n/p/o/z/c.md', './a/**/j/**/z/*.md')); - assert(!mm.isMatch('./a/b/c/j/e/z/c.txt', './a/**/j/**/z/*.md')); - }); -}); diff --git a/test/issue-related.js b/test/issue-related.js index 7bfc47bd..4aa12e9c 100644 --- a/test/issue-related.js +++ b/test/issue-related.js @@ -1,34 +1,62 @@ 'use strict'; var assert = require('assert'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var matcher = argv.mm ? require('minimatch') : require('..'); -var isMatch = argv.mm ? matcher : matcher.isMatch; +var nm = require('./support/match'); describe('issue-related tests', function() { + // see https://github.com/jonschlinkert/micromatch/issues/15 + it('issue #15', function() { + assert(nm.isMatch('a/b-c/d/e/z.js', 'a/b-*/**/z.js')); + assert(nm.isMatch('z.js', 'z*')); + assert(nm.isMatch('z.js', '**/z*')); + assert(nm.isMatch('z.js', '**/z*.js')); + assert(nm.isMatch('z.js', '**/*.js')); + assert(nm.isMatch('foo', '**/foo')); + }); + + // see https://github.com/jonschlinkert/micromatch/issues/23 it('issue #23', function() { - assert(!isMatch('zzjs', 'z*.js')); - assert(!isMatch('zzjs', '*z.js')); + assert(!nm.isMatch('zzjs', 'z*.js')); + assert(!nm.isMatch('zzjs', '*z.js')); }); + // see https://github.com/jonschlinkert/micromatch/issues/24 it('issue #24', function() { - assert(!isMatch('a', 'a/**')); - assert(!isMatch('a/b/c/d/', 'a/b/**/f')); - assert(isMatch('a', '**')); - assert(isMatch('a/', '**')); - assert(isMatch('a/b/c/d', '**')); - assert(isMatch('a/b/c/d/', '**')); - assert(isMatch('a/b/c/d/', '**/**')); - assert(isMatch('a/b/c/d/', '**/b/**')); - assert(isMatch('a/b/c/d/', 'a/b/**')); - assert(isMatch('a/b/c/d/', 'a/b/**/')); - assert(isMatch('a/b/c/d/e.f', 'a/b/**/**/*.*')); - assert(isMatch('a/b/c/d/e.f', 'a/b/**/*.*')); - assert(isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*')); - assert(isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*')); + assert(!nm.isMatch('a', 'a/**')); + assert(!nm.isMatch('a/b/c/d/', 'a/b/**/f')); + assert(nm.isMatch('a', '**')); + assert(nm.isMatch('a/', '**')); + assert(nm.isMatch('a/b/c/d', '**')); + assert(nm.isMatch('a/b/c/d/', '**')); + assert(nm.isMatch('a/b/c/d/', '**/**')); + assert(nm.isMatch('a/b/c/d/', '**/b/**')); + assert(nm.isMatch('a/b/c/d/', 'a/b/**')); + assert(nm.isMatch('a/b/c/d/', 'a/b/**/')); + assert(nm.isMatch('a/b/c/d/e.f', 'a/b/**/**/*.*')); + assert(nm.isMatch('a/b/c/d/e.f', 'a/b/**/*.*')); + assert(nm.isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*')); + assert(nm.isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*')); }); - it('issue #15', function() { - assert(isMatch('a/b-c/d/e/z.js', 'a/b-*/**/z.js')); + // see https://github.com/jonschlinkert/micromatch/issues/59 + it('should only match nested directories when `**` is the only thing in a segment', function() { + assert(!nm.isMatch('a/b/c', 'a/b**')); + assert(!nm.isMatch('a/c/b', 'a/**b')); + }); + + // see https://github.com/jonschlinkert/micromatch/issues/63 + it('issue #63', function() { + assert(nm.isMatch('/aaa/bbb/foo', '/aaa/bbb/**')); + assert(nm.isMatch('/aaa/bbb/', '/aaa/bbb/**')); + assert(nm.isMatch('/aaa/bbb/foo.git', '/aaa/bbb/**')); + assert(!nm.isMatch('/aaa/bbb/.git', '/aaa/bbb/**')); + assert(!nm.isMatch('aaa/bbb/.git', 'aaa/bbb/**')); + assert(!nm.isMatch('/aaa/bbb/ccc/.git', '/aaa/bbb/**')); + assert(!nm.isMatch('/aaa/.git/foo', '/aaa/**/*')); + assert(nm.isMatch('/aaa/.git/foo', '/aaa/**/*', {dot: true})); + assert(nm.isMatch('/aaa/bbb/.git', '/aaa/bbb/*', {dot: true})); + assert(nm.isMatch('aaa/bbb/.git', 'aaa/bbb/**', {dot: true})); + assert(nm.isMatch('/aaa/bbb/.git', '/aaa/bbb/**', {dot: true})); + assert(nm.isMatch('/aaa/bbb/ccc/.git', '/aaa/bbb/**', {dot: true})); }); }); diff --git a/test/malicious.js b/test/malicious.js new file mode 100644 index 00000000..e4757e88 --- /dev/null +++ b/test/malicious.js @@ -0,0 +1,30 @@ +'use strict'; + +var assert = require('assert'); +var argv = require('yargs-parser')(process.argv.slice(2)); +var matcher = argv.mm ? require('minimatch') : require('..'); +var isMatch = argv.mm ? matcher : matcher.isMatch; + +/** + * These tests are based on minimatch unit tests + */ + +function generate(len, ch) { + var pattern = ''; + while (--len) pattern += ch; + return pattern; +} + +describe('handling of potential regex exploits', function() { + it('should support long escape sequences', function() { + assert(isMatch('A', '!(' + generate(1024 * 2, '\\') + 'A)'), 'within the limits, and valid match'); + assert(!isMatch('A', '[!(' + generate(1024 * 2, '\\') + 'A'), 'within the limits, but invalid regex'); + }); + + it('should throw an error when the pattern is too long', function() { + assert.throws(function() { + var exploit = '!(' + generate(1024 * 64, '\\') + 'A)'; + assert(!isMatch('A', exploit)); + }, /expected pattern to be less than 65536 characters/); + }); +}); diff --git a/test/minimatch.js b/test/minimatch.js new file mode 100644 index 00000000..94ed4ca5 --- /dev/null +++ b/test/minimatch.js @@ -0,0 +1,33 @@ +'use strict'; + +var match = require('./support/match'); +var patterns = require('./fixtures/patterns'); + +describe('basic tests', function() { + patterns.forEach(function(unit, i) { + // if (unit[0] !== '[\\\\]') return; + + it(i + ': ' + unit[0], function() { + if (typeof unit === 'string') { + console.log(); + console.log(' ', unit); + return; + } + + // update fixtures list + if (typeof unit === 'function') { + return unit(); + } + + var pattern = unit[0]; + var expected = (unit[1] || []).sort(compare); + var options = unit[2] || {}; + var fixtures = unit[3] || patterns.fixtures; + match(fixtures, pattern, expected, options); + }); + }); +}); + +function compare(a, b) { + return a === b ? 0 : a > b ? 1 : -1; +} diff --git a/test/minimatch/basic.js b/test/minimatch/basic.js deleted file mode 100644 index b6a61f63..00000000 --- a/test/minimatch/basic.js +++ /dev/null @@ -1,131 +0,0 @@ -var path = require('path'); -var should = require('should'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var mm = require('../..'); - -if ('minimatch' in argv) { - mm = require('minimatch'); -} - -it('minimatch tests:', function() { - // http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test - mm.makeRe('a*').should.eql(/^(?:(?=.)a[^/]*?)$/); - mm.makeRe('X*', {nonull: true}).should.eql(/^(?:(?=.)X[^/]*?)$/); - mm.makeRe('X*').should.eql(/^(?:(?=.)X[^/]*?)$/); - mm.makeRe('\\*', {nonull: true}).should.eql(/^(?:\*)$/); - mm.makeRe('\\**', {nonull: true}).should.eql(/^(?:(?=.)\*[^/]*?)$/); - mm.makeRe('\\*\\*', {nonull: true}).should.eql(/^(?:\*\*)$/); - mm.makeRe('b*/').should.eql(/^(?:(?=.)b[^/]*?\/)$/); - mm.makeRe('c*').should.eql(/^(?:(?=.)c[^/]*?)$/); - mm.makeRe('**').should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?)$/); - mm.makeRe('\\.\\./*/').should.eql(/^(?:\.\.\/(?!\.)(?=.)[^/]*?\/)$/); - mm.makeRe('s/\\..*//').should.eql(/^(?:s\/(?=.)\.\.[^/]*?\/)$/); - - // legendary larry crashes bashes - mm.makeRe('/^root:/{s/^[^:]*:[^:]*:([^:]*).*$/\\1/').should.eql(/^(?:\/\^root:\/\{s\/(?=.)\^[^:][^/]*?:[^:][^/]*?:\([^:]\)[^/]*?\.[^/]*?\$\/1\/)$/); - mm.makeRe('/^root:/{s/^[^:]*:[^:]*:([^:]*).*$/\\1/').should.eql(/^(?:\/\^root:\/\{s\/(?=.)\^[^:][^/]*?:[^:][^/]*?:\([^:]\)[^/]*?\.[^/]*?\$\/1\/)$/); - - // character classes - mm.makeRe('[a-c]b*').should.eql(/^(?:(?!\.)(?=.)[a-c]b[^/]*?)$/); - mm.makeRe('[a-y]*[^c]').should.eql(/^(?:(?!\.)(?=.)[a-y][^/]*?[^c])$/); - mm.makeRe('a*[^c]').should.eql(/^(?:(?=.)a[^/]*?[^c])$/); - mm.makeRe('a[X-]b').should.eql(/^(?:(?=.)a[X-]b)$/); - mm.makeRe('[^a-c]*').should.eql(/^(?:(?!\.)(?=.)[^a-c][^/]*?)$/); - mm.makeRe('a\\*b/*').should.eql(/^(?:a\*b\/(?!\.)(?=.)[^/]*?)$/); - mm.makeRe('a\\*?/*').should.eql(/^(?:(?=.)a\*[^/]\/(?!\.)(?=.)[^/]*?)$/); - mm.makeRe('*\\\\!*').should.eql(/^(?:(?!\.)(?=.)[^/]*?\\\![^/]*?)$/); - mm.makeRe('*\\!*').should.eql(/^(?:(?!\.)(?=.)[^/]*?\![^/]*?)$/); - mm.makeRe('*.\\*').should.eql(/^(?:(?!\.)(?=.)[^/]*?\.\*)$/); - mm.makeRe('a[b]c').should.eql(/^(?:(?=.)a[b]c)$/); - mm.makeRe('a[\\b]c').should.eql(/^(?:(?=.)a[b]c)$/); - mm.makeRe('a?c').should.eql(/^(?:(?=.)a[^/]c)$/); - mm.makeRe('a\\*c').should.eql(/^(?:a\*c)$/); - mm.makeRe('').should.be.false(); - - // http://www.opensource.apple.com/source/bash/bash-23/bash/tests/glob-test - mm.makeRe('*/man*/bash.*').should.eql(/^(?:(?!\.)(?=.)[^/]*?\/(?=.)man[^/]*?\/(?=.)bash\.[^/]*?)$/); - mm.makeRe('man/man1/bash.1').should.eql(/^(?:man\/man1\/bash\.1)$/); - mm.makeRe('a***c').should.eql(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?c)$/); - mm.makeRe('a*****?c').should.eql(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/); - mm.makeRe('?*****??').should.eql(/^(?:(?!\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/); - mm.makeRe('*****??').should.eql(/^(?:(?!\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/); - mm.makeRe('?*****?c').should.eql(/^(?:(?!\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/); - mm.makeRe('?***?****c').should.eql(/^(?:(?!\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/); - mm.makeRe('?***?****?').should.eql(/^(?:(?!\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/); - mm.makeRe('?***?****').should.eql(/^(?:(?!\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('*******c').should.eql(/^(?:(?!\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c)$/); - mm.makeRe('*******?').should.eql(/^(?:(?!\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/])$/); - mm.makeRe('a*cd**?**??k').should.eql(/^(?:(?=.)a[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/); - mm.makeRe('a**?**cd**?**??k').should.eql(/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/); - mm.makeRe('a**?**cd**?**??k***').should.eql(/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('a**?**cd**?**??***k').should.eql(/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k)$/); - mm.makeRe('a**?**cd**?**??***k**').should.eql(/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k[^/]*?[^/]*?)$/); - mm.makeRe('a****c**?**??*****').should.eql(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('[-abc]').should.eql(/^(?:(?!\.)(?=.)[-abc])$/); - mm.makeRe('[abc-]').should.eql(/^(?:(?!\.)(?=.)[abc-])$/); - mm.makeRe('\\').should.eql(/^(?:\\)$/); - mm.makeRe('[\\\\]').should.eql(/^(?:(?!\.)(?=.)[\\])$/); - mm.makeRe('[[]').should.eql(/^(?:(?!\.)(?=.)[\[])$/); - mm.makeRe('[').should.eql(/^(?:\[)$/); - mm.makeRe('[*').should.eql(/^(?:(?=.)\[(?!\.)(?=.)[^/]*?)$/); - - // a right bracket shall lose its special meaning and - // represent itself in a bracket expression if it occurs - // first in the list. -- POSIX.2 2.8.3.2 - mm.makeRe('[]]').should.eql(/^(?:(?!\.)(?=.)[\]])$/); - mm.makeRe('[]-]').should.eql(/^(?:(?!\.)(?=.)[\]-])$/); - mm.makeRe('[a-z]').should.eql(/^(?:(?!\.)(?=.)[a-z])$/); - mm.makeRe('??**********?****?').should.eql(/^(?:(?!\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/); - mm.makeRe('??**********?****c').should.eql(/^(?:(?!\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/); - mm.makeRe('?************c****?****').should.eql(/^(?:(?!\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('*c*?**').should.eql(/^(?:(?!\.)(?=.)[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/); - mm.makeRe('a*****c*?**').should.eql(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/); - mm.makeRe('a********???*******').should.eql(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('[]').should.eql(/^(?:\[\])$/); - mm.makeRe('[abc').should.eql(/^(?:\[abc)$/); - - // nocase tests - mm.makeRe('XYZ', { nocase: true, null: true }).should.eql(/^(?:(?=.)XYZ)$/i); - mm.makeRe('ab*').should.eql(/^(?:(?=.)ab[^/]*?)$/); - mm.makeRe('ab*', { nocase: true, null: true }).should.eql(/^(?:(?=.)ab[^/]*?)$/i); - mm.makeRe('[ia]?[ck]').should.eql(/^(?:(?!\.)(?=.)[ia][^/][ck])$/); - - // onestar/twostar - mm.makeRe('{/*,*}').should.eql(/^(?:\/(?!\.)(?=.)[^/]*?|(?!\.)(?=.)[^/]*?)$/); - mm.makeRe('{/?,*}').should.eql(/^(?:\/(?!\.)(?=.)[^/]|(?!\.)(?=.)[^/]*?)$/); - - // dots should not match unless requested - mm.makeRe('**').should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?)$/); - mm.makeRe('a/*/b').should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/b)$/); - mm.makeRe('a/*/b', {dot: true}).should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b)$/); - mm.makeRe('a/.*/b').should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - mm.makeRe('a/.*/b', {dot: true}).should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - mm.makeRe('a/*/b').should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/b)$/); - mm.makeRe('a/*/b', {dot: true}).should.eql(/^(?:a\/(?!(?:^|\/)\.{1,2}(?:$|\/))(?=.)[^/]*?\/b)$/); - mm.makeRe('a/.*/b').should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - mm.makeRe('a/.*/b', {dot: true}).should.eql(/^(?:a\/(?=.)\.[^/]*?\/b)$/); - mm.makeRe('**').should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?)$/); - mm.makeRe('**', {dot: true}).should.eql(/^(?:(?:(?!(?:\/|^)(?:\.{1,2})($|\/)).)*?)$/); - - // paren sets cannot contain slashes - mm.makeRe('*(a/b)').should.eql(/^(?:(?!\.)(?=.)[^/]*?\(a\/b\))$/); - mm.makeRe('*(a|{b),c)}').should.eql(/^(?:(?!\.)(?=.)(?:a|b)*|(?!\.)(?=.)(?:a|c)*)$/); - mm.makeRe('[!a*').should.eql(/^(?:(?=.)\[(?=.)\!a[^/]*?)$/); - mm.makeRe('[#a*').should.eql(/^(?:(?=.)\[(?=.)#a[^/]*?)$/); - mm.makeRe('+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g').should.eql(/^(?:(?=.)\+\(a\|[^/]*?\|c\\\\\|d\\\\\|e\\\\\\\\\|f\\\\\\\\\|g)$/); - mm.makeRe('*(a|{b,c})').should.eql(/^(?:(?!\.)(?=.)(?:a|b)*|(?!\.)(?=.)(?:a|c)*)$/); - mm.makeRe('{a,*(b|c,d)}').should.eql(/^(?:a|(?!\.)(?=.)[^/]*?\(b\|c|d\))$/); - mm.makeRe('{a,*(b|{c,d})}').should.eql(/^(?:a|(?!\.)(?=.)(?:b|c)*|(?!\.)(?=.)(?:b|d)*)$/); - mm.makeRe('*(a|{b|c,c})').should.eql(/^(?:(?!\.)(?=.)(?:a|b|c)*|(?!\.)(?=.)(?:a|c)*)$/); - mm.makeRe('*(a|{b|c,c})').should.eql(/^(?:(?!\.)(?=.)(?:a|b|c)*|(?!\.)(?=.)(?:a|c)*)$/); - mm.makeRe('a?b').should.eql(/^(?:(?=.)a[^/]b)$/); - mm.makeRe('a?b', {nonull: true}).should.eql(/^(?:(?=.)a[^/]b)$/); - - // negation tests - mm.makeRe('!a*').should.eql(/^(?!^(?:(?=.)a[^/]*?)$).*$/); - mm.makeRe('!a*', {nonegate: true}).should.eql(/^(?:(?=.)\!a[^/]*?)$/); - mm.makeRe('!!a*').should.eql(/^(?:(?=.)a[^/]*?)$/); - mm.makeRe('!\\!a*').should.eql(/^(?!^(?:(?=.)\!a[^/]*?)$).*$/); - mm.makeRe('*.!(js)').should.eql(/^(?:(?!\.)(?=.)[^/]*?\.(?:(?!js)[^/]*?))$/); - mm.makeRe('**/.x/**').should.eql(/^(?:(?:(?!(?:\/|^)\.).)*?\/\.x\/(?:(?!(?:\/|^)\.).)*?)$/); -}); diff --git a/test/minimatch/defaults.js b/test/minimatch/defaults.js deleted file mode 100644 index 8c1a3f67..00000000 --- a/test/minimatch/defaults.js +++ /dev/null @@ -1,125 +0,0 @@ -var path = require('path'); -var should = require('should'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var mm = require('../..'); - -if ('minimatch' in argv) { - mm = require('minimatch'); -} - -it('minimatch tests:', function() { - // http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test - mm.makeRe('a*').should.equal(/^(?:(?=.)a[^/]*?)$/); - mm.makeRe('X*').should.equal(/^(?:(?=.)X[^/]*?)$/); - mm.makeRe('X*').should.equal(/^(?:(?=.)X[^/]*?)$/); - mm.makeRe('\\*').should.equal(/^(?:\\*)$/); - mm.makeRe('\\**').should.equal(/^(?:(?=.)\\*[^/]*?)$/); - mm.makeRe('\\*\\*').should.equal(/^(?:\\*\\*)$/); - mm.makeRe('b*/').should.equal(/^(?:(?=.)b[^/]*?\\/)$/); - mm.makeRe('c*').should.equal(/^(?:(?=.)c[^/]*?)$/); - mm.makeRe('**').should.equal(/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/); - mm.makeRe('\\.\\./*/').should.equal(/^(?:\\.\\.\\/(?!\\.)(?=.)[^/]*?\\/)$/); - mm.makeRe('s/\\..*//').should.equal(/^(?:s\\/(?=.)\\.\\.[^/]*?\\/)$/); - - // legendary larry crashes bashes - mm.makeRe('/^root:/{s/^[^:]*:[^:]*:\\([^:]*).*$/\\1/').should.equal(/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/1\\/)$/); - mm.makeRe('/^root:/{s/^[^:]*:[^:]*:\\([^:]*).*$/\\1/').should.equal(/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/\u0001\\/)$/); - - // character classes - mm.makeRe('[a-c]b*').should.equal(/^(?:(?!\\.)(?=.)[a-c]b[^/]*?)$/); - mm.makeRe('[a-y]*[^c]').should.equal(/^(?:(?!\\.)(?=.)[a-y][^/]*?[^c])$/); - mm.makeRe('a*[^c]').should.equal(/^(?:(?=.)a[^/]*?[^c])$/); - mm.makeRe('a[X-]b').should.equal(/^(?:(?=.)a[X-]b)$/); - mm.makeRe('[^a-c]*').should.equal(/^(?:(?!\\.)(?=.)[^a-c][^/]*?)$/); - mm.makeRe('a\\*b/*').should.equal(/^(?:a\\*b\\/(?!\\.)(?=.)[^/]*?)$/); - mm.makeRe('a\\*?/*').should.equal(/^(?:(?=.)a\\*[^/]\\/(?!\\.)(?=.)[^/]*?)$/); - mm.makeRe('*\\\\!*').should.equal(/^(?:(?!\\.)(?=.)[^/]*?\\\\\\![^/]*?)$/); - mm.makeRe('*\\!*').should.equal(/^(?:(?!\\.)(?=.)[^/]*?\\![^/]*?)$/); - mm.makeRe('*.\\*').should.equal(/^(?:(?!\\.)(?=.)[^/]*?\\.\\*)$/); - mm.makeRe('a[b]c').should.equal(/^(?:(?=.)a[b]c)$/); - mm.makeRe('a[\\b]c').should.equal(/^(?:(?=.)a[b]c)$/); - mm.makeRe('a?c').should.equal(/^(?:(?=.)a[^/]c)$/); - mm.makeRe('a\\*c').should.equal(/^(?:a\\*c)$/); - mm.makeRe('').should.equal('false'); - - // http://www.opensource.apple.com/source/bash/bash-23/bash/tests/glob-test - mm.makeRe('*/man*/bash.*').should.equal(/^(?:(?!\\.)(?=.)[^/]*?\\/(?=.)man[^/]*?\\/(?=.)bash\\.[^/]*?)$/); - mm.makeRe('man/man1/bash.1').should.equal(/^(?:man\\/man1\\/bash\\.1)$/); - mm.makeRe('a***c').should.equal(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?c)$/); - mm.makeRe('a*****?c').should.equal(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/); - mm.makeRe('?*****??').should.equal(/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/); - mm.makeRe('*****??').should.equal(/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/); - mm.makeRe('?*****?c').should.equal(/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/); - mm.makeRe('?***?****c').should.equal(/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/); - mm.makeRe('?***?****?').should.equal(/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/); - mm.makeRe('?***?****').should.equal(/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('*******c').should.equal(/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c)$/); - mm.makeRe('*******?').should.equal(/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/])$/); - mm.makeRe('a*cd**?**??k').should.equal(/^(?:(?=.)a[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/); - mm.makeRe('a**?**cd**?**??k').should.equal(/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/); - mm.makeRe('a**?**cd**?**??k***').should.equal(/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('a**?**cd**?**??***k').should.equal(/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k)$/); - mm.makeRe('a**?**cd**?**??***k**').should.equal(/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k[^/]*?[^/]*?)$/); - mm.makeRe('a****c**?**??*****').should.equal(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('[-abc]').should.equal(/^(?:(?!\\.)(?=.)[-abc])$/); - mm.makeRe('[abc-]').should.equal(/^(?:(?!\\.)(?=.)[abc-])$/); - mm.makeRe('\\').should.equal(/^(?:\\\\)$/); - mm.makeRe('[\\\\]').should.equal(/^(?:(?!\\.)(?=.)[\\\\])$/); - mm.makeRe('[[]').should.equal(/^(?:(?!\\.)(?=.)[\\[])$/); - mm.makeRe('[').should.equal(/^(?:\\[)$/); - mm.makeRe('[*').should.equal(/^(?:(?=.)\\[(?!\\.)(?=.)[^/]*?)$/); - - // a right bracket shall lose its special meaning and - // represent itself in a bracket expression if it occurs - // first in the list. -- POSIX.2 2.8.3.2 - mm.makeRe('[]]').should.equal(/^(?:(?!\\.)(?=.)[\\]])$/); - mm.makeRe('[]-]').should.equal(/^(?:(?!\\.)(?=.)[\\]-])$/); - mm.makeRe('[a-z]').should.equal(/^(?:(?!\\.)(?=.)[a-z])$/); - mm.makeRe('??**********?****?').should.equal(/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/); - mm.makeRe('??**********?****c').should.equal(/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/); - mm.makeRe('?************c****?****').should.equal(/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('*c*?**').should.equal(/^(?:(?!\\.)(?=.)[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/); - mm.makeRe('a*****c*?**').should.equal(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/); - mm.makeRe('a********???*******').should.equal(/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/); - mm.makeRe('[]').should.equal(/^(?:\\[\\])$/); - mm.makeRe('[abc').should.equal(/^(?:\\[abc)$/); - - // nocase tests - mm.makeRe('XYZ').should.equal(/^(?:(?=.)XYZ)$/i); - mm.makeRe('ab*').should.equal(/^(?:(?=.)ab[^/]*?)$/i); - mm.makeRe('[ia]?[ck]').should.equal(/^(?:(?!\\.)(?=.)[ia][^/][ck])$/i); - - // onestar/twostar - mm.makeRe('{/*,*}').should.equal(/^(?:\\/(?!\\.)(?=.)[^/]*?|(?!\\.)(?=.)[^/]*?)$/); - mm.makeRe('{/?,*}').should.equal(/^(?:\\/(?!\\.)(?=.)[^/]|(?!\\.)(?=.)[^/]*?)$/); - - // dots should not match unless requested - mm.makeRe('**').should.equal(/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/); - mm.makeRe('a/*/b').should.equal(/^(?:a\\/(?!(?:^|\\/)\\.{1,2}(?:$|\\/))(?=.)[^/]*?\\/b)$/); - mm.makeRe('a/.*/b').should.equal(/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/); - mm.makeRe('a/*/b').should.equal(/^(?:a\\/(?!\\.)(?=.)[^/]*?\\/b)$/); - mm.makeRe('a/.*/b').should.equal(/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/); - mm.makeRe('**').should.equal(/^(?:(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?)$/); - - // paren sets cannot contain slashes - mm.makeRe('*(a/b)').should.equal(/^(?:(?!\\.)(?=.)[^/]*?\\(a\\/b\\))$/); - mm.makeRe('*(a|{b),c)}').should.equal(/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/); - mm.makeRe('[!a*').should.equal(/^(?:(?=.)\\[(?=.)\\!a[^/]*?)$/); - mm.makeRe('[#a*').should.equal(/^(?:(?=.)\\[(?=.)#a[^/]*?)$/); - mm.makeRe('+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g').should.equal(/^(?:(?=.)\\+\\(a\\|[^/]*?\\|c\\\\\\\\\\|d\\\\\\\\\\|e\\\\\\\\\\\\\\\\\\|f\\\\\\\\\\\\\\\\\\|g)$/); - mm.makeRe('*(a|{b,c})').should.equal(/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/); - mm.makeRe('{a,*(b|c,d)}').should.equal(/^(?:a|(?!\\.)(?=.)[^/]*?\\(b\\|c|d\\))$/); - mm.makeRe('{a,*(b|{c,d})}').should.equal(/^(?:a|(?!\\.)(?=.)(?:b|c)*|(?!\\.)(?=.)(?:b|d)*)$/); - mm.makeRe('*(a|{b|c,c})').should.equal(/^(?:(?!\\.)(?=.)(?:a|b|c)*|(?!\\.)(?=.)(?:a|c)*)$/); - mm.makeRe('*(a|{b|c,c})').should.equal(/^(?:(?!\\.)(?=.)[^\/]*?\\(a\\|b\\|c\\)|(?!\\.)(?=.)[^/]*?\\(a\\|c\\))$/); - mm.makeRe('a?b').should.equal(/^(?:(?=.)a[^/]b)$/); - mm.makeRe('#*').should.equal(/^(?:(?=.)#[^/]*?)$/); - - // negation tests - mm.makeRe('!a*').should.equal(/^(?!^(?:(?=.)a[^/]*?)$).*$/); - mm.makeRe('!a*').should.equal(/^(?:(?=.)\\!a[^/]*?)$/); - mm.makeRe('!!a*').should.equal(/^(?:(?=.)a[^/]*?)$/); - mm.makeRe('!\\!a*').should.equal(/^(?!^(?:(?=.)\\!a[^/]*?)$).*$/); - mm.makeRe('*.!(js)').should.equal(/^(?:(?!\\.)(?=.)[^/]*?\\.(?:(?!js)[^/]*?))$/); - mm.makeRe('**/.x/**').should.equal(/^(?:(?:(?!(?:\\/|^)\\.).)*?\\/\\.x\\/(?:(?!(?:\\/|^)\\.).)*?)$/); -}); diff --git a/test/minimatch/temp.js b/test/minimatch/temp.js deleted file mode 100644 index 407b8aef..00000000 --- a/test/minimatch/temp.js +++ /dev/null @@ -1,132 +0,0 @@ -var path = require('path'); -var should = require('should'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var mm = require('../..'); - -if ('minimatch' in argv) { - mm = require('minimatch'); -} - -it('minimatch tests:', function() { - // http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test - mm.makeRe('a*').should.eql(/^(?:a[^/]*?)$/); - mm.makeRe('X*', {nonull: true}).should.eql(/^(?:X[^/]*?)$/); - mm.makeRe('X*').should.eql(/^(?:X[^/]*?)$/); - mm.makeRe('\\*', {nonull: true}).should.eql(/^(?:\*)$/); - mm.makeRe('a/*\\*/b', {nonull: true}).should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\*\/b)$/); - mm.makeRe('\\**', {nonull: true}).should.eql(/^(?:\*[^/]*?)$/); - mm.makeRe('\\*\\*', {nonull: true}).should.eql(/^(?:\*\*)$/); - mm.makeRe('b*/').should.eql(/^(?:b(?!\.)(?=.)[^/]*?\/)$/); - mm.makeRe('c*').should.eql(/^(?:c[^/]*?)$/); - mm.makeRe('**').should.eql(/^(?:(?:(?!(?:^|\/)\.).)*?)$/); - mm.makeRe('\\.\\./*/').should.eql(/^(?:\.\.\/(?!\.)(?=.)[^/]*?\/)$/); - mm.makeRe('s/\\..*//').should.eql(/^(?:s\/\..(?!\.)(?=.)[^/]*?\/\/)$/); - -// legendary larry crashes bashes - mm.makeRe('/^root:/{s/^[^:]*:[^:]*:([^:]*).*$/\\1/').should.eql(/^(?:\/^root:\/{s\/^(?!\.)(?=.)[^:](?!\.)(?=.)[^/]*?:(?!\.)(?=.)[^:](?!\.)(?=.)[^/]*?:((?!\.)(?=.)[^:](?!\.)(?=.)[^/]*?).(?!\.)(?=.)[^/]*?$\/\1\/)$/); - mm.makeRe('/^root:/{s/^[^:]*:[^:]*:([^:]*).*$/\\1/').should.eql(/^(?:\/^root:\/{s\/^(?!\.)(?=.)[^:](?!\.)(?=.)[^/]*?:(?!\.)(?=.)[^:](?!\.)(?=.)[^/]*?:((?!\.)(?=.)[^:](?!\.)(?=.)[^/]*?).(?!\.)(?=.)[^/]*?$\/\1\/)$/); - - // character classes - mm.makeRe('[a-c]b*').should.eql(/^(?:(?!\.)(?=.)[a-c]b[^/]*?)$/); - mm.makeRe('[a-y]*[^c]').should.eql(/^(?:(?!\.)(?=.)[a-y](?!\.)(?=.)[^/]*?(?!\.)(?=.)[^c])$/); - mm.makeRe('a*[^c]').should.eql(/^(?:a(?!\.)(?=.)[^/]*?(?!\.)(?=.)[^c])$/); - mm.makeRe('a[X-]b').should.eql(/^(?:a(?!\.)(?=.)[X-]b)$/); - mm.makeRe('[^a-c]*').should.eql(/^(?:(?!\.)(?=.)[^a-c][^/]*?)$/); - mm.makeRe('a\\*b/*').should.eql(/^(?:a\*b\/(?!\.)(?=.)[^/]*?)$/); - mm.makeRe('a\\*?/*').should.eql(/^(?:a\%\/(?!\.)(?=.)[^/]\/(?!\.)(?=.)[^/]*?)$/); - mm.makeRe('*\\\\!*').should.eql(/^(?:(?!\.)(?=.)[^/]*?\\![^/]*?)$/); - mm.makeRe('*\\!*').should.eql(/^(?:(?!\.)(?=.)[^/]*?\![^/]*?)$/); - mm.makeRe('*.\\*').should.eql(/^(?:(?!\.)(?=.)[^/]*?.\*)$/); - mm.makeRe('a[b]c').should.eql(/^(?:a(?!\.)(?=.)[b]c)$/); - mm.makeRe('a[\\b]c').should.eql(/^(?:a(?!\.)(?=.)[\b]c)$/); - mm.makeRe('a?c').should.eql(/^(?:\/(?!\.)(?=.)[^/]c)$/); - mm.makeRe('a\\*c').should.eql(/^(?:a\*c)$/); - mm.makeRe('').should.eql(/^(?:)$/); - - // http://www.opensource.apple.com/source/bash/bash-23/bash/tests/glob-test - mm.makeRe('*/man*/bash.*').should.eql(/^(?:(?!\.)(?=.)[^/]*?\/man(?!\.)(?=.)[^/]*?\/bash.[^/]*?)$/); - mm.makeRe('man/man1/bash.1').should.eql(/^(?:man\/man1\/bash\.1)$/); - mm.makeRe('a***c').should.eql(/^(?:a.*(?!\.)(?=.)[^/]*?c)$/); - mm.makeRe('a*****?c').should.eql(/^(?:a.*.*\/(?!\.)(?=.)[^/]c)$/); - // console.log(mm.makeRe('?*****??')); - mm.makeRe('*****??').should.eql(/^(?:.*.*\/(?!\.)(?=.)[^/][^/])$/); -// console.log(mm.makeRe('?*****?c')); -// console.log(mm.makeRe('?***?****c')); -// console.log(mm.makeRe('?***?****?')); -// console.log(mm.makeRe('?***?****')); -// // console.log(mm.makeRe('*******c')); -// // console.log(mm.makeRe('*******?')); -// // console.log(mm.makeRe('a*cd**?**??k')); -// // console.log(mm.makeRe('a**?**cd**?**??k')); -// // console.log(mm.makeRe('a**?**cd**?**??k***')); -// // console.log(mm.makeRe('a**?**cd**?**??***k')); -// // console.log(mm.makeRe('a**?**cd**?**??***k**')); -// // console.log(mm.makeRe('a****c**?**??*****')); -// mm.makeRe('[-abc]').should.eql(/^(?:(?!\.)(?=.)[-abc])$/); -// mm.makeRe('[abc-]').should.eql(/^(?:(?!\.)(?=.)[abc-])$/); -// // console.log(mm.makeRe('\\')); -// mm.makeRe('[\\\\]').should.eql(/^(?:(?!\.)(?=.)[\\])$/); -// mm.makeRe('[[]').should.eql(/^(?:(?!\.)(?=.)[(?!\.)(?=.)[])$/); -// // console.log(mm.makeRe('[')); -// mm.makeRe('[*').should.eql(/^(?:(?!\.)(?=.)[[^/]*?)$/); - -// // a right bracket shall lose its special meaning and -// // represent itself in a bracket expression if it occurs -// // first in the list. -- POSIX.2 2.8.3.2 -// mm.makeRe('[]]').should.eql(/^(?:(?!\.)(?=.)[]])$/); -// mm.makeRe('[]-]').should.eql(/^(?:(?!\.)(?=.)[]-])$/); -// mm.makeRe('[a-z]').should.eql(/^(?:(?!\.)(?=.)[a-z])$/); -// mm.makeRe('??**********?****?').should.eql(/^(?:[^/]?\.*.*.*.*.*?\.*.%\/(?!\.)(?=.)[^/])$/); -// mm.makeRe('??**********?****c').should.eql(/^(?:[^/]?\.*.*.*.*.*?\.*.*c)$/); -// // console.log(mm.makeRe('?************c****?****')); -// // console.log(mm.makeRe('*c*?**')); -// // console.log(mm.makeRe('a*****c*?**')); -// mm.makeRe('a********???*******').should.eql(/^(?:a.*.*.*.%\/(?!\.)(?=.)[^/][^/]?\.*.*.*[^/]*?)$/); -// mm.makeRe('[]').should.eql(/^(?:(?!\.)(?=.)[])$/); -// // console.log(mm.makeRe('[abc')); - -// // nocase tests -// mm.makeRe('XYZ', { nocase: true, null: true }).should.eql(/^(?:XYZ)$/i); -// mm.makeRe('ab*').should.eql(/^(?:ab[^/]*?)$/); -// mm.makeRe('ab*', { nocase: true, null: true }).should.eql(/^(?:ab[^/]*?)$/i); -// mm.makeRe('[ia]?[ck]').should.eql(/^(?:(?!\.)(?=.)[ia\/(?!\.)(?=.)[^/](?!\.)(?=.)[ck])$/); - -// // onestar/twostar -// mm.makeRe('{/*,*}').should.eql(/^(?:(?:\/(?!\.)(?=.)[^/]*?|(?!\.)(?=.)[^/]*?))$/); -// mm.makeRe('{/?,*}').should.eql(/^(?:(?:\/(?!\.)(?=.)[^/]|(?!\.)(?=.)[^/]*?))$/); - -// // dots should not match unless requested -// mm.makeRe('**').should.eql(/^(?:(?:(?!(?:^|\/)\.).)*?)$/); -// mm.makeRe('a/*/b').should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/b)$/); -// mm.makeRe('a/*/b', {dot: true}).should.eql(/^(?:a\/(?!(?:^|\/)(?:\.{1,2})(?:\/|$))(?=.)[^/]*?\/b)$/); -// mm.makeRe('a/.*/b').should.eql(/^(?:a\/.(?!\.)(?=.)[^/]*?\/b)$/); -// mm.makeRe('a/.*/b', {dot: true}).should.eql(/^(?:a\/.(?!(?:^|\/)(?:\.{1,2})(?:\/|$))(?=.)[^/]*?\/b)$/); -// mm.makeRe('a/*/b').should.eql(/^(?:a\/(?!\.)(?=.)[^/]*?\/b)$/); -// mm.makeRe('a/*/b', {dot: true}).should.eql(/^(?:a\/(?!(?:^|\/)(?:\.{1,2})(?:\/|$))(?=.)[^/]*?\/b)$/); -// mm.makeRe('a/.*/b').should.eql(/^(?:a\/.(?!\.)(?=.)[^/]*?\/b)$/); -// mm.makeRe('a/.*/b', {dot: true}).should.eql(/^(?:a\/.(?!(?:^|\/)(?:\.{1,2})(?:\/|$))(?=.)[^/]*?\/b)$/); -// mm.makeRe('**').should.eql(/^(?:(?:(?!(?:^|\/)\.).)*?)$/); -// mm.makeRe('**', {dot: true}).should.eql(/^(?:.*)$/); - -// // paren sets cannot contain slashes -// // console.log(mm.makeRe('*(a/b)')); -// // console.log(mm.makeRe('*(a|{b),c)}')); -// mm.makeRe('[!a*').should.eql(/^(?:(?!\.)(?=.)[!a[^/]*?)$/); -// mm.makeRe('[#a*').should.eql(/^(?:(?!\.)(?=.)[#a[^/]*?)$/); -// // console.log(mm.makeRe('+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g')); -// // console.log(mm.makeRe('*(a|{b,c})')); -// // console.log(mm.makeRe('{a,*(b|c,d)}')); -// // console.log(mm.makeRe('{a,*(b|{c,d})}')); -// // console.log(mm.makeRe('*(a|{b|c,c})')); -// // console.log(mm.makeRe('*(a|{b|c,c})')); -// mm.makeRe('a?b').should.eql(/^(?:\/(?!\.)(?=.)[^/]b)$/); -// mm.makeRe('a?b', {nonull: true}).should.eql(/^(?:\/(?!\.)(?=.)[^/]b)$/); - -// // negation tests -// mm.makeRe('!a*').should.eql(/^(?!^(?:a[^/]*?)$).*$/); -// mm.makeRe('!a*', {nonegate: true}).should.eql(/^(?!^(?:a[^/]*?)$).*$/); -// mm.makeRe('!!a*').should.eql(/^(?!^(?:!a[^/]*?)$).*$/); -// mm.makeRe('!\\!a*').should.eql(/^(?!^(?:\!a[^/]*?)$).*$/); -// // console.log(mm.makeRe('*.!(js)')); -// mm.makeRe('**/.x/**').should.eql(/^(?:.*\/?\.x\/.*)$/); -}); \ No newline at end of file diff --git a/test/negation.js b/test/negation.js index b2f9c1a0..24c56f34 100644 --- a/test/negation.js +++ b/test/negation.js @@ -1,35 +1,84 @@ 'use strict'; -var assert = require('assert'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var matcher = argv.mm ? require('minimatch') : require('..'); - -function match(arr, pattern, expected, options) { - var actual = matcher.match(arr, pattern, options); - assert.deepEqual(actual.sort(), expected.sort()); -} +var mm = require('./support/match'); describe('negation', function() { it('should negate files with extensions:', function() { - match(['.md'], '!.md', []); - match(['a.js', 'b.md', 'c.txt'], '!**/*.md', ['a.js', 'b.md', 'c.txt']); - match(['a.js', 'b.md', 'c.txt'], '!*.md', ['a.js', 'c.txt']); - match(['abc.md', 'abc.txt'], '!*.md', ['abc.txt']); - match(['foo.md'], '!*.md', []); - match(['foo.md'], '!.md', ['foo.md']); + mm(['.md'], '!.md', []); + mm(['a.js', 'b.md', 'c.txt'], '!**/*.md', ['a.js', 'c.txt']); + mm(['a.js', 'b.md', 'c.txt'], '!*.md', ['a.js', 'c.txt']); + mm(['abc.md', 'abc.txt'], '!*.md', ['abc.txt']); + mm(['foo.md'], '!*.md', []); + mm(['foo.md'], '!.md', ['foo.md']); + }); + + it('should only treat leading exclamation as special', function() { + mm(['foo!.md', 'bar.md'], 'foo!.md', ['foo!.md']); + mm(['foo!.md', 'bar.md'], '*.md', ['foo!.md', 'bar.md']); + mm(['foo!.md', 'bar.md'], '*!.md', ['foo!.md']); + mm(['foobar.md'], '*b*.md', ['foobar.md']); + mm(['foo!bar.md', 'foo!.md', '!foo!.md'], '*!*.md', ['foo!bar.md', 'foo!.md', '!foo!.md']); + mm(['foo!bar.md', 'foo!.md', '!foo!.md'], '\\!*!*.md', ['!foo!.md']); + mm(['foo!.md', 'ba!r.js'], '**/*!*.*', ['foo!.md', 'ba!r.js']); + }); + + it('should support negated globs ("*")', function() { + mm(['a.js', 'b.txt', 'c.md'], '!*.md', ['a.js', 'b.txt']); + mm(['a/a/a.js', 'a/b/a.js', 'a/c/a.js'], '!a/*/a.js', []); + mm(['a/a/a/a.js', 'b/a/b/a.js', 'c/a/c/a.js'], '!a/*/*/a.js', ['b/a/b/a.js', 'c/a/c/a.js']); + mm(['a/a.txt', 'a/b.txt', 'a/c.txt'], '!a/a*.txt', ['a/b.txt', 'a/c.txt']); + mm(['a.a.txt', 'a.b.txt', 'a.c.txt'], '!a.a*.txt', ['a.b.txt', 'a.c.txt']); + mm(['a/a.txt', 'a/b.txt', 'a/c.txt'], '!a/*.txt', []); + }); + + it('should support negated globstars ("**")', function() { + mm(['a.js', 'b.txt', 'c.md'], '!*.md', ['a.js', 'b.txt']); + mm(['a/a/a.js', 'a/b/a.js', 'a/c/a.js', 'a/a/b.js'], '!**/a.js', ['a/a/b.js']); + mm(['a/a/a/a.js', 'b/a/b/a.js', 'c/a/c/a.js'], '!a/**/a.js', ['b/a/b/a.js', 'c/a/c/a.js']); + mm(['a/a.txt', 'a/b.txt', 'a/c.txt'], '!a/b.txt', ['a/a.txt', 'a/c.txt']); + mm(['a/b.js', 'a.js', 'a/b.md', 'a.md'], '!**/*.md', ['a/b.js', 'a.js']); + mm(['a/b.js', 'a.js', 'a/b.md', 'a.md'], '**/*.md', ['a/b.md', 'a.md']); + + mm(['a/b.js'], '!**/*.md', ['a/b.js']); + mm(['a.js'], '!**/*.md', ['a.js']); + mm(['a/b.md'], '!**/*.md', []); + mm(['a.md'], '!**/*.md', []); + + mm(['a/b.js'], '!*.md', ['a/b.js']); + mm(['a.js'], '!*.md', ['a.js']); + mm(['a/b.md'], '!*.md', ['a/b.md']); + mm(['a.md'], '!*.md', []); + + mm(['a.js'], '!**/*.md', ['a.js']); + mm(['b.md'], '!**/*.md', []); + mm(['c.txt'], '!**/*.md', ['c.txt']); }); it('should negate dotfiles:', function() { - match(['.dotfile.md'], '!*.md', ['.dotfile.md']); - match(['.dotfile.txt'], '!*.md', ['.dotfile.txt']); - match(['.gitignore', 'a', 'b'], '!.gitignore', ['a', 'b']); + mm(['.dotfile.md'], '!*.md', ['.dotfile.md']); + mm(['.dotfile.txt'], '!*.md', ['.dotfile.txt']); + mm(['.dotfile.txt', 'a/b/.dotfile'], '!*.md', ['.dotfile.txt', 'a/b/.dotfile']); + mm(['.gitignore', 'a', 'b'], '!.gitignore', ['a', 'b']); }); it('should negate files in the immediate directory:', function() { - match(['a/b.js', 'a.js', 'a/b.md', 'a.md'], '!*.md', ['a/b.js', 'a.js', 'a/b.md']); + mm(['a/b.js', 'a.js', 'a/b.md', 'a.md'], '!*.md', ['a/b.js', 'a.js', 'a/b.md']); + }); + + it('should support any number of leading exclamations', function() { + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!a*', ['d', 'e', '!ab', '!abc', '\\!a']); + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!a*', ['a!b']); + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!a*', ['d', 'e', '!ab', '!abc', '\\!a']); + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!!a*', ['a!b']); + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!!!a*', ['d', 'e', '!ab', '!abc', '\\!a']); + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!!!!a*', ['a!b']); + }); + + it('should not give special meaning to non-leading exclamations', function() { + mm(['a', 'aa', 'a/b', 'a!b', 'a!!b', 'a/!!/b'], 'a!!b', ['a!!b']); }); it('should negate files in any directory:', function() { - match(['a/b.js', 'a.js', 'a/b.md', 'a.md'], '!**/*.md', ['a/b.js', 'a.md', 'a.js']); + mm(['a/a.txt', 'a/b.txt', 'a/c.txt'], '!a/b.txt', ['a/a.txt', 'a/c.txt']); }); }); diff --git a/test/options.js b/test/options.js new file mode 100644 index 00000000..9e1b4102 --- /dev/null +++ b/test/options.js @@ -0,0 +1,269 @@ +'use strict'; + +var assert = require('assert'); +var path = require('path'); +var sep = path.sep; +var mm = require('./support/match'); + +describe('options', function() { + describe('options.ignore', function() { + var negations = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c', 'a/d', 'a/e']; + var globs = ['a', 'a/a', 'a/a/a', 'a/a/a/a', 'a/a/a/a/a', 'a/a/b', 'a/b', 'a/b/c', 'a/c', 'a/x', 'b', 'b/b/b', 'b/b/c', 'c/c/c', 'e/f/g', 'h/i/a', 'x/x/x', 'x/y', 'z/z', 'z/z/z']; + + it('should filter out ignored patterns', function() { + var opts = {ignore: ['a/**']}; + + mm(globs, '*', ['a', 'b'], opts); + mm(globs, '*', ['b'], {ignore: '**/a'}); + mm(globs, '*/*', ['x/y', 'z/z'], opts); + mm(globs, '*/*/*', ['b/b/b', 'b/b/c', 'c/c/c', 'e/f/g', 'h/i/a', 'x/x/x', 'z/z/z'], opts); + mm(globs, '*/*/*/*', [], opts); + mm(globs, '*/*/*/*/*', [], opts); + mm(globs, 'a/*', [], opts); + mm(globs, '**/*/x', ['x/x/x'], opts); + + mm(negations, '!b/a', ['b/b', 'b/c'], opts); + mm(negations, '!b/(a)', ['b/b', 'b/c'], opts); + mm(negations, '!(b/(a))', ['b/b', 'b/c'], opts); + mm(negations, '!(b/a)', ['b/b', 'b/c'], opts); + + mm(negations, '**', negations, 'nothing is ignored'); + mm(negations, '**', ['a/c', 'a/d', 'a/e', 'b/c'], {ignore: ['*/b', '*/a']}); + mm(negations, '**', [], {ignore: ['**']}); + }); + + it('should "un-ignore" values when a negation pattern is passed', function() { + mm(negations, '**', ['a/d'], {ignore: ['**', '!*/d']}); + mm(negations, '**', ['a/a', 'b/a'], {ignore: ['**', '!*/a']}); + }); + }); + + describe('options.nobrace', function() { + it('should not expand braces', function() { + mm(['1', '2', '3'], '{1..2}', {nobrace: true}, []); + }); + }); + + describe('options.expand', function() { + it('should expand braces to an array', function() { + assert.deepEqual(mm.braces('{a,b}', {expand: true}), ['a', 'b']); + assert.deepEqual(mm.braces('foo/{a,b}/bar', {expand: true}), ['foo/a/bar', 'foo/b/bar']); + }); + }); + + describe('options.matchBase', function() { + it('should match the basename of file paths when `options.matchBase` is true', function() { + mm(['a/b/c/d.md'], '*.md', [], 'should not match multiple levels'); + mm(['a/b/c/foo.md'], '*.md', [], 'should not match multiple levels'); + mm(['ab', 'acb', 'acb/', 'acb/d/e', 'x/y/acb', 'x/y/acb/d'], 'a?b', ['acb', 'acb/'], 'should not match multiple levels'); + mm(['a/b/c/d.md'], '*.md', ['a/b/c/d.md'], {matchBase: true}); + mm(['a/b/c/foo.md'], '*.md', ['a/b/c/foo.md'], {matchBase: true}); + mm(['x/y/acb', 'acb/', 'acb/d/e', 'x/y/acb/d'], 'a?b', ['x/y/acb', 'acb/'], {matchBase: true}); + }); + + it('should support `options.basename` as an alternative to `matchBase`', function() { + mm(['a/b/c/d.md'], '*.md', [], 'should not match multiple levels'); + mm(['a/b/c/foo.md'], '*.md', [], 'should not match multiple levels'); + mm(['ab', 'acb', 'acb/', 'acb/d/e', 'x/y/acb', 'x/y/acb/d'], 'a?b', ['acb', 'acb/'], 'should not match multiple levels'); + mm(['a/b/c/d.md'], '*.md', ['a/b/c/d.md'], {basename: true}); + mm(['a/b/c/foo.md'], '*.md', ['a/b/c/foo.md'], {basename: true}); + mm(['x/y/acb', 'acb/', 'acb/d/e', 'x/y/acb/d'], 'a?b', ['x/y/acb', 'acb/'], {basename: true}); + }); + }); + + describe('options.flags', function() { + it('should be case-sensitive by default', function() { + mm(['a/b/d/e.md'], 'a/b/D/*.md', [], 'should not match a dirname'); + mm(['a/b/c/e.md'], 'A/b/*/E.md', [], 'should not match a basename'); + mm(['a/b/c/e.md'], 'A/b/C/*.MD', [], 'should not match a file extension'); + }); + + it('should not be case-sensitive when `i` is set on `options.flags`', function() { + mm(['a/b/d/e.md'], 'a/b/D/*.md', ['a/b/d/e.md'], {flags: 'i'}); + mm(['a/b/c/e.md'], 'A/b/*/E.md', ['a/b/c/e.md'], {flags: 'i'}); + mm(['a/b/c/e.md'], 'A/b/C/*.MD', ['a/b/c/e.md'], {flags: 'i'}); + }); + }); + + describe('options.nocase', function() { + it('should not be case-sensitive when `options.nocase` is true', function() { + mm(['a/b/c/e.md'], 'A/b/*/E.md', ['a/b/c/e.md'], {nocase: true}); + mm(['a/b/c/e.md'], 'A/b/C/*.MD', ['a/b/c/e.md'], {nocase: true}); + mm(['a/b/c/e.md'], 'A/b/C/*.md', ['a/b/c/e.md'], {nocase: true}); + mm(['a/b/d/e.md'], 'a/b/D/*.md', ['a/b/d/e.md'], {nocase: true}); + }); + + it('should not double-set `i` when both `nocase` and the `i` flag are set', function() { + var opts = {nocase: true, flags: 'i'}; + mm(['a/b/d/e.md'], 'a/b/D/*.md', opts, ['a/b/d/e.md']); + mm(['a/b/c/e.md'], 'A/b/*/E.md', opts, ['a/b/c/e.md']); + mm(['a/b/c/e.md'], 'A/b/C/*.MD', opts, ['a/b/c/e.md']); + }); + }); + + describe('options.nodupes', function() { + beforeEach(function() { + path.sep = '\\'; + }); + afterEach(function() { + path.sep = sep; + }); + + it('should remove duplicate elements from the result array:', function() { + mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c'], {}); + mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['/a/b/c'], {}); + mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c'], {nodupes: true}); + mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['/a/b/c'], {nodupes: true}); + }); + + it('should not remove duplicates', function() { + mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c', '/a/b/c'], {nodupes: false}); + mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['/a/b/c'], {nodupes: false}); + }); + }); + + describe('options.unescape', function() { + it('should remove backslashes in glob patterns:', function() { + var fixtures = ['abc', '/a/b/c', '\\a\\b\\c']; + mm(fixtures, '\\a\\b\\c', ['/a/b/c']); + mm(fixtures, '\\a\\b\\c', {unescape: true}, ['/a/b/c']); + mm(fixtures, '\\a\\b\\c', {unescape: true, nodupes: false}, ['/a/b/c']); + }); + }); + + describe('options.nonull', function() { + it('should return the pattern when no matches are found', function() { + mm(['a/b/c/e.md'], 'foo/*.md', ['foo/*.md'], {nonull: true}); + mm(['a/b/c/e.md'], 'bar/*.js', ['bar/*.js'], {nonull: true}); + }); + }); + + describe('options.nonegate', function() { + it('should support the `nonegate` option:', function() { + mm(['a/a/a', 'a/b/a', 'b/b/a', 'c/c/a', 'c/c/b'], '!**/a', ['c/c/b']); + mm(['.dotfile.txt', 'a/b/.dotfile'], '!*.md', [], {nonegate: true}); + mm(['!a/a/a', 'a/b/a', 'b/b/a', '!c/c/a'], '!**/a', ['!a/a/a', '!c/c/a'], {nonegate: true}); + mm(['!*.md', '.dotfile.txt', 'a/b/.dotfile'], '!*.md', ['!*.md'], {nonegate: true}); + }); + }); + + describe('options.unixify', function() { + it('should unixify file paths', function() { + mm(['a\\b\\c.md'], '**/*.md', ['a/b/c.md'], {unixify: true}); + }); + + it('should unixify absolute paths', function() { + mm(['E:\\a\\b\\c.md'], 'E:/**/*.md', ['E:/a/b/c.md'], {unixify: true}); + }); + }); + + describe('options.dot', function() { + describe('when `dot` or `dotfile` is NOT true:', function() { + it('should not match dotfiles by default:', function() { + mm(['.dotfile'], '*', []); + mm(['.dotfile'], '**', []); + mm(['a/b/c/.dotfile.md'], '*.md', []); + mm(['a/b', 'a/.b', '.a/b', '.a/.b'], '**', ['a/b']); + mm(['a/b/c/.dotfile'], '*.*', []); + + // https://github.com/isaacs/minimatch/issues/30 + mm(['foo/bar.js'], '**/foo/**', ['foo/bar.js']); + mm(['./foo/bar.js'], './**/foo/**', ['foo/bar.js']); + mm(['./foo/bar.js'], '**/foo/**', ['foo/bar.js']); + }); + + it('should match dotfiles when a leading dot is defined in the path:', function() { + mm(['a/b/c/.dotfile.md'], '**/.*', ['a/b/c/.dotfile.md']); + mm(['a/b/c/.dotfile.md'], '**/.*.md', ['a/b/c/.dotfile.md']); + }); + + it('should use negation patterns on dotfiles:', function() { + mm(['.a', '.b', 'c', 'c.md'], '!.*', ['c', 'c.md']); + mm(['.a', '.b', 'c', 'c.md'], '!.b', ['.a', 'c', 'c.md']); + }); + }); + + describe('when `dot` or `dotfile` is true:', function() { + it('should match dotfiles when there is a leading dot:', function() { + var opts = { dot: true }; + + mm(['.dotfile'], '*', opts, ['.dotfile']); + mm(['.dotfile'], '**', opts, ['.dotfile']); + mm(['a/b', 'a/.b', '.a/b', '.a/.b'], '**', opts, ['a/b', 'a/.b', '.a/b', '.a/.b']); + mm(['a/b', 'a/.b', 'a/.b', '.a/.b'], 'a/{.*,**}', opts, ['a/b', 'a/.b']); + mm(['a/b', 'a/.b', 'a/.b', '.a/.b'], '{.*,**}', {}, ['a/b']); + mm(['a/b', 'a/.b', 'a/.b', '.a/.b'], '{.*,**}', opts, ['a/b', '.a/.b', 'a/.b']); + mm(['.dotfile'], '.dotfile', opts, ['.dotfile']); + mm(['.dotfile.md'], '.*.md', opts, ['.dotfile.md']); + }); + + it('should match dotfiles when there is not a leading dot:', function() { + var opts = { dot: true }; + mm(['.dotfile'], '*.*', opts, ['.dotfile']); + mm(['.a', '.b', 'c', 'c.md'], '*.*', opts, ['.a', '.b', 'c.md']); + mm(['.dotfile'], '*.md', opts, []); + mm(['.verb.txt'], '*.md', opts, []); + mm(['a/b/c/.dotfile'], '*.md', opts, []); + mm(['a/b/c/.dotfile.md'], '*.md', opts, []); + mm(['a/b/c/.verb.md'], '**/*.md', opts, ['a/b/c/.verb.md']); + mm(['foo.md'], '*.md', opts, ['foo.md']); + }); + + it('should use negation patterns on dotfiles:', function() { + mm(['.a', '.b', 'c', 'c.md'], '!.*', ['c', 'c.md']); + mm(['.a', '.b', 'c', 'c.md'], '!(.*)', ['c', 'c.md']); + mm(['.a', '.b', 'c', 'c.md'], '!(.*)*', ['c', 'c.md']); + mm(['.a', '.b', 'c', 'c.md'], '!*.*', ['c']); + }); + + it('should match dotfiles when `options.dot` is true:', function() { + mm(['a/./b', 'a/../b', 'a/c/b', 'a/.d/b'], 'a/.*/b', [ 'a/../b', 'a/./b', 'a/.d/b' ], {dot: true}); + mm(['a/./b', 'a/../b', 'a/c/b', 'a/.d/b'], 'a/.*/b', [ 'a/../b', 'a/./b', 'a/.d/b' ], {dot: false}); + mm(['a/./b', 'a/../b', 'a/c/b', 'a/.d/b'], 'a/*/b', ['a/c/b', 'a/.d/b'], {dot: true}); + mm(['.dotfile'], '*.*', ['.dotfile'], {dot: true}); + mm(['.dotfile'], '*.md', [], {dot: true}); + mm(['.dotfile'], '.dotfile', ['.dotfile'], {dot: true}); + mm(['.dotfile.md'], '.*.md', ['.dotfile.md'], {dot: true}); + mm(['.verb.txt'], '*.md', [], {dot: true}); + mm(['.verb.txt'], '*.md', [], {dot: true}); + mm(['a/b/c/.dotfile'], '*.md', [], {dot: true}); + mm(['a/b/c/.dotfile.md'], '**/*.md', ['a/b/c/.dotfile.md'], {dot: true}); + mm(['a/b/c/.dotfile.md'], '**/.*', ['a/b/c/.dotfile.md']); + mm(['a/b/c/.dotfile.md'], '**/.*.md', ['a/b/c/.dotfile.md']); + mm(['a/b/c/.dotfile.md'], '*.md', []); + mm(['a/b/c/.dotfile.md'], '*.md', [], {dot: true}); + mm(['a/b/c/.verb.md'], '**/*.md', ['a/b/c/.verb.md'], {dot: true}); + mm(['d.md'], '*.md', ['d.md'], {dot: true}); + }); + }); + }); + + describe('windows', function() { + it('should unixify file paths', function() { + mm(['a\\b\\c.md'], '**/*.md', ['a/b/c.md']); + }); + + it('should unixify absolute paths', function() { + mm(['E:\\a\\b\\c.md'], 'E:/**/*.md', ['E:/a/b/c.md']); + }); + }); + + describe('normalize', function() { + it('should normalize leading `./`', function() { + var fixtures = ['a.md', 'a/b/c.md', 'a/b/d.md', './a/b/c.md', './b/c.md', '.\\a\\b\\c.md']; + mm(fixtures, '**/*.md', ['a.md', 'a/b/c.md', 'a/b/d.md', 'b/c.md']); + }); + + it('should match leading `./`', function() { + var fixtures = ['a.md', 'a/b.md', './a.md', './a/b.md', 'a/b/c.md', './a/b/c.md', '.\\a\\b\\c.md', 'a\\b\\c.md']; + mm(fixtures, '**/*.md', ['a.md', 'a/b.md', 'a/b/c.md']); + mm(fixtures, '*.md', ['a.md']); + mm(fixtures, '*/*.md', ['a/b.md']); + mm(fixtures, './**/*.md', ['a.md', 'a/b.md', 'a/b/c.md']); + mm(fixtures, './*.md', ['a.md']); + mm(fixtures, './*/*.md', ['a/b.md']); + mm(['./a'], 'a', ['a']); + }); + }); +}); + diff --git a/test/patterns.js b/test/patterns.js new file mode 100644 index 00000000..e86d92b4 --- /dev/null +++ b/test/patterns.js @@ -0,0 +1,270 @@ +if (module === require.main) { + console.log('1..1\nok'); +} + +var fixtures = [ + 'a', 'b', 'c', 'd', 'abc', + 'abd', 'abe', 'bb', 'bcd', + 'ca', 'cb', 'dd', 'de', 'bdir/', 'bdir/cfile' +]; + +module.exports = [ + 'http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test', + ['a*', ['a', 'abc', 'abd', 'abe']], + ['X*', ['X*'], {nonull: true}], + + // allow null glob expansion + ['X*', []], + + // Same results as Bash. Minimatch does this differently + ['\\*', ['\\*'], {nonull: true}], + ['\\**', ['\\**'], {nonull: true}], + ['\\*\\*', ['\\*\\*'], {nonull: true}], + + ['b*/', ['bdir/']], + ['c*', ['c', 'ca', 'cb']], + ['**', fixtures], + + ['\\.\\./*/', ['\\.\\./*/'], {nonull: true}], + ['s/\\..*//', ['s/\\..*//'], {nonull: true}], + + 'legendary larry crashes bashes', + ['/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/', + ['/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/'], {nonull: true}], + ['/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\u0001/', + ['/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\u0001/'], {nonull: true}], + + /** + * Character classes + */ + + 'character classes', + ['[a-c]b*', ['abc', 'abd', 'abe', 'bb', 'cb']], + ['[a-y]*[^c]', ['abd', 'abe', 'bb', 'bcd', 'bdir/', 'ca', 'cb', 'dd', 'de']], + ['a*[^c]', ['abd', 'abe']], + function () { + fixtures.push('a-b', 'aXb'); + }, + ['a[X-]b', ['a-b', 'aXb']], + function () { + fixtures.push('.x', '.y'); + }, + ['[^a-c]*', ['d', 'dd', 'de']], + function () { + fixtures.push('a*b/', 'a*b/ooo', 'ab/ooo'); + }, + + 'trailing slashes', + ['a*b/*', ['ab/ooo', 'a*b/ooo']], + ['a*?/*', ['ab/ooo', 'a*b/ooo']], + ['a\\*b/*', ['a*b/ooo']], + ['a\\*?/*', ['a*b/ooo']], + ['*\\\\!*', [], {null: true}, ['echo !7']], + ['*\\!*', ['echo !7'], null, ['echo !7']], + ['*.\\*', ['r.*'], null, ['r.*']], + ['a[b]c', ['abc']], + ['a[\\b]c', ['abc']], + ['a?c', ['abc']], + ['a\\*c', [], {null: true}, ['abc']], + ['', [''], { null: true }, ['']], + + /** + * Bash tests + */ + + 'http://www.opensource.apple.com/source/bash/bash-23/bash/tests/glob-test', + function () { + fixtures.push('man/', 'man/man1/', 'man/man1/bash.1'); + }, + ['*/man*/bash.*', ['man/man1/bash.1']], + ['man/man1/bash.1', ['man/man1/bash.1']], + ['a***c', ['abc'], null, ['abc']], + ['a*****?c', ['abc'], null, ['abc']], + ['?*****??', ['abc'], null, ['abc']], + ['*****??', ['abc'], null, ['abc']], + ['?*****?c', ['abc'], null, ['abc']], + ['?***?****c', ['abc'], null, ['abc']], + ['?***?****?', ['abc'], null, ['abc']], + ['?***?****', ['abc'], null, ['abc']], + ['*******c', ['abc'], null, ['abc']], + ['*******?', ['abc'], null, ['abc']], + ['a*cd**?**??k', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a**?**cd**?**??k', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a**?**cd**?**??k***', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a**?**cd**?**??***k', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a**?**cd**?**??***k**', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['a****c**?**??*****', ['abcdecdhjk'], null, ['abcdecdhjk']], + ['[-abc]', ['-'], null, ['-']], + ['[abc-]', ['-'], null, ['-']], + ['\\', ['\\'], null, ['\\']], + ['[\\\\]', ['\\'], null, ['\\']], + ['[[]', ['['], null, ['[']], + ['[', ['['], null, ['[']], + ['[*', ['[abc'], null, ['[abc']], + + 'a right bracket shall lose its special meaning and represent itself in a bracket expression if it occurs first in the list. -- POSIX.2 2.8.3.2', + ['[]]', [']'], null, [']']], + ['[]-]', [']'], null, [']']], + ['[a-\z]', ['p'], null, ['p']], + ['??**********?****?', [], { null: true }, ['abc']], + ['??**********?****c', [], { null: true }, ['abc']], + ['?************c****?****', [], { null: true }, ['abc']], + ['*c*?**', [], { null: true }, ['abc']], + ['a*****c*?**', [], { null: true }, ['abc']], + ['a********???*******', [], { null: true }, ['abc']], + ['[]', [], { null: true }, ['a']], + ['[abc', [], { null: true }, ['[']], + + 'nocase tests', + ['XYZ', ['xYz'], { nocase: true, null: true }, + ['xYz', 'ABC', 'IjK']], + [ + 'ab*', + ['ABC'], + { nocase: true, null: true }, + ['xYz', 'ABC', 'IjK'] + ], + [ + '[ia]?[ck]', + ['ABC', 'IjK'], + { nocase: true, null: true }, + ['xYz', 'ABC', 'IjK'] + ], + + 'braces: onestar/twostar', + ['{/*,*}', [], {null: true}, ['/asdf/asdf/asdf']], + // ['{/?,*}', ['/a', 'bb'], {null: true}, ['/a', '/b/b', '/a/b/c', 'bb']], + + 'dots should not match unless requested', + ['**', ['a/b'], {}, ['a/b', 'a/.d', '.a/.d']], + + // .. and . can only match patterns starting with ., + // even when options.dot is set. + function () { + fixtures = ['a/./b', 'a/../b', 'a/c/b', 'a/.d/b']; + }, + ['a/*/b', ['a/c/b', 'a/.d/b'], {dot: true}], + ['a/*/b', ['a/c/b'], {dot: false}], + + ['a/.*/b', ['a/./b', 'a/../b', 'a/.d/b'], {dot: true}], + ['a/.*/b', ['a/./b', 'a/../b', 'a/.d/b'], {dot: false}], + + // this also tests that changing the options needs + // to change the cache key, even if the pattern is + // the same! + ['**', + ['a/b', 'a/.d', '.a/.d'], + { dot: true }, + [ '.a/.d', 'a/.d', 'a/b'] + ], + + // 'paren sets cannot contain slashes', + // ['*(a/b)', ['*(a/b)'], {nonull: true}, ['a/b']], + + // brace sets trump all else. + // + // invalid glob pattern. fails on bash4 and bsdglob. + // however, in this implementation, it's easier just + // to do the intuitive thing, and let brace-expansion + // actually come before parsing any extglob patterns, + // like the documentation seems to say. + // + // XXX: if anyone complains about this, either fix it + // or tell them to grow up and stop complaining. + // + // bash/bsdglob says this: + // , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]] + // but we do this instead: + // ['*(a|{b),c)}', ['a', 'ab', 'ac'], {}, ['a', 'ab', 'ac', 'ad']], + + // test partial parsing in the presence of comment/negation chars + ['[!a*', ['[!ab'], {}, ['[!ab', '[ab']], + + + // crazy nested {,,} and *(||) tests. + function () { + fixtures = [ + 'a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'bc', 'cb', 'bc,d', + 'c,db', 'c,d', 'd)', '(b|c', '*(b|c', 'b|c', 'b|cc', 'cb|c', + 'x(a|b|c)', 'x(a|c)', '(a|b|c)', '(a|c)' + ]; + }, + ['*(a|{b,c})', ['a', 'b', 'c', 'ab', 'ac']], + ['{a,*(b|c,d)}', ['a', '(b|c', '*(b|c', 'd)']], + // a + // *(b|c) + // *(b|d) + ['{a,*(b|{c,d})}', ['a', 'b', 'bc', 'cb', 'c', 'd']], + ['*(a|{b|c,c})', ['a', 'b', 'c', 'ab', 'ac', 'bc', 'cb']], + + // test various flag settings. + [ + '*(a|{b|c,c})', + ['x(a|b|c)', 'x(a|c)', '(a|b|c)', '(a|c)'], + { noext: true } + ], + [ + 'a?b', + ['x/y/acb', 'acb/'], + {matchBase: true}, + ['x/y/acb', 'acb/', 'acb/d/e', 'x/y/acb/d'] + ], + + // begin channelling Boole and deMorgan... + 'negation tests', + function () { + fixtures = ['d', 'e', '!ab', '!abc', 'a!b', '\\!a']; + }, + + // anything that is NOT a* matches. + ['!a*', ['\\!a', 'd', 'e', '!ab', '!abc']], + + // anything that IS !a* matches. + ['!a*', ['!ab', '!abc'], {nonegate: true}], + + // anything that IS a* matches + ['a*', ['a!b']], + + // anything that is NOT !a* matches + ['!\\!a*', ['a!b', 'd', 'e', '\\!a']], + + // negation nestled within a pattern + function () { + fixtures = [ + 'foo.js', + 'foo.bar', + 'foo.js.js', + 'blar.js', + 'foo.', + 'boo.js.boo' + ]; + }, + // last one is tricky! * matches foo, . matches ., and 'js.js' != 'js' + // copy bash 4.3 behavior on this. + + 'https://github.com/isaacs/minimatch/issues/5', + function () { + fixtures = [ + 'a/b/.x/c', 'a/b/.x/c/d', 'a/b/.x/c/d/e', 'a/b/.x', 'a/b/.x/', + 'a/.x/b', '.x', '.x/', '.x/a', '.x/a/b', 'a/.x/b/.x/c', '.x/.x' + ]; + }, + [ + '**/.x/**', + [ + '.x/', '.x/a', '.x/a/b', 'a/.x/b', 'a/b/.x/', 'a/b/.x/c', + 'a/b/.x/c/d', 'a/b/.x/c/d/e' + ] + ], + + 'https://github.com/isaacs/minimatch/issues/59', + ['[z-a]', []], + ['a/[2015-03-10T00:23:08.647Z]/z', []], + ['[a-0][a-\u0100]', []] +]; + +Object.defineProperty(module.exports, 'fixtures', { + get: function () { + return fixtures; + } +}); diff --git a/test/qmarks.js b/test/qmarks.js index 2bcb2ef8..6d2d168b 100644 --- a/test/qmarks.js +++ b/test/qmarks.js @@ -2,16 +2,28 @@ var assert = require('assert'); var argv = require('yargs-parser')(process.argv.slice(2)); -var matcher = argv.mm ? require('minimatch') : require('..'); +var mm = require('minimatch'); +var nm = require('..'); +var matcher = argv.mm ? mm : nm; + +function compare(a, b) { + return a === b ? 0 : a > b ? 1 : -1; +} function match(arr, pattern, expected, options) { var actual = matcher.match(arr, pattern, options); - assert.deepEqual(actual.sort(), expected.sort()); + actual.sort(compare); + expected.sort(compare); + assert.deepEqual(actual, expected); } describe('qmarks and stars', function() { - it('should match with qmarks in globs:', function() { - match(['abc', 'abb', 'acc'], 'a***c', ['abc', 'acc']); + it('should correctly handle question marks in globs', function() { + match(['?'], '?', ['?']); + match(['aaa', 'aac', 'abc'], 'a?c', ['abc', 'aac']); + match(['aaa', 'aac', 'abc'], 'a*?c', ['aac', 'abc']); + match(['a', 'aa', 'ab', 'ab?', 'ac', 'ac?', 'abcd', 'abbb'], 'ab?', ['ab?']); + match(['abc', 'abb', 'acc'], 'a**?c', ['abc', 'acc']); match(['abc'], 'a*****?c', ['abc']); match(['abc', 'zzz', 'bbb'], '?*****??', ['abc', 'zzz', 'bbb']); match(['abc', 'zzz', 'bbb'], '*****??', ['abc', 'zzz', 'bbb']); @@ -28,4 +40,45 @@ describe('qmarks and stars', function() { match(['abcdecdhjk'], 'a**?**cd**?**??***k**', ['abcdecdhjk']); match(['abcdecdhjk'], 'a****c**?**??*****', ['abcdecdhjk']); }); + + it('should match one character per question mark', function() { + match(['a/b/c.md'], 'a/?/c.md', ['a/b/c.md']); + match(['a/bb/c.md'], 'a/?/c.md', []); + match(['a/bb/c.md'], 'a/??/c.md', ['a/bb/c.md']); + match(['a/bbb/c.md'], 'a/??/c.md', []); + match(['a/bbb/c.md'], 'a/???/c.md', ['a/bbb/c.md']); + match(['a/bbbb/c.md'], 'a/????/c.md', ['a/bbbb/c.md']); + }); + + it('should match multiple groups of question marks', function() { + match(['a/bb/c/dd/e.md'], 'a/?/c/?/e.md', []); + match(['a/b/c/d/e.md'], 'a/?/c/?/e.md', ['a/b/c/d/e.md']); + match(['a/b/c/d/e.md'], 'a/?/c/???/e.md', []); + match(['a/b/c/zzz/e.md'], 'a/?/c/???/e.md', ['a/b/c/zzz/e.md']); + }); + + it('should use qmarks with other special characters', function() { + match(['a/b/c/d/e.md'], 'a/?/c/?/*/e.md', []); + match(['a/b/c/d/e/e.md'], 'a/?/c/?/*/e.md', ['a/b/c/d/e/e.md']); + match(['a/b/c/d/efghijk/e.md'], 'a/?/c/?/*/e.md', ['a/b/c/d/efghijk/e.md']); + match(['a/b/c/d/efghijk/e.md'], 'a/?/**/e.md', ['a/b/c/d/efghijk/e.md']); + match(['a/bb/e.md'], 'a/?/e.md', []); + match(['a/bb/e.md'], 'a/?/**/e.md', []); + match(['a/b/c/d/efghijk/e.md'], 'a/*/?/**/e.md', ['a/b/c/d/efghijk/e.md']); + match(['a/b/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md', ['a/b/c/d/efgh.ijk/e.md']); + match(['a/b.bb/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md', ['a/b.bb/c/d/efgh.ijk/e.md']); + match(['a/bbb/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md', ['a/bbb/c/d/efgh.ijk/e.md']); + }); + + it('question marks should not match slashes', function() { + assert(!nm.isMatch('aaa/bbb', 'aaa?bbb')); + assert(!nm.isMatch('aaa//bbb', 'aaa?bbb')); + assert(!nm.isMatch('aaa\\bbb', 'aaa?bbb')); + assert(!nm.isMatch('aaa\\\\bbb', 'aaa?bbb')); + }); + + it('question marks should not match dots', function() { + assert(!nm.isMatch('aaa.bbb', 'aaa?bbb')); + assert(!nm.isMatch('aaa/.bbb', 'aaa/?bbb')); + }); }); diff --git a/test/random.js b/test/random.js new file mode 100644 index 00000000..6e9a0aaa --- /dev/null +++ b/test/random.js @@ -0,0 +1,33 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var forOwn = require('for-own'); +var parse = require('./support/parse'); +var nm = require('./support/matcher'); +var fixtures = parse('*.txt', {cwd: path.join(__dirname, 'fixtures')}); + +forOwn(fixtures, function(lines, filename) { + describe(filename + ':', function() { + lines.forEach(function(line) { + if (typeof line === 'string') { + console.log(line); + return; + } + + var fixture = line[0]; + var pattern = line[1]; + var expected = line[2]; + + var title = '"' + fixture + + '" should' + (expected ? '' : ' not') + + ' match "' + pattern + '"'; + + it(title, function() { + var msg = fixture + (expected ? ' === ' : ' !== ') + pattern; + // assert.equal(nm.isMatch(fixture, pattern), nm.mm.isMatch(fixture, pattern), msg); + assert.equal(nm.isMatch(fixture, pattern), expected, msg); + }); + }); + }); +}); diff --git a/test/regex.ranges.js b/test/regex.ranges.js new file mode 100644 index 00000000..dfdc9602 --- /dev/null +++ b/test/regex.ranges.js @@ -0,0 +1,39 @@ +'use strict'; + +require('mocha'); +var assert = require('assert'); +var argv = require('yargs-parser')(process.argv.slice(2)); +var minimatch = require('minimatch'); +var brackets = require('..'); + +var matcher = argv.mm ? minimatch : brackets; +var isMatch = argv.mm ? minimatch : brackets.isMatch.bind(matcher); + +function match(arr, pattern, expected, options) { + var actual = matcher.match(arr, pattern, options).sort(compare); + expected.sort(compare); + assert.deepEqual(actual, expected); +} + +function compare(a, b) { + return a === b ? 0 : a > b ? 1 : -1; +} + +describe('ranges', function() { + it('should support valid regex ranges', function() { + var fixtures = ['a.a', 'a.b', 'a.a.a', 'c.a', 'd.a.d', 'a.bb', 'a.ccc']; + match(fixtures, '[a-b].[a-b]', ['a.a', 'a.b']); + match(fixtures, '[a-d].[a-b]', ['a.a', 'a.b', 'c.a']); + match(fixtures, '[a-d]*.[a-b]', ['a.a', 'a.b', 'c.a']); + }); + + it('should support valid regex ranges with negation patterns', function() { + var fixtures = ['a.a', 'a.b', 'a.a.a', 'c.a', 'd.a.d', 'a.bb', 'a.ccc']; + match(fixtures, '!*.[a-b]', ['a.bb', 'a.ccc', 'd.a.d']); + match(fixtures, '![a-b].[a-b]', ['a.a.a', 'a.bb', 'a.ccc', 'c.a', 'd.a.d']); + match(fixtures, '![a-b]+.[a-b]+', ['a.a.a', 'a.ccc', 'c.a', 'd.a.d']); + match(fixtures, '!*.[a-b]*', ['a.ccc', 'd.a.d']); + match(fixtures, '*.[^a-b]', ['d.a.d']); + match(fixtures, 'a.[^a-b]*', ['a.ccc']); + }); +}); diff --git a/test/special-chars.js b/test/special-chars.js new file mode 100644 index 00000000..8eed06ad --- /dev/null +++ b/test/special-chars.js @@ -0,0 +1,97 @@ +'use strict'; + +var assert = require('assert'); +var mm = require('./support/match'); + +describe('special characters', function() { + describe('regex', function() { + it('should match common regex characters', function() { + var fixtures = ['a c', 'a1c', 'a123c', 'a.c', 'a.xy.zc', 'a.zc', 'abbbbc', 'abbbc', 'abbc', 'abc', 'abq', 'axy zc', 'axy', 'axy.zc', 'axyzc', '^abc$']; + + mm(fixtures, 'ab?bc', ['abbbc']); + mm(fixtures, 'ab*c', ['abbbbc', 'abbbc', 'abbc', 'abc']); + mm(fixtures, 'ab+bc', ['abbbbc', 'abbbc', 'abbc']); + mm(fixtures, '^abc$', ['^abc$']); + mm(fixtures, 'a.c', ['a.c']); + mm(fixtures, 'a.*c', ['a.c', 'a.xy.zc', 'a.zc']); + mm(fixtures, 'a*c', ['a c', 'a.c', 'a1c', 'a123c', 'abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc', 'axy zc', 'axy.zc', 'a.xy.zc', 'a.zc']); + mm(fixtures, 'a\\w+c', ['a1c', 'a123c', 'abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc'], 'Should match word characters'); + mm(fixtures, 'a\\W+c', ['a.c', 'a c'], 'Should match non-word characters'); + mm(fixtures, 'a\\d+c', ['a1c', 'a123c'], 'Should match numbers'); + mm(['foo@#$%123ASD #$$%^&', 'foo!@#$asdfl;', '123'], '\\d+', ['123']); + mm(['a123c', 'abbbc'], 'a\\D+c', ['abbbc'], 'Should match non-numbers'); + mm(['foo', ' foo '], '(f|o)+\\b', ['foo'], 'Should match word boundaries'); + }); + }); + + describe('$ dollar signs', function() { + it('should treat dollar signs as literal:', function() { + assert(mm.isMatch('$', '$')); + assert(mm.isMatch('$/foo', '$/*')); + assert(mm.isMatch('$/foo', '$/*')); + assert(mm.isMatch('foo$', '*$')); + assert(mm.isMatch('$foo/foo', '$foo/*')); + assert(mm.isMatch('foo$/foo', 'foo$/*')); + assert(mm.isMatch('foo$/foo$', 'foo$/*')); + }); + }); + + describe('^ caret', function() { + it('should treat caret as literal:', function() { + assert(mm.isMatch('^', '^')); + assert(mm.isMatch('^/foo', '^/*')); + assert(mm.isMatch('^/foo', '^/*')); + assert(mm.isMatch('foo^', '*^')); + assert(mm.isMatch('^foo/foo', '^foo/*')); + assert(mm.isMatch('foo^/foo', 'foo^/*')); + }); + }); + + describe('slashes', function() { + it('should match forward slashes', function() { + assert(mm.isMatch('/', '/')); + }); + + it('should match backslashes', function() { + assert(mm.isMatch('\\', '[\\\\]')); + assert(mm.isMatch('\\', '[\\\\]+')); + assert(mm.isMatch('\\\\', '[\\\\]+')); + assert(mm.isMatch('\\\\\\', '[\\\\]+')); + mm(['\\'], '[\\\\]', ['\\']); + mm(['\\', '\\\\', '\\\\\\'], '[\\\\]+', ['\\', '\\\\', '\\\\\\']); + }); + }); + + describe('colons and drive letters', function() { + it('should treat common URL characters as literals', function() { + assert(mm.isMatch(':', ':')); + assert(mm.isMatch(':/foo', ':/*')); + assert(mm.isMatch('D://foo', 'D://*')); + assert(mm.isMatch('D://foo', 'D:\\/\\/*')); + assert(mm.isMatch('D:\\/\\/foo', 'D:\\\\/\\\\/*')); + }); + }); + + describe('[ab] - brackets:', function() { + it('should support regex character classes:', function() { + mm(['a/b.md', 'a/c.md', 'a/d.md', 'a/E.md'], 'a/[A-Z].md', ['a/E.md']); + mm(['a/b.md', 'a/c.md', 'a/d.md'], 'a/[bd].md', ['a/b.md', 'a/d.md']); + mm(['a-1.md', 'a-2.md', 'a-3.md', 'a-4.md', 'a-5.md'], 'a-[2-4].md', ['a-2.md', 'a-3.md', 'a-4.md']); + mm(['a/b.md', 'b/b.md', 'c/b.md', 'b/c.md', 'a/d.md'], '[bc]/[bd].md', ['b/b.md', 'c/b.md']); + }); + + it('should handle unclosed brackets', function() { + mm(['[!ab', '[ab'], '[!a*', ['[!ab']); + }); + }); + + describe('(a|b) - logical OR:', function() { + it('should support regex logical OR:', function() { + mm(['a/a', 'a/b', 'a/c', 'b/a', 'b/b'], '(a|b)/b', ['a/b', 'b/b']); + mm(['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'c/b'], '((a|b)|c)/b', ['a/b', 'b/b', 'c/b']); + mm(['a/b.md', 'a/c.md', 'a/d.md'], 'a/(b|d).md', ['a/b.md', 'a/d.md']); + mm(['a-1.md', 'a-2.md', 'a-3.md', 'a-4.md', 'a-5.md'], 'a-(2|3|4).md', ['a-2.md', 'a-3.md', 'a-4.md']); + mm(['a/b.md', 'b/b.md', 'c/b.md', 'b/c.md', 'a/d.md'], '(b|c)/(b|d).md', ['b/b.md', 'c/b.md']); + }); + }); +}); diff --git a/test/stars.js b/test/stars.js new file mode 100644 index 00000000..d3b32a3c --- /dev/null +++ b/test/stars.js @@ -0,0 +1,84 @@ +'use strict'; + +var assert = require('assert'); +var argv = require('yargs-parser')(process.argv.slice(2)); +var mm = require('..'); +var matcher = argv.mm ? require('multimatch') : mm; + +function match(arr, pattern, expected, options) { + var actual = matcher(arr, pattern, options); + assert.deepEqual(actual.sort(), expected.sort()); +} + +describe('stars', function() { + it('should match one directory level with a single star (*)', function() { + var fixtures = ['a', 'b', 'a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a', 'x/y', 'z/z']; + match(fixtures, '*', ['a', 'b']); + match(fixtures, '*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); + match(fixtures, '*/*/*', ['a/a/a', 'a/a/b']); + match(fixtures, '*/*/*/*', ['a/a/a/a']); + match(fixtures, '*/*/*/*/*', ['a/a/a/a/a']); + match(fixtures, 'a/*', ['a/a', 'a/b', 'a/c', 'a/x']); + match(fixtures, 'a/*/*', ['a/a/a', 'a/a/b']); + match(fixtures, 'a/*/*/*', ['a/a/a/a']); + match(fixtures, 'a/*/*/*/*', ['a/a/a/a/a']); + match(fixtures, 'a/*/a', ['a/a/a']); + match(fixtures, 'a/*/b', ['a/a/b']); + }); + + it('should match one or more characters', function() { + var fixtures = ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac', 'a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a', 'x/y', 'z/z']; + match(fixtures, '*', ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac']); + match(fixtures, 'a*', ['a', 'aa', 'aaa', 'aaaa', 'ab']); + match(fixtures, '*b', ['ab', 'b', 'bb']); + }); + + it('should match one or zero characters', function() { + var fixtures = ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac', 'a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a', 'x/y', 'z/z']; + match(fixtures, '*', ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac']); + match(fixtures, '*a*', ['a', 'aa', 'aaa', 'aaaa', 'ab', 'cac']); + match(fixtures, '*b*', ['ab', 'b', 'bb']); + match(fixtures, '*c*', ['c', 'cc', 'cac']); + }); + + it('should respect trailing slashes on paterns', function() { + var fixtures = ['a', 'a/', 'b', 'b/', 'a/a', 'a/a/', 'a/b', 'a/b/', 'a/c', 'a/c/', 'a/x', 'a/x/', 'a/a/a', 'a/a/b', 'a/a/b/', 'a/a/a/', 'a/a/a/a', 'a/a/a/a/', 'a/a/a/a/a', 'a/a/a/a/a/', 'x/y', 'z/z', 'x/y/', 'z/z/', 'a/b/c/.d/e/']; + match(fixtures, '*/', ['a/', 'b/']); + match(fixtures, '*/*/', ['a/a/', 'a/b/', 'a/c/', 'a/x/', 'x/y/', 'z/z/']); + match(fixtures, '*/*/*/', ['a/a/a/', 'a/a/b/']); + match(fixtures, '*/*/*/*/', ['a/a/a/a/']); + match(fixtures, '*/*/*/*/*/', ['a/a/a/a/a/']); + match(fixtures, 'a/*/', ['a/a/', 'a/b/', 'a/c/', 'a/x/']); + match(fixtures, 'a/*/*/', ['a/a/a/', 'a/a/b/']); + match(fixtures, 'a/*/*/*/', ['a/a/a/a/']); + match(fixtures, 'a/*/*/*/*/', ['a/a/a/a/a/']); + match(fixtures, 'a/*/a/', ['a/a/a/']); + match(fixtures, 'a/*/b/', ['a/a/b/']); + }); + + it('should match a literal star when escaped', function() { + var fixtures = ['.md', 'a**a.md', '**a.md', '**/a.md', '**.md', '.md', '*', '**', '*.md']; + match(fixtures, '\\*', ['*']); + match(fixtures, '\\*.md', ['*.md']); + match(fixtures, '\\**.md', ['**a.md', '**.md', '*.md']); + match(fixtures, 'a\\**.md', ['a**a.md']); + }); + + it('should match leading `./`', function() { + var fixtures = ['a', './a', 'b', 'a/a', './a/b', 'a/c', './a/x', './a/a/a', 'a/a/b', './a/a/a/a', './a/a/a/a/a', 'x/y', './z/z']; + match(fixtures, '*', ['a', 'b']); + match(fixtures, '**/a/**', ['a/a', 'a/c', 'a/b', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + match(fixtures, '*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); + match(fixtures, '*/*/*', ['a/a/a', 'a/a/b']); + match(fixtures, '*/*/*/*', ['a/a/a/a']); + match(fixtures, '*/*/*/*/*', ['a/a/a/a/a']); + match(fixtures, './*', ['a', 'b']); + match(fixtures, './**/a/**', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + match(fixtures, './a/*/a', ['a/a/a']); + match(fixtures, 'a/*', ['a/a', 'a/b', 'a/c', 'a/x']); + match(fixtures, 'a/*/*', ['a/a/a', 'a/a/b']); + match(fixtures, 'a/*/*/*', ['a/a/a/a']); + match(fixtures, 'a/*/*/*/*', ['a/a/a/a/a']); + match(fixtures, 'a/*/a', ['a/a/a']); + }); +}); diff --git a/test/support/bash.js b/test/support/bash.js new file mode 100644 index 00000000..f5b73ea8 --- /dev/null +++ b/test/support/bash.js @@ -0,0 +1,52 @@ +'use strict'; + +var spawn = require('cross-spawn'); +var utils = require('./utils'); + +function bash(str, pattern, options) { + var cmd = pattern; + + if (!/echo/.test(cmd)) { + cmd = `shopt -s extglob && shopt -s globstar && if [[ ${str} == ${pattern} ]]; then echo true; fi`; + } + + var res = spawn.sync(utils.getBashPath(), ['-c', cmd], options); + var err = toString(res.stderr); + if (err) { + console.error(cmd); + throw new Error(err); + } + + return !!toString(res.stdout); +} + +bash.isMatch = function(fixture, pattern, options) { + return bash(fixture, pattern, options); +}; + +bash.match = function(fixtures, pattern) { + var matches = []; + var len = fixtures.length; + var idx = -1; + while (++idx < len) { + var fixture = fixtures[idx]; + if (bash.isMatch(fixture, pattern)) { + matches.push(fixture); + } + } + return matches; +}; + +/** + * Stringify `buf` + */ + +function toString(buf) { + return buf ? buf.toString().trim() : null; +} + +/** + * Expose `bash` + */ + +module.exports = bash; diff --git a/test/support/cc.sh b/test/support/cc.sh deleted file mode 100644 index e051cadb..00000000 --- a/test/support/cc.sh +++ /dev/null @@ -1,35 +0,0 @@ -# -# More ksh-like extended globbing tests, cribbed from zsh-3.1.5 -# -shopt -s extglob - -failed=0 -while read res str pat; do - [[ $res = '#' ]] && continue - [[ $str = ${pat} ]] - ts=$? - [[ $1 = -q ]] || echo "$ts: [[ $str = $pat ]]" - if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then - echo "Test failed: [[ $str = $pat ]]" - (( failed += 1 )) - fi -done < b ? 1 : a < b ? -1 : 0; +}; diff --git a/test/support/exists.js b/test/support/exists.js new file mode 100644 index 00000000..e8d7ab5b --- /dev/null +++ b/test/support/exists.js @@ -0,0 +1,20 @@ +'use strict'; + +var path = require('path'); +var exists = require('fs-exists-sync'); + +module.exports = function(files, cwd) { + files = Array.isArray(files) ? files : [files]; + var len = files.length; + var idx = -1; + while (++idx < len) { + var file = files[idx]; + if (typeof cwd === 'string') { + file = path.join(cwd, file); + } + if (!exists(file)) { + return false; + } + } + return true; +}; diff --git a/test/support/match.js b/test/support/match.js new file mode 100644 index 00000000..ec6df678 --- /dev/null +++ b/test/support/match.js @@ -0,0 +1,61 @@ +'use strict'; + +var assert = require('assert'); +var utils = require('../../lib/utils'); +var matcher = require('./matcher'); +var compare = require('./compare'); + +module.exports = function(fixtures, patterns, expected, options) { + if (!Array.isArray(expected)) { + var tmp = expected; + expected = options; + options = tmp; + } + + var actual = matcher(utils.arrayify(fixtures), patterns, options); + expected.sort(compare); + actual.sort(compare); + + assert.deepEqual(actual, expected, patterns); +}; + +module.exports.match = function(fixtures, pattern, expected, options) { + if (!Array.isArray(expected)) { + var tmp = expected; + expected = options; + options = tmp; + } + + var actual = matcher.match(utils.arrayify(fixtures), pattern, options); + expected.sort(compare); + actual.sort(compare); + + assert.deepEqual(actual, expected, pattern); +}; + +module.exports.isMatch = function() { + return matcher.isMatch.apply(null, arguments); +}; + +module.exports.makeRe = function() { + return matcher.makeRe.apply(null, arguments); +}; + +module.exports.braces = function() { + return matcher.braces.apply(null, arguments); +}; + +function isMatch(fixture, pattern, expected, options) { + if (typeof expected !== 'boolean') { + var tmp = expected; + expected = options; + options = tmp; + } + + var isMatch = matcher.isMatch(fixture, pattern, options); + if (expected === false) { + assert(!isMatch, 'should not match ' + pattern); + } else { + assert(isMatch, 'should match ' + pattern); + } +}; diff --git a/test/support/matcher.js b/test/support/matcher.js new file mode 100644 index 00000000..8ab920fb --- /dev/null +++ b/test/support/matcher.js @@ -0,0 +1,84 @@ +'use strict'; + +var argv = require('yargs-parser')(process.argv.slice(2)); +var mm = require('multimatch'); +var bash = require('bash-match'); +var minimatch = require('minimatch'); +var utils = require('../../lib/utils'); +var nm = require('../..'); + +// use multimatch for the array/array scenario +function mi() { + return mm.apply(null, arguments); +} + +// label for debugging +mm.multimatch = true; +mi.minimatch = true; +nm.nanomatch = true; +bash.bash = true; + +/** + * Decorate methods onto bash for parity with nanomatch + */ + +bash.makeRe = function() {}; + +/** + * Decorate methods onto multimatch for parity with nanomatch + */ + +mm.isMatch = function(files, patterns, options) { + return mm(utils.arrayify(files), patterns, options).length > 0; +}; + +mm.match = function(files, patterns, options) { + return mm(utils.arrayify(files), patterns, options); +}; + +mm.makeRe = function(pattern, options) { + return mi.makeRe(pattern, options); +}; + +mm.braces = function(pattern, options) { + return mi.braceExpand(pattern, options); +}; + +/** + * Decorate methods onto minimatch for parity with nanomatch + */ + +mi.isMatch = function(file, pattern, options) { + return minimatch(file, pattern, options); +}; + +mi.match = function(files, pattern, options) { + return minimatch.match(utils.arrayify(files), pattern, options); +}; + +mi.makeRe = function(pattern, options) { + return minimatch.makeRe(pattern, options); +}; + +mi.braces = function(pattern, options) { + return minimatch.braceExpand(pattern, options); +}; + +/** + * Detect matcher based on argv, with nanomatch as default + */ + +var matcher = argv.mm ? mm : (argv.mi ? mi : nm); +if (argv.bash) { + matcher = bash; +} + +/** + * Expose matcher + */ + +module.exports = matcher; +module.exports.bash = bash; +module.exports.nm = nm; +module.exports.mm = mm; +module.exports.mi = mi; diff --git a/test/support/parse.js b/test/support/parse.js new file mode 100644 index 00000000..60527fd4 --- /dev/null +++ b/test/support/parse.js @@ -0,0 +1,47 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var util = require('util'); +var nm = require('../..'); + +function parseFiles(pattern, options) { + var opts = Object.assign({cwd: process.cwd()}, options); + var cwd = opts.cwd; + + var files = nm(fs.readdirSync(cwd), pattern); + var tests = {}; + + for (var i = 0; i < files.length; i++) { + var file = files[i]; + var name = path.basename(file, path.extname(file)); + tests[name] = parse(path.join(cwd, file)); + } + return tests; +} + +function parse(fp) { + var str = fs.readFileSync(fp, 'utf8'); + var lines = str.split('\n'); + var len = lines.length; + var idx = -1; + var tests = []; + + while (++idx < len) { + var line = lines[idx].trim(); + + if (!line) continue; + if (/^#\s\w/.test(line)) { + tests.push(line.replace(/^[#\s]+/, '').toLowerCase()); + continue; + } + if (!/^[tf] /.test(line)) continue; + + var segs = line.split(/\s+/).filter(Boolean); + if (segs.length !== 3) continue; + tests.push([segs[1], segs[2], segs[0] === 't']); + } + return tests.filter(Boolean); +} + +module.exports = parseFiles; diff --git a/test/support/refs.js b/test/support/refs.js new file mode 100644 index 00000000..8ccceb7d --- /dev/null +++ b/test/support/refs.js @@ -0,0 +1,29 @@ +'use strict'; + +var micromatch = require('../..'); +var minimatch = require('minimatch'); +var nanomatch = require('nanomatch'); +var brackets = require('expand-brackets'); +var extglob = require('extglob'); +var braces = require('braces'); + +/** + * Reference parsers + */ + +module.exports = function(pattern, options) { + console.log('micromatch:', micromatch.makeRe(pattern, options)); + console.log('minimatch:', minimatch.makeRe(pattern, options)); + console.log('nanomatch:', nanomatch.makeRe(pattern, options)); + console.log('brackets:', brackets.makeRe(pattern, options)); + console.log('extglob:', extglob.makeRe(pattern, options)); + console.log('braces:', braces.makeRe(pattern, options)); +}; + +// temporary debuggin methods +module.exports.mc = micromatch; +module.exports.mi = minimatch; +module.exports.nm = nanomatch; +module.exports.bk = brackets; +module.exports.ex = extglob; +module.exports.br = braces; diff --git a/test/support/run.js b/test/support/run.js deleted file mode 100644 index 693646fc..00000000 --- a/test/support/run.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var os = require('os'); -var path = require('path'); -var del = require('delete'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var spawn = require('./spawn'); - -var file = path.resolve(__dirname, argv._[0] || 'extglob.sh'); - -function spawnCommand(cwd, filepath, cb) { - var absolute = path.resolve(cwd, filepath); - var relative = path.relative(cwd, absolute); - var dest = path.resolve(os.homedir(), relative).replace(/\.sh$/, ''); - - fs.readFile(absolute, function(err, contents) { - if (err) return cb(err); - - fs.writeFileSync(dest, contents); - fs.chmod(dest, parseInt('777', 8), function(err) { - if (err) return cb(err); - - spawn(dest, function(err, code) { - if (err) return cb(err); - - del(dest, {force: true}, function(err) { - if (err) return cb(err); - cb(null, code); - }); - }); - }); - }); -} - -spawnCommand(__dirname, file, function(err, code) { - console.log(err); - console.log(code); -}); diff --git a/test/support/spawn.js b/test/support/spawn.js deleted file mode 100644 index 57833f4d..00000000 --- a/test/support/spawn.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -var spawn = require('cross-spawn'); - -module.exports = function buffered(command, args, options, callback) { - var stdout = null; - var stderr = null; - var cp; - - if (typeof options === 'function') { - callback = options; - options = null; - } - - if (typeof args === 'function') { - callback = args; - args = options = null; - } - - cp = spawn(command, args, options); - - cp.stdout && cp.stdout.on('data', function(buffer) { - stdout = stdout || ''; - stdout += buffer.toString(); - }); - - cp.stderr && cp.stderr.on('data', function(buffer) { - stderr = stderr || ''; - stderr += buffer.toString(); - }); - - cp.on('error', callback); - cp.on('close', function(code) { - code !== 0 && stderr && console.warn(stderr); - callback(null, stdout, code); - }); -} diff --git a/test/support/utils.js b/test/support/utils.js new file mode 100644 index 00000000..89c2793d --- /dev/null +++ b/test/support/utils.js @@ -0,0 +1,16 @@ +'use strict'; + +var exists = require('fs-exists-sync'); +var bashPath; + +exports.getBashPath = function() { + if (bashPath) return bashPath; + if (exists('/usr/local/bin/bash')) { + bashPath = '/usr/local/bin/bash'; + } else if (exports.exists('/bin/bash')) { + bashPath = '/bin/bash'; + } else { + bashPath = 'bash'; + } + return bashPath; +}; From 2e339d0df1f76c055e9a21e47dddc2dc935d5837 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 20 Oct 2016 17:38:23 -0400 Subject: [PATCH 07/68] add gulp-unused --- gulpfile.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 5e3e3315..857a63e4 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,6 +2,7 @@ var gulp = require('gulp'); var mocha = require('gulp-mocha'); +var unused = require('gulp-unused'); var istanbul = require('gulp-istanbul'); var eslint = require('gulp-eslint'); @@ -11,16 +12,21 @@ gulp.task('coverage', function() { .pipe(istanbul.hookRequire()); }); -gulp.task('mocha', ['coverage'], function() { +gulp.task('test', ['coverage'], function() { return gulp.src('test/*.js') .pipe(mocha({reporter: 'spec'})) .pipe(istanbul.writeReports()); }); -gulp.task('eslint', function() { - return gulp.src(['gulpfile.js', 'index.js', 'lib/*.js']) +gulp.task('lint', function() { + return gulp.src(['*.js', 'lib/*.js', 'test/{*,support/*}.js']) .pipe(eslint()) .pipe(eslint.format()); }); -gulp.task('default', ['mocha', 'eslint']); +gulp.task('unused', function() { + return gulp.src(['index.js', 'lib/*.js']) + .pipe(unused({keys: Object.keys(require('./lib/utils.js'))})); +}); + +gulp.task('default', ['test', 'lint']); From df915219fcfe93def7ad47f2ae30977f294624d0 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 20 Oct 2016 17:39:42 -0400 Subject: [PATCH 08/68] lint --- test/patterns.js | 20 ++++++++++---------- test/support/patterns.js | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/patterns.js b/test/patterns.js index e86d92b4..08436cd6 100644 --- a/test/patterns.js +++ b/test/patterns.js @@ -42,15 +42,15 @@ module.exports = [ ['[a-c]b*', ['abc', 'abd', 'abe', 'bb', 'cb']], ['[a-y]*[^c]', ['abd', 'abe', 'bb', 'bcd', 'bdir/', 'ca', 'cb', 'dd', 'de']], ['a*[^c]', ['abd', 'abe']], - function () { + function() { fixtures.push('a-b', 'aXb'); }, ['a[X-]b', ['a-b', 'aXb']], - function () { + function() { fixtures.push('.x', '.y'); }, ['[^a-c]*', ['d', 'dd', 'de']], - function () { + function() { fixtures.push('a*b/', 'a*b/ooo', 'ab/ooo'); }, @@ -73,7 +73,7 @@ module.exports = [ */ 'http://www.opensource.apple.com/source/bash/bash-23/bash/tests/glob-test', - function () { + function() { fixtures.push('man/', 'man/man1/', 'man/man1/bash.1'); }, ['*/man*/bash.*', ['man/man1/bash.1']], @@ -140,7 +140,7 @@ module.exports = [ // .. and . can only match patterns starting with ., // even when options.dot is set. - function () { + function() { fixtures = ['a/./b', 'a/../b', 'a/c/b', 'a/.d/b']; }, ['a/*/b', ['a/c/b', 'a/.d/b'], {dot: true}], @@ -182,7 +182,7 @@ module.exports = [ // crazy nested {,,} and *(||) tests. - function () { + function() { fixtures = [ 'a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'bc', 'cb', 'bc,d', 'c,db', 'c,d', 'd)', '(b|c', '*(b|c', 'b|c', 'b|cc', 'cb|c', @@ -212,7 +212,7 @@ module.exports = [ // begin channelling Boole and deMorgan... 'negation tests', - function () { + function() { fixtures = ['d', 'e', '!ab', '!abc', 'a!b', '\\!a']; }, @@ -229,7 +229,7 @@ module.exports = [ ['!\\!a*', ['a!b', 'd', 'e', '\\!a']], // negation nestled within a pattern - function () { + function() { fixtures = [ 'foo.js', 'foo.bar', @@ -243,7 +243,7 @@ module.exports = [ // copy bash 4.3 behavior on this. 'https://github.com/isaacs/minimatch/issues/5', - function () { + function() { fixtures = [ 'a/b/.x/c', 'a/b/.x/c/d', 'a/b/.x/c/d/e', 'a/b/.x', 'a/b/.x/', 'a/.x/b', '.x', '.x/', '.x/a', '.x/a/b', 'a/.x/b/.x/c', '.x/.x' @@ -264,7 +264,7 @@ module.exports = [ ]; Object.defineProperty(module.exports, 'fixtures', { - get: function () { + get: function() { return fixtures; } }); diff --git a/test/support/patterns.js b/test/support/patterns.js index a2b27908..d4ab01ad 100644 --- a/test/support/patterns.js +++ b/test/support/patterns.js @@ -103,4 +103,4 @@ module.exports = [ 'E:**/*.md', 'E:\\\\**/*.js', 'E:\\\\**/*.md', -]; \ No newline at end of file +]; From 4aeeb4f182a7433f6b4b7aacb70d49a340c3fee2 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 20 Oct 2016 17:54:40 -0400 Subject: [PATCH 09/68] normalize tests, clean up --- test/api.isMatch.js | 3 +- test/api.match.js | 59 +- test/api.not.js | 97 ++- test/{random.js => bash.spec.js} | 0 test/brackets.js | 251 ++++---- test/extglobs.js | 563 +++++++++--------- test/{support/extglob.sh => fixtures/extglob} | 20 - test/fixtures/negation | 13 + test/fixtures/patterns.js | 2 - test/integration.js | 12 +- test/malicious.js | 10 +- test/minimatch.js | 2 - test/patterns.js | 270 --------- test/qmarks.js | 108 ++-- test/regex.ranges.js | 36 +- test/stars.js | 103 ++-- test/support/bash.js | 52 -- test/support/dotglob.sh | 44 -- test/support/exists.js | 20 - test/support/generate.js | 43 -- test/support/glob.sh | 101 ---- test/support/globstar.sh | 51 -- test/support/match.js | 17 +- test/support/negation.sh | 34 -- test/support/reference.js | 6 - test/support/refs.js | 29 - 26 files changed, 598 insertions(+), 1348 deletions(-) rename test/{random.js => bash.spec.js} (100%) rename test/{support/extglob.sh => fixtures/extglob} (94%) create mode 100644 test/fixtures/negation delete mode 100644 test/patterns.js delete mode 100644 test/support/bash.js delete mode 100644 test/support/dotglob.sh delete mode 100644 test/support/exists.js delete mode 100644 test/support/generate.js delete mode 100644 test/support/glob.sh delete mode 100644 test/support/globstar.sh delete mode 100644 test/support/negation.sh delete mode 100644 test/support/reference.js delete mode 100644 test/support/refs.js diff --git a/test/api.isMatch.js b/test/api.isMatch.js index cce2708d..4c5c600b 100644 --- a/test/api.isMatch.js +++ b/test/api.isMatch.js @@ -1,7 +1,8 @@ 'use strict'; var assert = require('assert'); -var mm = require('..'); +var mm = require('./support/match'); + describe('.isMatch():', function() { describe('error handling:', function() { diff --git a/test/api.match.js b/test/api.match.js index 5d6f28f8..ab9d6c19 100644 --- a/test/api.match.js +++ b/test/api.match.js @@ -1,69 +1,70 @@ 'use strict'; -var match = require('./support/match'); +var assert = require('assert'); +var mm = require('./support/match'); describe('.match method', function() { describe('posix paths', function() { it('should return an array of matches for a literal string', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; - match(fixtures, '(a/b)', ['a/b']); - match(fixtures, 'a/b', ['a/b']); + mm(fixtures, '(a/b)', ['a/b']); + mm(fixtures, 'a/b', ['a/b']); }); it('should support regex logical or', function() { var fixtures = ['a/a', 'a/b', 'a/c']; - match(fixtures, 'a/(a|c)', ['a/a', 'a/c']); - match(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); + mm(fixtures, 'a/(a|c)', ['a/a', 'a/c']); + mm(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); }); it('should support regex ranges', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'a/x/y', 'a/x']; - match(fixtures, 'a/[b-c]', ['a/b', 'a/c']); - match(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, 'a/[b-c]', ['a/b', 'a/c']); + mm(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); }); it('should support negation patterns', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; - match(fixtures, '!*/*', []); - match(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); - match(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); - match(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); - match(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); - match(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); - match(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); - match(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, '!*/*', []); + mm(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); + mm(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); + mm(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); + mm(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); + mm(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); }); }); describe('unix paths', function() { it('should return an array of matches for a literal string', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; - match(fixtures, '(a/b)', ['a/b']); - match(fixtures, 'a/b', ['a/b']); + mm(fixtures, '(a/b)', ['a/b']); + mm(fixtures, 'a/b', ['a/b']); }); it('should support regex logical or', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c']; - match(fixtures, 'a/(a|c)', ['a/a', 'a/c']); - match(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); + mm(fixtures, 'a/(a|c)', ['a/a', 'a/c']); + mm(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); }); it('should support regex ranges', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x\\y', 'a\\x']; - match(fixtures, 'a/[b-c]', ['a/b', 'a/c']); - match(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, 'a/[b-c]', ['a/b', 'a/c']); + mm(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); }); it('should support negation patterns', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; - match(fixtures, '!*/*', []); - match(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); - match(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); - match(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); - match(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); - match(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); - match(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); - match(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, '!*/*', []); + mm(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); + mm(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); + mm(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); + mm(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); + mm(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); }); }); }); diff --git a/test/api.not.js b/test/api.not.js index 5a85e99e..67956700 100644 --- a/test/api.not.js +++ b/test/api.not.js @@ -1,60 +1,51 @@ 'use strict'; var path = require('path'); -var assert = require('assert'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var matcher = argv.mm ? require('minimatch') : require('..'); -var compare = require('./support/compare'); var sep = path.sep; - -function match(arr, pattern, expected, options) { - var actual = matcher.not(arr, pattern, options); - expected.sort(compare); - actual.sort(compare); - assert.deepEqual(actual, expected); -} +var assert = require('assert'); +var mm = require('./support/match'); describe('.not method', function() { describe('posix paths', function() { it('should return an array of matches for a literal string', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; - match(fixtures, '(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); - match(fixtures, 'a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.not(fixtures, '(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.not(fixtures, 'a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); }); it('should support regex logical or', function() { var fixtures = ['a/a', 'a/b', 'a/c']; - match(fixtures, 'a/(a|c)', ['a/b']); - match(fixtures, 'a/(a|b|c)', []); + mm.not(fixtures, 'a/(a|c)', ['a/b']); + mm.not(fixtures, 'a/(a|b|c)', []); }); it('should support regex ranges', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'a/x/y', 'a/x']; - match(fixtures, 'a/[b-c]', ['a/a', 'a/x/y', 'a/x']); - match(fixtures, 'a/[a-z]', ['a/x/y']); + mm.not(fixtures, 'a/[b-c]', ['a/a', 'a/x/y', 'a/x']); + mm.not(fixtures, 'a/[a-z]', ['a/x/y']); }); it('should support globs (*)', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']; - match(fixtures, 'a/*', ['a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); - match(fixtures, 'a/*/a', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); - match(fixtures, 'a/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a/a', 'a/a/a/a/a']); - match(fixtures, 'a/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a/a']); - match(fixtures, 'a/*/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a']); + mm.not(fixtures, 'a/*', ['a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm.not(fixtures, 'a/*/a', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm.not(fixtures, 'a/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a/a', 'a/a/a/a/a']); + mm.not(fixtures, 'a/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a/a']); + mm.not(fixtures, 'a/*/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a']); }); it('should support globstars (**)', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']; - match(fixtures, 'a/**', []); - match(fixtures, 'a/**/*', []); - match(fixtures, 'a/**/**/*', []); + mm.not(fixtures, 'a/**', []); + mm.not(fixtures, 'a/**/*', []); + mm.not(fixtures, 'a/**/**/*', []); }); it('should support negation patterns', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; - match(fixtures, '!a/b', ['a/b']); - match(fixtures, '!a/(b)', ['a/b']); - match(fixtures, '!(a/b)', ['a/b']); + mm.not(fixtures, '!a/b', ['a/b']); + mm.not(fixtures, '!a/(b)', ['a/b']); + mm.not(fixtures, '!(a/b)', ['a/b']); }); }); @@ -68,53 +59,53 @@ describe('.not method', function() { it('should return an array of matches for a literal string', function() { var fixtures = ['a', 'a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; - match(fixtures, '(a/b)', ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); - match(fixtures, 'a/b', ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.not(fixtures, '(a/b)', ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.not(fixtures, 'a/b', ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); }); it('should support regex logical or', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c']; - match(fixtures, 'a/(a|c)', ['a/b']); - match(fixtures, 'a/(a|b|c)', []); + mm.not(fixtures, 'a/(a|c)', ['a/b']); + mm.not(fixtures, 'a/(a|b|c)', []); }); it('should support regex ranges', function() { var fixtures = ['.\\a\\a', 'a\\a', 'a\\b', 'a\\c', 'a\\x\\y', 'a\\x']; - match(fixtures, '[a-c]/[a-c]', ['a/x', 'a/x/y']); - match(fixtures, 'a/[b-c]', ['a/a', 'a/x', 'a/x/y']); - match(fixtures, 'a/[a-z]', ['a/x/y']); + mm.not(fixtures, '[a-c]/[a-c]', ['a/x', 'a/x/y']); + mm.not(fixtures, 'a/[b-c]', ['a/a', 'a/x', 'a/x/y']); + mm.not(fixtures, 'a/[a-z]', ['a/x/y']); }); it('should support globs (*)', function() { var fixtures = ['a\\a', 'a/a', 'a\\b', '.\\a\\b', 'a\\c', 'a\\x', 'a\\a\\a', 'a\\a\\b', 'a\\a\\a\\a', 'a\\a\\a\\a\\a']; - match(fixtures, 'a/*', ['a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); - match(fixtures, 'a/*/a', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); - match(fixtures, 'a/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a/a', 'a/a/a/a/a']); - match(fixtures, 'a/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a/a']); - match(fixtures, 'a/*/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a']); + mm.not(fixtures, 'a/*', ['a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm.not(fixtures, 'a/*/a', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm.not(fixtures, 'a/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a/a', 'a/a/a/a/a']); + mm.not(fixtures, 'a/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a/a']); + mm.not(fixtures, 'a/*/*/*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a']); }); it('should support globstars (**)', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x', 'a\\x\\y', 'a\\x\\y\\z']; var expected = ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']; - match(fixtures, '*', expected); - match(fixtures, '**', []); - match(fixtures, '*/*', ['a/x/y', 'a/x/y/z']); - match(fixtures, 'a/**', []); - match(fixtures, 'a/x/**', ['a/a', 'a/b', 'a/c', 'a/x']); - match(fixtures, 'a/**/*', []); - match(fixtures, 'a/**/**/*', []); + mm.not(fixtures, '*', expected); + mm.not(fixtures, '**', []); + mm.not(fixtures, '*/*', ['a/x/y', 'a/x/y/z']); + mm.not(fixtures, 'a/**', []); + mm.not(fixtures, 'a/x/**', ['a/a', 'a/b', 'a/c', 'a/x']); + mm.not(fixtures, 'a/**/*', []); + mm.not(fixtures, 'a/**/**/*', []); }); it('should support negation patterns', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; var expected = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; - match(fixtures, '!**', expected); - match(fixtures, '!*/*', expected); - match(fixtures, '!*', []); - match(fixtures, '!a/b', ['a/b']); - match(fixtures, '!a/(b)', ['a/b']); - match(fixtures, '!(a/b)', ['a/b']); + mm.not(fixtures, '!**', expected); + mm.not(fixtures, '!*/*', expected); + mm.not(fixtures, '!*', []); + mm.not(fixtures, '!a/b', ['a/b']); + mm.not(fixtures, '!a/(b)', ['a/b']); + mm.not(fixtures, '!(a/b)', ['a/b']); }); }); }); diff --git a/test/random.js b/test/bash.spec.js similarity index 100% rename from test/random.js rename to test/bash.spec.js diff --git a/test/brackets.js b/test/brackets.js index 18e69ad1..5ee5f58f 100644 --- a/test/brackets.js +++ b/test/brackets.js @@ -1,26 +1,7 @@ 'use strict'; -require('mocha'); var assert = require('assert'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var minimatch = require('minimatch'); -var nm = require('nanomatch'); -var mm = require('..'); - -var matcher = argv.mm ? minimatch : mm; -var isMatch = argv.mm ? minimatch : mm.isMatch.bind(matcher); - -function match(fixtures, pattern, expected, msg) { - var actual = matcher.match(fixtures, pattern).sort(alphaSort); - expected.sort(alphaSort); - assert.deepEqual(actual, expected, pattern + ' ' + (msg || '')); -} - -function alphaSort(a, b) { - a = String(a).toLowerCase(); - b = String(b).toLowerCase(); - return a > b ? 1 : a < b ? -1 : 0; -} +var mm = require('./support/match'); function create(pattern, options) { return mm.create(pattern, options).map(function(obj) { @@ -47,63 +28,63 @@ describe('brackets', function() { describe('.match', function() { it('should support POSIX.2 character classes', function() { - match(['e'], '[[:xdigit:]]', [ 'e' ]); - match(['a', '1', '5', 'A'], '[[:alpha:]123]', [ '1', 'a', 'A' ]); - match(['9', 'A', 'b'], '[![:alpha:]]', ['9']); - match(['9', 'A', 'b'], '[^[:alpha:]]', ['9']); - match(['9', 'a', 'B'], '[[:digit:]]', ['9']); - match(['a', 'b', 'A'], '[:alpha:]', ['a'], 'not a valid posix bracket, but valid char class'); - match(['a', 'b', 'A'], '[[:alpha:]]', [ 'a', 'A', 'b' ]); - match(['a', 'aa', 'aB', 'a7'], '[[:lower:][:lower:]]', ['a']); - match(['a', '7', 'aa', 'aB', 'a7'], '[[:lower:][:digit:]]', [ '7', 'a' ]); + mm(['e'], '[[:xdigit:]]', [ 'e' ]); + mm(['a', '1', '5', 'A'], '[[:alpha:]123]', [ '1', 'a', 'A' ]); + mm(['9', 'A', 'b'], '[![:alpha:]]', ['9']); + mm(['9', 'A', 'b'], '[^[:alpha:]]', ['9']); + mm(['9', 'a', 'B'], '[[:digit:]]', ['9']); + mm(['a', 'b', 'A'], '[:alpha:]', ['a'], 'not a valid posix bracket, but valid char class'); + mm(['a', 'b', 'A'], '[[:alpha:]]', [ 'a', 'A', 'b' ]); + mm(['a', 'aa', 'aB', 'a7'], '[[:lower:][:lower:]]', ['a']); + mm(['a', '7', 'aa', 'aB', 'a7'], '[[:lower:][:digit:]]', [ '7', 'a' ]); }); it('should match word characters', function() { var fixtures = ['a c', 'a1c', 'a123c', 'a.c', 'a.xy.zc', 'a.zc', 'abbbbc', 'abbbc', 'abbc', 'abc', 'abq', 'axy zc', 'axy', 'axy.zc', 'axyzc']; - match(fixtures, 'a[a-z]+c', ['abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc']); + mm(fixtures, 'a[a-z]+c', ['abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc']); }); it('should match character classes', function() { - match(['abc', 'abd'], 'a[bc]d', ['abd']); + mm(['abc', 'abd'], 'a[bc]d', ['abd']); }); it('should match character class alphabetical ranges', function() { - match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]e', ['ace']); - match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]', ['ac']); + mm(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]e', ['ace']); + mm(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[b-d]', ['ac']); }); it('should match character classes with leading dashes', function() { - match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[-c]', ['a-', 'ac']); + mm(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[-c]', ['a-', 'ac']); }); it('should match character classes with trailing dashes', function() { - match(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[c-]', ['a-', 'ac']); + mm(['abc', 'abd', 'ace', 'ac', 'a-'], 'a[c-]', ['a-', 'ac']); }); it('should match bracket literals', function() { - match(['a]c', 'abd', 'ace', 'ac', 'a-'], 'a[]]c', ['a]c']); + mm(['a]c', 'abd', 'ace', 'ac', 'a-'], 'a[]]c', ['a]c']); }); it('should match bracket literals', function() { - match(['a]', 'abd', 'ace', 'ac', 'a-'], 'a]', ['a]']); + mm(['a]', 'abd', 'ace', 'ac', 'a-'], 'a]', ['a]']); }); it('should negation patterns', function() { - match(['a]', 'acd', 'aed', 'ac', 'a-'], 'a[^bc]d', ['aed']); + mm(['a]', 'acd', 'aed', 'ac', 'a-'], 'a[^bc]d', ['aed']); }); it('should match negated dashes', function() { - match(['adc', 'a-c'], 'a[^-b]c', ['adc']); + mm(['adc', 'a-c'], 'a[^-b]c', ['adc']); }); it('should match negated brackets', function() { - match(['adc', 'a]c'], 'a[^]b]c', ['adc']); + mm(['adc', 'a]c'], 'a[^]b]c', ['adc']); }); it('should match alpha-numeric characters', function() { - match(['01234', '0123e456', '0123e45g78'], '[\\de]+', ['01234', '0123e456']); - match(['01234', '0123e456', '0123e45g78'], '[\\de]*', ['01234', '0123e456']); - match(['01234', '0123e456', '0123e45g78'], '[e\\d]+', ['01234', '0123e456']); + mm(['01234', '0123e456', '0123e45g78'], '[\\de]+', ['01234', '0123e456']); + mm(['01234', '0123e456', '0123e45g78'], '[\\de]*', ['01234', '0123e456']); + mm(['01234', '0123e456', '0123e45g78'], '[e\\d]+', ['01234', '0123e456']); }); it('should not create an invalid posix character class:', function() { @@ -112,154 +93,154 @@ describe('brackets', function() { }); it('should return `true` when the pattern matches:', function() { - assert(isMatch('a', '[[:lower:]]')); - assert(isMatch('A', '[[:upper:]]')); - assert(isMatch('A', '[[:digit:][:upper:][:space:]]')); - assert(isMatch('1', '[[:digit:][:upper:][:space:]]')); - assert(isMatch(' ', '[[:digit:][:upper:][:space:]]')); - assert(isMatch('5', '[[:xdigit:]]')); - assert(isMatch('f', '[[:xdigit:]]')); - assert(isMatch('D', '[[:xdigit:]]')); - assert(isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); - assert(isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); - assert(isMatch('.', '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); - assert(isMatch('5', '[a-c[:digit:]x-z]')); - assert(isMatch('b', '[a-c[:digit:]x-z]')); - assert(isMatch('y', '[a-c[:digit:]x-z]')); + assert(mm.isMatch('a', '[[:lower:]]')); + assert(mm.isMatch('A', '[[:upper:]]')); + assert(mm.isMatch('A', '[[:digit:][:upper:][:space:]]')); + assert(mm.isMatch('1', '[[:digit:][:upper:][:space:]]')); + assert(mm.isMatch(' ', '[[:digit:][:upper:][:space:]]')); + assert(mm.isMatch('5', '[[:xdigit:]]')); + assert(mm.isMatch('f', '[[:xdigit:]]')); + assert(mm.isMatch('D', '[[:xdigit:]]')); + assert(mm.isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); + assert(mm.isMatch('_', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]')); + assert(mm.isMatch('.', '[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); + assert(mm.isMatch('5', '[a-c[:digit:]x-z]')); + assert(mm.isMatch('b', '[a-c[:digit:]x-z]')); + assert(mm.isMatch('y', '[a-c[:digit:]x-z]')); }); it('should return `false` when the pattern does not match:', function() { - assert(!isMatch('A', '[[:lower:]]')); - assert(isMatch('A', '[![:lower:]]')); - assert(!isMatch('a', '[[:upper:]]')); - assert(!isMatch('a', '[[:digit:][:upper:][:space:]]')); - assert(!isMatch('.', '[[:digit:][:upper:][:space:]]')); - assert(!isMatch('.', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); - assert(!isMatch('q', '[a-c[:digit:]x-z]')); + assert(!mm.isMatch('A', '[[:lower:]]')); + assert(mm.isMatch('A', '[![:lower:]]')); + assert(!mm.isMatch('a', '[[:upper:]]')); + assert(!mm.isMatch('a', '[[:digit:][:upper:][:space:]]')); + assert(!mm.isMatch('.', '[[:digit:][:upper:][:space:]]')); + assert(!mm.isMatch('.', '[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]')); + assert(!mm.isMatch('q', '[a-c[:digit:]x-z]')); }); }); describe('.makeRe()', function() { it('should make a regular expression for the given pattern:', function() { - assert.deepEqual(matcher.makeRe('[[:alpha:]123]'), /^(?:[a-zA-Z123])$/); - assert.deepEqual(matcher.makeRe('[![:lower:]]'), /^(?:[^a-z])$/); + assert.deepEqual(mm.makeRe('[[:alpha:]123]'), /^(?:[a-zA-Z123])$/); + assert.deepEqual(mm.makeRe('[![:lower:]]'), /^(?:[^a-z])$/); }); }); - describe('.match()', function() { + describe('.mm()', function() { it('should return an array of matching strings:', function() { - assert.deepEqual(matcher.match(['a1B', 'a1b'], '[[:alpha:]][[:digit:]][[:upper:]]'), ['a1B']); - assert.deepEqual(matcher.match(['.', 'a', '!'], '[[:digit:][:punct:][:space:]]'), ['.', '!']); + mm(['a1B', 'a1b'], '[[:alpha:]][[:digit:]][[:upper:]]', ['a1B']); + mm(['.', 'a', '!'], '[[:digit:][:punct:][:space:]]', ['.', '!']); }); }); describe('POSIX: From the test suite for the POSIX.2 (BRE) pattern matching code:', function() { it('First, test POSIX.2 character classes', function() { - assert(isMatch('e', '[[:xdigit:]]')); - assert(isMatch('1', '[[:xdigit:]]')); - assert(isMatch('a', '[[:alpha:]123]')); - assert(isMatch('1', '[[:alpha:]123]')); + assert(mm.isMatch('e', '[[:xdigit:]]')); + assert(mm.isMatch('1', '[[:xdigit:]]')); + assert(mm.isMatch('a', '[[:alpha:]123]')); + assert(mm.isMatch('1', '[[:alpha:]123]')); }); it('should match using POSIX.2 negation patterns', function() { - assert(isMatch('9', '[![:alpha:]]')); - assert(isMatch('9', '[^[:alpha:]]')); + assert(mm.isMatch('9', '[![:alpha:]]')); + assert(mm.isMatch('9', '[^[:alpha:]]')); }); it('should match word characters', function() { - assert(isMatch('A', '[[:word:]]')); - assert(isMatch('B', '[[:word:]]')); - assert(isMatch('a', '[[:word:]]')); - assert(isMatch('b', '[[:word:]]')); + assert(mm.isMatch('A', '[[:word:]]')); + assert(mm.isMatch('B', '[[:word:]]')); + assert(mm.isMatch('a', '[[:word:]]')); + assert(mm.isMatch('b', '[[:word:]]')); }); it('should match digits with word class', function() { - assert(isMatch('1', '[[:word:]]')); - assert(isMatch('2', '[[:word:]]')); + assert(mm.isMatch('1', '[[:word:]]')); + assert(mm.isMatch('2', '[[:word:]]')); }); it('should not digits', function() { - assert(isMatch('1', '[[:digit:]]')); - assert(isMatch('2', '[[:digit:]]')); + assert(mm.isMatch('1', '[[:digit:]]')); + assert(mm.isMatch('2', '[[:digit:]]')); }); it('should not match word characters with digit class', function() { - assert(!isMatch('a', '[[:digit:]]')); - assert(!isMatch('A', '[[:digit:]]')); + assert(!mm.isMatch('a', '[[:digit:]]')); + assert(!mm.isMatch('A', '[[:digit:]]')); }); it('should match uppercase alpha characters', function() { - assert(isMatch('A', '[[:upper:]]')); - assert(isMatch('B', '[[:upper:]]')); + assert(mm.isMatch('A', '[[:upper:]]')); + assert(mm.isMatch('B', '[[:upper:]]')); }); it('should not match lowercase alpha characters', function() { - assert(!isMatch('a', '[[:upper:]]')); - assert(!isMatch('b', '[[:upper:]]')); + assert(!mm.isMatch('a', '[[:upper:]]')); + assert(!mm.isMatch('b', '[[:upper:]]')); }); it('should not match digits with upper class', function() { - assert(!isMatch('1', '[[:upper:]]')); - assert(!isMatch('2', '[[:upper:]]')); + assert(!mm.isMatch('1', '[[:upper:]]')); + assert(!mm.isMatch('2', '[[:upper:]]')); }); it('should match lowercase alpha characters', function() { - assert(isMatch('a', '[[:lower:]]')); - assert(isMatch('b', '[[:lower:]]')); + assert(mm.isMatch('a', '[[:lower:]]')); + assert(mm.isMatch('b', '[[:lower:]]')); }); it('should not match uppercase alpha characters', function() { - assert(!isMatch('A', '[[:lower:]]')); - assert(!isMatch('B', '[[:lower:]]')); + assert(!mm.isMatch('A', '[[:lower:]]')); + assert(!mm.isMatch('B', '[[:lower:]]')); }); it('should match one lower and one upper character', function() { - assert(isMatch('aA', '[[:lower:]][[:upper:]]')); - assert(!isMatch('AA', '[[:lower:]][[:upper:]]')); - assert(!isMatch('Aa', '[[:lower:]][[:upper:]]')); + assert(mm.isMatch('aA', '[[:lower:]][[:upper:]]')); + assert(!mm.isMatch('AA', '[[:lower:]][[:upper:]]')); + assert(!mm.isMatch('Aa', '[[:lower:]][[:upper:]]')); }); it('should match hexidecimal digits', function() { - assert(isMatch('ababab', '[[:xdigit:]]*')); - assert(isMatch('020202', '[[:xdigit:]]*')); - assert(isMatch('900', '[[:xdigit:]]*')); + assert(mm.isMatch('ababab', '[[:xdigit:]]*')); + assert(mm.isMatch('020202', '[[:xdigit:]]*')); + assert(mm.isMatch('900', '[[:xdigit:]]*')); }); it('should match punctuation characters (\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~)', function() { - assert(isMatch('!', '[[:punct:]]')); - assert(isMatch('?', '[[:punct:]]')); - assert(isMatch('#', '[[:punct:]]')); - assert(isMatch('&', '[[:punct:]]')); - assert(isMatch('@', '[[:punct:]]')); - assert(isMatch('+', '[[:punct:]]')); - assert(isMatch('*', '[[:punct:]]')); - assert(isMatch(':', '[[:punct:]]')); - assert(isMatch('=', '[[:punct:]]')); - assert(isMatch('|', '[[:punct:]]')); - assert(isMatch('|++', '[[:punct:]]*')); + assert(mm.isMatch('!', '[[:punct:]]')); + assert(mm.isMatch('?', '[[:punct:]]')); + assert(mm.isMatch('#', '[[:punct:]]')); + assert(mm.isMatch('&', '[[:punct:]]')); + assert(mm.isMatch('@', '[[:punct:]]')); + assert(mm.isMatch('+', '[[:punct:]]')); + assert(mm.isMatch('*', '[[:punct:]]')); + assert(mm.isMatch(':', '[[:punct:]]')); + assert(mm.isMatch('=', '[[:punct:]]')); + assert(mm.isMatch('|', '[[:punct:]]')); + assert(mm.isMatch('|++', '[[:punct:]]*')); }); it('should only match one character', function() { - assert(!isMatch('?*+', '[[:punct:]]')); + assert(!mm.isMatch('?*+', '[[:punct:]]')); }); it('should only match zero or more characters', function() { - assert(isMatch('?*+', '[[:punct:]]*')); - assert(isMatch('', '[[:punct:]]*')); + assert(mm.isMatch('?*+', '[[:punct:]]*')); + assert(mm.isMatch('', '[[:punct:]]*')); }); it('invalid character class expressions are just characters to be matched', function() { - match(['a'], '[:al:]', ['a']); - match(['a'], '[[:al:]', ['a']); - match(['!'], '[abc[:punct:][0-9]', ['!']); + mm(['a'], '[:al:]', ['a']); + mm(['a'], '[[:al:]', ['a']); + mm(['!'], '[abc[:punct:][0-9]', ['!']); }); it('should match the start of a valid sh identifier', function() { - assert(isMatch('PATH', '[_[:alpha:]]*')); + assert(mm.isMatch('PATH', '[_[:alpha:]]*')); }); it('should match the first two characters of a valid sh identifier', function() { - assert(isMatch('PATH', '[_[:alpha:]][_[:alnum:]]*')); + assert(mm.isMatch('PATH', '[_[:alpha:]][_[:alnum:]]*')); }); /** @@ -268,33 +249,33 @@ describe('brackets', function() { */ it('how about A?', function() { - match(['9'], '[[:digit:]]', ['9']); - match(['X'], '[[:digit:]]', []); - match(['aB'], '[[:lower:]][[:upper:]]', ['aB']); - match(['a', '3', 'aa', 'a3', 'abc'], '[[:alpha:][:digit:]]', ['3', 'a']); - match(['a', 'b'], '[[:alpha:]\\]', [], []); + mm(['9'], '[[:digit:]]', ['9']); + mm(['X'], '[[:digit:]]', []); + mm(['aB'], '[[:lower:]][[:upper:]]', ['aB']); + mm(['a', '3', 'aa', 'a3', 'abc'], '[[:alpha:][:digit:]]', ['3', 'a']); + mm(['a', 'b'], '[[:alpha:]\\]', [], []); }); it('OK, what\'s a tab? is it a blank? a space?', function() { - assert(isMatch('\t', '[[:blank:]]')); - assert(isMatch('\t', '[[:space:]]')); - assert(isMatch(' ', '[[:space:]]')); + assert(mm.isMatch('\t', '[[:blank:]]')); + assert(mm.isMatch('\t', '[[:space:]]')); + assert(mm.isMatch(' ', '[[:space:]]')); }); it('let\'s check out characters in the ASCII range', function() { - assert(!isMatch('\\377', '[[:ascii:]]')); - assert(!isMatch('9', '[1[:alpha:]123]')); + assert(!mm.isMatch('\\377', '[[:ascii:]]')); + assert(!mm.isMatch('9', '[1[:alpha:]123]')); }); it('punctuation', function() { - assert(!isMatch(' ', '[[:punct:]]')); + assert(!mm.isMatch(' ', '[[:punct:]]')); }); it('graph', function() { - assert(isMatch('A', '[[:graph:]]')); - assert(!isMatch('\b', '[[:graph:]]')); - assert(!isMatch('\n', '[[:graph:]]')); - assert(isMatch('\s', '[[:graph:]]')); + assert(mm.isMatch('A', '[[:graph:]]')); + assert(!mm.isMatch('\b', '[[:graph:]]')); + assert(!mm.isMatch('\n', '[[:graph:]]')); + assert(mm.isMatch('\s', '[[:graph:]]')); }); }); }); diff --git a/test/extglobs.js b/test/extglobs.js index 469b4992..12aba007 100644 --- a/test/extglobs.js +++ b/test/extglobs.js @@ -1,379 +1,362 @@ 'use strict'; var assert = require('assert'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var minimatch = require('minimatch'); -var micromatch = require('..'); -var extglob = require('extglob'); -var nm = require('nanomatch'); - -var matcher = argv.mm ? minimatch : micromatch; -var isMatch = argv.mm ? minimatch : micromatch.isMatch; - -function match(arr, pattern, expected, options) { - var actual = matcher.match(arr, pattern, options).sort(); - expected.sort(); - assert.deepEqual(actual, expected, micromatch.makeRe(pattern)); -} +var mm = require('./support/match'); /** * These tests were converted directly from bash 4.3 and 4.4 unit tests. */ describe('extglobs', function() { - it('should export a function', function() { - assert.equal(typeof matcher, 'function'); - }); - it('should throw on imbalanced sets when `options.strictErrors` is true', function() { assert.throws(function() { - isMatch('a((b', 'a(b', {strictErrors: true}); + mm.isMatch('a((b', 'a(b', {strictErrors: true}); }, 'row:1 col:2 missing opening parens: "a(b"'); assert.throws(function() { - isMatch('a((b', 'a(*b', {strictErrors: true}); + mm.isMatch('a((b', 'a(*b', {strictErrors: true}); }, 'row:1 col:2 missing opening parens: "a(*b"'); }); it('should match extglobs ending with statechar', function() { // from minimatch tests - assert(!isMatch('ax', 'a?(b*)')); - assert(isMatch('ax', '?(a*|b)')); + assert(!mm.isMatch('ax', 'a?(b*)')); + assert(mm.isMatch('ax', '?(a*|b)')); }); it('should match extended globs:', function() { - match(['a.js.js', 'a.md.js'], '*.*(js).js', ['a.js.js']); - match(['a/z', 'a/b'], 'a/!(z)', ['a/b']); - match(['c/z/v'], 'c/z/v', ['c/z/v']); - match(['c/a/v'], 'c/!(z)/v', ['c/a/v']); - match(['c/z/v', 'c/a/v'], 'c/!(z)/v', ['c/a/v']); - match(['c/z/v', 'c/a/v'], 'c/@(z)/v', ['c/z/v']); - match(['c/z/v', 'c/a/v'], 'c/+(z)/v', ['c/z/v']); - match(['c/z/v', 'c/a/v'], 'c/*(z)/v', ['c/z/v']); - match(['c/z/v', 'z', 'zf', 'fz'], '?(z)', ['z']); - match(['c/z/v', 'z', 'zf', 'fz'], '+(z)', ['z']); - match(['c/z/v', 'z', 'zf', 'fz'], '*(z)', ['z']); - match(['cz', 'abz', 'az'], 'a@(z)', ['az']); - match(['cz', 'abz', 'az'], 'a*@(z)', ['az', 'abz']); - match(['cz', 'abz', 'az'], 'a!(z)', ['abz']); - match(['cz', 'abz', 'az'], 'a?(z)', ['az']); - match(['cz', 'abz', 'az'], 'a+(z)', ['az']); - match(['az', 'bz', 'axz'], 'a+(z)', ['az']); - match(['cz', 'abz', 'az'], 'a*(z)', ['az']); - match(['cz', 'abz', 'az'], 'a**(z)', ['az', 'abz']); - match(['cz', 'abz', 'az'], 'a*!(z)', ['az', 'abz']); + mm(['a.js.js', 'a.md.js'], '*.*(js).js', ['a.js.js']); + mm(['a/z', 'a/b'], 'a/!(z)', ['a/b']); + mm(['c/z/v'], 'c/z/v', ['c/z/v']); + mm(['c/a/v'], 'c/!(z)/v', ['c/a/v']); + mm(['c/z/v', 'c/a/v'], 'c/!(z)/v', ['c/a/v']); + mm(['c/z/v', 'c/a/v'], 'c/@(z)/v', ['c/z/v']); + mm(['c/z/v', 'c/a/v'], 'c/+(z)/v', ['c/z/v']); + mm(['c/z/v', 'c/a/v'], 'c/*(z)/v', ['c/z/v']); + mm(['c/z/v', 'z', 'zf', 'fz'], '?(z)', ['z']); + mm(['c/z/v', 'z', 'zf', 'fz'], '+(z)', ['z']); + mm(['c/z/v', 'z', 'zf', 'fz'], '*(z)', ['z']); + mm(['cz', 'abz', 'az'], 'a@(z)', ['az']); + mm(['cz', 'abz', 'az'], 'a*@(z)', ['az', 'abz']); + mm(['cz', 'abz', 'az'], 'a!(z)', ['abz']); + mm(['cz', 'abz', 'az'], 'a?(z)', ['az']); + mm(['cz', 'abz', 'az'], 'a+(z)', ['az']); + mm(['az', 'bz', 'axz'], 'a+(z)', ['az']); + mm(['cz', 'abz', 'az'], 'a*(z)', ['az']); + mm(['cz', 'abz', 'az'], 'a**(z)', ['az', 'abz']); + mm(['cz', 'abz', 'az'], 'a*!(z)', ['az', 'abz']); }); it('should support negation', function() { var arr = ['a', 'b', 'aa', 'ab', 'bb', 'ac', 'aaa', 'aab', 'abb', 'ccc']; - match(arr, '!(a)*', ['b', 'bb', 'ccc']); - match(arr, 'a!(b)*', ['a', 'aa', 'aaa', 'aab', 'ac']); + mm(arr, '!(a)*', ['b', 'bb', 'ccc']); + mm(arr, 'a!(b)*', ['a', 'aa', 'aaa', 'aab', 'ac']); }); it('should support qmark matching', function() { var arr = ['a', 'aa', 'ab', 'aaa', 'abcdefg']; - match(arr, '?', ['a']); - match(arr, '??', ['aa', 'ab']); - match(arr, '???', ['aaa']); + mm(arr, '?', ['a']); + mm(arr, '??', ['aa', 'ab']); + mm(arr, '???', ['aaa']); }); it('should match exactly one of the given pattern:', function() { var arr = ['aa.aa', 'a.bb', 'a.aa.a', 'cc.a', 'a.a', 'c.a', 'dd.aa.d', 'b.a']; - match(arr, '(b|a).(a)', ['a.a', 'b.a']); - match(arr, '@(b|a).@(a)', ['a.a', 'b.a']); + mm(arr, '(b|a).(a)', ['a.a', 'b.a']); + mm(arr, '@(b|a).@(a)', ['a.a', 'b.a']); }); it('should work with globs', function() { var arr = ['123abc', 'ab', 'abab', 'abcdef', 'accdef', 'abcfefg', 'abef', 'abcfef', 'abd', 'acd']; - match(arr, 'ab*(e|f)', ['ab', 'abef']); - match(arr, 'ab?*(e|f)', ['abd', 'abef', 'abcfef']); - match(arr, 'ab*d+(e|f)', ['abcdef']); - match(arr, 'ab**(e|f)', ['ab', 'abab', 'abcdef', 'abcfefg', 'abcfef', 'abef', 'abd']); - match(arr, 'ab*+(e|f)', ['abcdef', 'abcfef', 'abef']); - match(arr, 'ab**(e|f)g', ['abcfefg']); - match(arr, 'ab***ef', ['abcdef', 'abcfef', 'abef']); - match(arr, 'ab**', ['ab', 'abab', 'abcdef', 'abcfef', 'abcfefg', 'abd', 'abef']); - match(arr, '*?(a)bc', ['123abc']); - match(arr, 'a(b*(foo|bar))d', ['abd']); - match(arr, '(a+|b)+', ['ab', 'abab']); - match(arr, '(a+|b)*', ['ab', 'abab', 'accdef', 'abcdef', 'abcfefg', 'abef', 'abcfef', 'abd', 'acd']); - match(['/dev/udp/129.22.8.102/45'], '/dev\\/@(tcp|udp)\\/*\\/*', ['/dev/udp/129.22.8.102/45']); - match(['12', '1', '12abc'], '0|[1-9]*([0-9])', ['1', '12'], 'Should match valid numbers'); - match(['07', '0377', '09'], '+([0-7])', ['0377', '07'], 'Should match octal numbers'); + mm(arr, 'ab*(e|f)', ['ab', 'abef']); + mm(arr, 'ab?*(e|f)', ['abd', 'abef', 'abcfef']); + mm(arr, 'ab*d+(e|f)', ['abcdef']); + mm(arr, 'ab**(e|f)', ['ab', 'abab', 'abcdef', 'abcfefg', 'abcfef', 'abef', 'abd']); + mm(arr, 'ab*+(e|f)', ['abcdef', 'abcfef', 'abef']); + mm(arr, 'ab**(e|f)g', ['abcfefg']); + mm(arr, 'ab***ef', ['abcdef', 'abcfef', 'abef']); + mm(arr, 'ab**', ['ab', 'abab', 'abcdef', 'abcfef', 'abcfefg', 'abd', 'abef']); + mm(arr, '*?(a)bc', ['123abc']); + mm(arr, 'a(b*(foo|bar))d', ['abd']); + mm(arr, '(a+|b)+', ['ab', 'abab']); + mm(arr, '(a+|b)*', ['ab', 'abab', 'accdef', 'abcdef', 'abcfefg', 'abef', 'abcfef', 'abd', 'acd']); + mm(['/dev/udp/129.22.8.102/45'], '/dev\\/@(tcp|udp)\\/*\\/*', ['/dev/udp/129.22.8.102/45']); + mm(['12', '1', '12abc'], '0|[1-9]*([0-9])', ['1', '12'], 'Should match valid numbers'); + mm(['07', '0377', '09'], '+([0-7])', ['0377', '07'], 'Should match octal numbers'); }); it('stuff from korn\'s book', function() { - assert(isMatch('paragraph', 'para@(chute|graph)')); - assert(!isMatch('paramour', 'para@(chute|graph)')); - assert(isMatch('para991', 'para?([345]|99)1')); - assert(!isMatch('para381', 'para?([345]|99)1')); - assert(!isMatch('paragraph', 'para*([0-9])')); - assert(isMatch('para', 'para*([0-9])')); - assert(isMatch('para13829383746592', 'para*([0-9])')); - assert(!isMatch('paragraph', 'para*([0-9])')); - assert(!isMatch('para', 'para+([0-9])')); - assert(isMatch('para987346523', 'para+([0-9])')); - assert(isMatch('paragraph', 'para!(*.[0-9])')); - assert(isMatch('para.38', 'para!(*.[00-09])')); - assert(isMatch('para.graph', 'para!(*.[0-9])')); - assert(isMatch('para39', 'para!(*.[0-9])')); + assert(mm.isMatch('paragraph', 'para@(chute|graph)')); + assert(!mm.isMatch('paramour', 'para@(chute|graph)')); + assert(mm.isMatch('para991', 'para?([345]|99)1')); + assert(!mm.isMatch('para381', 'para?([345]|99)1')); + assert(!mm.isMatch('paragraph', 'para*([0-9])')); + assert(mm.isMatch('para', 'para*([0-9])')); + assert(mm.isMatch('para13829383746592', 'para*([0-9])')); + assert(!mm.isMatch('paragraph', 'para*([0-9])')); + assert(!mm.isMatch('para', 'para+([0-9])')); + assert(mm.isMatch('para987346523', 'para+([0-9])')); + assert(mm.isMatch('paragraph', 'para!(*.[0-9])')); + assert(mm.isMatch('para.38', 'para!(*.[00-09])')); + assert(mm.isMatch('para.graph', 'para!(*.[0-9])')); + assert(mm.isMatch('para39', 'para!(*.[0-9])')); }); it('tests derived from those in rosenblatt\'s korn shell book', function() { - match(['', '137577991', '2468'], '*(0|1|3|5|7|9)', ['', '137577991']); - match(['file.c', 'file.C', 'file.cc', 'file.ccc'], '*.c?(c)', ['file.c', 'file.cc']); - match(['parse.y', 'shell.c', 'Makefile', 'Makefile.in'], '!(*.c|*.h|Makefile.in|config*|README)', ['parse.y', 'Makefile']); - match(['VMS.FILE;', 'VMS.FILE;0', 'VMS.FILE;1', 'VMS.FILE;139', 'VMS.FILE;1N'], '*\\;[1-9]*([0-9])', ['VMS.FILE;1', 'VMS.FILE;139']); + mm(['', '137577991', '2468'], '*(0|1|3|5|7|9)', ['', '137577991']); + mm(['file.c', 'file.C', 'file.cc', 'file.ccc'], '*.c?(c)', ['file.c', 'file.cc']); + mm(['parse.y', 'shell.c', 'Makefile', 'Makefile.in'], '!(*.c|*.h|Makefile.in|config*|README)', ['parse.y', 'Makefile']); + mm(['VMS.FILE;', 'VMS.FILE;0', 'VMS.FILE;1', 'VMS.FILE;139', 'VMS.FILE;1N'], '*\\;[1-9]*([0-9])', ['VMS.FILE;1', 'VMS.FILE;139']); }); it('tests derived from the pd-ksh test suite', function() { - match(['abcx', 'abcz', 'bbc'], '!([[*])*', ['abcx', 'abcz', 'bbc']); - match(['abcx', 'abcz', 'bbc'], '+(a|b\\[)*', ['abcx', 'abcz']); - match(['abd', 'acd'], 'a+(b|c)d', ['abd', 'acd']); - match(['abd', 'acd', 'ac', 'ab'], 'a!(@(b|B))', ['acd', 'abd', 'ac']); - match(['abd', 'acd'], 'a!(@(b|B))d', ['acd']); - match(['abd', 'acd'], 'a[b*(foo|bar)]d', ['abd']); - match(['abcx', 'abcz', 'bbc', 'aaz', 'aaaz'], '[a*(]*z', ['aaz', 'aaaz', 'abcz']); + mm(['abcx', 'abcz', 'bbc'], '!([[*])*', ['abcx', 'abcz', 'bbc']); + mm(['abcx', 'abcz', 'bbc'], '+(a|b\\[)*', ['abcx', 'abcz']); + mm(['abd', 'acd'], 'a+(b|c)d', ['abd', 'acd']); + mm(['abd', 'acd', 'ac', 'ab'], 'a!(@(b|B))', ['acd', 'abd', 'ac']); + mm(['abd', 'acd'], 'a!(@(b|B))d', ['acd']); + mm(['abd', 'acd'], 'a[b*(foo|bar)]d', ['abd']); + mm(['abcx', 'abcz', 'bbc', 'aaz', 'aaaz'], '[a*(]*z', ['aaz', 'aaaz', 'abcz']); }); it('simple kleene star tests', function() { - assert(!isMatch('foo', '*(a|b\\[)')); - assert(isMatch('foo', '*(a|b\\[)|f*')); + assert(!mm.isMatch('foo', '*(a|b\\[)')); + assert(mm.isMatch('foo', '*(a|b\\[)|f*')); }); it('this doesn\'t work in bash either (per bash micromatch.tests notes)', function() { - assert(!isMatch('*(a|b[)', '*(a|b\\[)')); - assert(isMatch('*(a|b[)', '\\*\\(a\\|b\\[\\)')); + assert(!mm.isMatch('*(a|b[)', '*(a|b\\[)')); + assert(mm.isMatch('*(a|b[)', '\\*\\(a\\|b\\[\\)')); }); it('should support multiple exclusion patterns in one extglob:', function() { var arr = ['a.a', 'a.b', 'a.c', 'a.c.d', 'c.c', 'a.', 'd.d', 'e.e', 'f.f', 'a.abcd']; - match(arr, '*.(a|b|@(ab|a*@(b))*(c)d)', ['a.a', 'a.b', 'a.abcd']); - match(arr, '!(*.a|*.b|*.c)', ['a.', 'a.c.d', 'd.d', 'e.e', 'f.f']); - match(arr, '*!(.a|.b|.c)', arr); - match(arr, '*.!(a|b|c)', ['a.c.d', 'a.', 'd.d', 'e.e', 'f.f']); + mm(arr, '*.(a|b|@(ab|a*@(b))*(c)d)', ['a.a', 'a.b', 'a.abcd']); + mm(arr, '!(*.a|*.b|*.c)', ['a.', 'a.c.d', 'd.d', 'e.e', 'f.f']); + mm(arr, '*!(.a|.b|.c)', arr); + mm(arr, '*.!(a|b|c)', ['a.c.d', 'a.', 'd.d', 'e.e', 'f.f']); }); it('should correctly match empty parens', function() { - match(['def', 'ef'], '()ef', ['ef']); + mm(['def', 'ef'], '()ef', ['ef']); }); it('should match escaped parens', function() { var arr = ['a(b', 'a\\(b', 'a((b', 'a((((b', 'ab']; - match(arr, 'a(b', ['a(b']); - match(arr, 'a\\(b', ['a(b', 'a\\(b']); - match(arr, 'a(*b', ['a(b', 'a((b', 'a((((b']); + mm(arr, 'a(b', ['a(b']); + mm(arr, 'a\\(b', ['a(b', 'a\\(b']); + mm(arr, 'a(*b', ['a(b', 'a((b', 'a((((b']); }); it('should match escaped backslashes', function() { - match(['a(b', 'a\\(b', 'a((b', 'a((((b', 'ab'], 'a\\\\(b', ['a\\(b']); - match(['a\\b', 'a/b', 'ab'], 'a/b', ['a/b']); - match(['a\\z', 'a/z', 'az'], 'a\\z', ['a/z']); + mm(['a(b', 'a\\(b', 'a((b', 'a((((b', 'ab'], 'a\\\\(b', ['a\\(b']); + mm(['a\\b', 'a/b', 'ab'], 'a/b', ['a/b']); + mm(['a\\z', 'a/z', 'az'], 'a\\z', ['a/z']); }); }); describe('bash', function() { it('should match extended globs from the bash spec:', function() { - assert(isMatch('fofo', '*(f*(o))')); - assert(isMatch('ffo', '*(f*(o))')); - assert(isMatch('foooofo', '*(f*(o))')); - assert(isMatch('foooofof', '*(f*(o))')); - assert(isMatch('fooofoofofooo', '*(f*(o))')); - assert(!isMatch('foooofof', '*(f+(o))')); - assert(!isMatch('xfoooofof', '*(f*(o))')); - assert(!isMatch('foooofofx', '*(f*(o))')); - assert(isMatch('ofxoofxo', '*(*(of*(o)x)o)')); - assert(!isMatch('ofooofoofofooo', '*(f*(o))')); - assert(isMatch('foooxfooxfoxfooox', '*(f*(o)x)')); - assert(!isMatch('foooxfooxofoxfooox', '*(f*(o)x)')); - assert(isMatch('foooxfooxfxfooox', '*(f*(o)x)')); - assert(isMatch('ofxoofxo', '*(*(of*(o)x)o)')); - assert(isMatch('ofoooxoofxo', '*(*(of*(o)x)o)')); - assert(isMatch('ofoooxoofxoofoooxoofxo', '*(*(of*(o)x)o)')); - assert(isMatch('ofoooxoofxoofoooxoofxoo', '*(*(of*(o)x)o)')); - assert(!isMatch('ofoooxoofxoofoooxoofxofo', '*(*(of*(o)x)o)')); - assert(isMatch('ofoooxoofxoofoooxoofxooofxofxo', '*(*(of*(o)x)o)')); - assert(isMatch('aac', '*(@(a))a@(c)')); - assert(isMatch('ac', '*(@(a))a@(c)')); - assert(!isMatch('c', '*(@(a))a@(c)')); - assert(isMatch('aaac', '*(@(a))a@(c)')); - assert(!isMatch('baaac', '*(@(a))a@(c)')); - assert(isMatch('abcd', '?@(a|b)*@(c)d')); - assert(isMatch('abcd', '@(ab|a*@(b))*(c)d')); - assert(isMatch('acd', '@(ab|a*(b))*(c)d')); - assert(isMatch('abbcd', '@(ab|a*(b))*(c)d')); - assert(isMatch('effgz', '@(b+(c)d|e*(f)g?|?(h)i@(j|k))')); - assert(isMatch('efgz', '@(b+(c)d|e*(f)g?|?(h)i@(j|k))')); - assert(isMatch('egz', '@(b+(c)d|e*(f)g?|?(h)i@(j|k))')); - assert(isMatch('egzefffgzbcdij', '*(b+(c)d|e*(f)g?|?(h)i@(j|k))')); - assert(!isMatch('egz', '@(b+(c)d|e+(f)g?|?(h)i@(j|k))')); - assert(isMatch('ofoofo', '*(of+(o))')); - assert(isMatch('oxfoxoxfox', '*(oxf+(ox))')); - assert(!isMatch('oxfoxfox', '*(oxf+(ox))')); - assert(isMatch('ofoofo', '*(of+(o)|f)')); - assert(isMatch('foofoofo', '@(foo|f|fo)*(f|of+(o))'), 'Should match as fo+ofo+ofo'); - assert(isMatch('oofooofo', '*(of|oof+(o))')); - assert(isMatch('fffooofoooooffoofffooofff', '*(*(f)*(o))')); - assert(isMatch('fofoofoofofoo', '*(fo|foo)'), 'Should backtrack in alternation matches'); + assert(mm.isMatch('fofo', '*(f*(o))')); + assert(mm.isMatch('ffo', '*(f*(o))')); + assert(mm.isMatch('foooofo', '*(f*(o))')); + assert(mm.isMatch('foooofof', '*(f*(o))')); + assert(mm.isMatch('fooofoofofooo', '*(f*(o))')); + assert(!mm.isMatch('foooofof', '*(f+(o))')); + assert(!mm.isMatch('xfoooofof', '*(f*(o))')); + assert(!mm.isMatch('foooofofx', '*(f*(o))')); + assert(mm.isMatch('ofxoofxo', '*(*(of*(o)x)o)')); + assert(!mm.isMatch('ofooofoofofooo', '*(f*(o))')); + assert(mm.isMatch('foooxfooxfoxfooox', '*(f*(o)x)')); + assert(!mm.isMatch('foooxfooxofoxfooox', '*(f*(o)x)')); + assert(mm.isMatch('foooxfooxfxfooox', '*(f*(o)x)')); + assert(mm.isMatch('ofxoofxo', '*(*(of*(o)x)o)')); + assert(mm.isMatch('ofoooxoofxo', '*(*(of*(o)x)o)')); + assert(mm.isMatch('ofoooxoofxoofoooxoofxo', '*(*(of*(o)x)o)')); + assert(mm.isMatch('ofoooxoofxoofoooxoofxoo', '*(*(of*(o)x)o)')); + assert(!mm.isMatch('ofoooxoofxoofoooxoofxofo', '*(*(of*(o)x)o)')); + assert(mm.isMatch('ofoooxoofxoofoooxoofxooofxofxo', '*(*(of*(o)x)o)')); + assert(mm.isMatch('aac', '*(@(a))a@(c)')); + assert(mm.isMatch('ac', '*(@(a))a@(c)')); + assert(!mm.isMatch('c', '*(@(a))a@(c)')); + assert(mm.isMatch('aaac', '*(@(a))a@(c)')); + assert(!mm.isMatch('baaac', '*(@(a))a@(c)')); + assert(mm.isMatch('abcd', '?@(a|b)*@(c)d')); + assert(mm.isMatch('abcd', '@(ab|a*@(b))*(c)d')); + assert(mm.isMatch('acd', '@(ab|a*(b))*(c)d')); + assert(mm.isMatch('abbcd', '@(ab|a*(b))*(c)d')); + assert(mm.isMatch('effgz', '@(b+(c)d|e*(f)g?|?(h)i@(j|k))')); + assert(mm.isMatch('efgz', '@(b+(c)d|e*(f)g?|?(h)i@(j|k))')); + assert(mm.isMatch('egz', '@(b+(c)d|e*(f)g?|?(h)i@(j|k))')); + assert(mm.isMatch('egzefffgzbcdij', '*(b+(c)d|e*(f)g?|?(h)i@(j|k))')); + assert(!mm.isMatch('egz', '@(b+(c)d|e+(f)g?|?(h)i@(j|k))')); + assert(mm.isMatch('ofoofo', '*(of+(o))')); + assert(mm.isMatch('oxfoxoxfox', '*(oxf+(ox))')); + assert(!mm.isMatch('oxfoxfox', '*(oxf+(ox))')); + assert(mm.isMatch('ofoofo', '*(of+(o)|f)')); + assert(mm.isMatch('foofoofo', '@(foo|f|fo)*(f|of+(o))'), 'Should match as fo+ofo+ofo'); + assert(mm.isMatch('oofooofo', '*(of|oof+(o))')); + assert(mm.isMatch('fffooofoooooffoofffooofff', '*(*(f)*(o))')); + assert(mm.isMatch('fofoofoofofoo', '*(fo|foo)'), 'Should backtrack in alternation matches'); }); it('should support exclusions', function() { - match(['foob', 'foobb', 'foo', 'bar', 'baz', 'foobar'], '!(foo)b*', ['bar', 'baz']); + mm(['foob', 'foobb', 'foo', 'bar', 'baz', 'foobar'], '!(foo)b*', ['bar', 'baz']); // Bash 4.3 says this should match `foo` too. Probably a bug in Bash since this is correct. - match(['foo', 'bar', 'baz', 'foobar'], '*(!(foo))', ['bar', 'baz', 'foobar']); + mm(['foo', 'bar', 'baz', 'foobar'], '*(!(foo))', ['bar', 'baz', 'foobar']); // Bash 4.3 says this should match `foo` and `foobar` too, probably a bug in Bash since this is correct. - match(['foo', 'bar', 'baz', 'foobar'], '!(foo)*', ['bar', 'baz']); + mm(['foo', 'bar', 'baz', 'foobar'], '!(foo)*', ['bar', 'baz']); - match(['moo.cow', 'moo', 'cow'], '!(*.*)', ['moo', 'cow']); - match(['moo.cow', 'moo', 'cow'], '!(*.*).', []); - assert(!isMatch('f', '!(f)')); - assert(!isMatch('f', '+(!(f))')); - assert(!isMatch('f', '*(!(f))')); - assert(!isMatch('mad.moo.cow', '!(*.*).!(*.*)')); - assert(!isMatch('mucca.pazza', 'mu!(*(c))?.pa!(*(z))?')); - assert(!isMatch('zoot', '@(!(z*)|*x)')); - assert(isMatch('foo', '!(x)')); - assert(isMatch('foo', '!(x)*')); - assert(isMatch('foot', '@(!(z*)|*x)')); - assert(isMatch('foox', '@(!(z*)|*x)')); - assert(isMatch('ooo', '!(f)')); - assert(isMatch('ooo', '*(!(f))')); - assert(isMatch('ooo', '+(!(f))')); - assert(isMatch('zoox', '@(!(z*)|*x)')); - match(['aaac', 'foo'], '*(@(a))a@(c)', ['aaac']); - match(['aaac'], '*(@(a))a@(c)', ['aaac']); - match(['aac'], '*(@(a))a@(c)', ['aac']); - match(['aac'], '*(@(a))b@(c)', []); - match(['abbcd'], '@(ab|a*(b))*(c)d', ['abbcd']); - match(['abcd'], '?@(a|b)*@(c)d', ['abcd']); - match(['abcd'], '@(ab|a*@(b))*(c)d', ['abcd']); - match(['ac'], '*(@(a))a@(c)', ['ac']); - match(['acd'], '@(ab|a*(b))*(c)d', ['acd']); - match(['baaac'], '*(@(a))a@(c)', []); - match(['c'], '*(@(a))a@(c)', []); - match(['effgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['effgz']); - match(['efgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['efgz']); - match(['egz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['egz']); - match(['egz'], '@(b+(c)d|e+(f)g?|?(h)i@(j|k))', []); - match(['egzefffgzbcdij'], '*(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['egzefffgzbcdij']); - match(['f'], '!(f)', []); - match(['f'], '*(!(f))', []); - match(['f'], '+(!(f))', []); - match(['fa', 'fb', 'f', 'fo'], '!(f!(o))', ['fo']); - match(['fa', 'fb', 'f', 'fo'], '!(f(o))', ['f', 'fb', 'fa']); - match(['fff', 'foo', 'ooo', 'f'], '*(!(f))', ['fff', 'ooo', 'foo']); - match(['fff'], '!(f)', ['fff']); - match(['fff'], '*(!(f))', ['fff']); - match(['fff'], '+(!(f))', ['fff']); - match(['fffooofoooooffoofffooofff'], '*(*(f)*(o))', ['fffooofoooooffoofffooofff']); - match(['ffo'], '*(f*(o))', ['ffo']); - match(['fofo'], '*(f*(o))', ['fofo']); - match(['fofoofoofofoo'], '*(fo|foo)', ['fofoofoofofoo']); - match(['foo', 'bar'], '!(foo)', ['bar']); - match(['foo'], '!(!(foo))', ['foo']); - match(['foo'], '!(f)', ['foo']); - match(['foo'], '!(x)', ['foo']); - match(['foo'], '!(x)*', ['foo']); - match(['foo'], '*(!(f))', ['foo']); - match(['foo'], '*((foo))', ['foo']); - match(['foo'], '+(!(f))', ['foo']); - match(['foo/bar'], 'foo/!(foo)', ['foo/bar']); - match(['foob', 'foobb'], '(foo)bb', ['foobb']); - match(['foobar'], '!(foo)', ['foobar']); - match(['foofoofo'], '@(foo|f|fo)*(f|of+(o))', ['foofoofo']); - match(['fooofoofofooo'], '*(f*(o))', ['fooofoofofooo']); - match(['foooofo'], '*(f*(o))', ['foooofo']); - match(['foooofof'], '*(f*(o))', ['foooofof']); - match(['foooofof'], '*(f+(o))', []); - match(['foooofofx'], '*(f*(o))', []); - match(['foooxfooxfoxfooox'], '*(f*(o)x)', ['foooxfooxfoxfooox']); - match(['foooxfooxfxfooox'], '*(f*(o)x)', ['foooxfooxfxfooox']); - match(['foooxfooxofoxfooox'], '*(f*(o)x)', []); - match(['foot'], '@(!(z*)|*x)', ['foot']); - match(['foox'], '@(!(z*)|*x)', ['foox']); - match(['mad.moo.cow'], '!(*.*).!(*.*)', []); - match(['moo.cow', 'moo', 'cow'], '.!(*.*)', []); - match(['ofoofo'], '*(of+(o))', ['ofoofo']); - match(['ofoofo'], '*(of+(o)|f)', ['ofoofo']); - match(['ofooofoofofooo'], '*(f*(o))', []); - match(['ofoooxoofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxo']); - match(['ofoooxoofxoofoooxoofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxo']); - match(['ofoooxoofxoofoooxoofxofo'], '*(*(of*(o)x)o)', []); - match(['ofoooxoofxoofoooxoofxoo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxoo']); - match(['ofoooxoofxoofoooxoofxooofxofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxooofxofxo']); - match(['ofxoofxo'], '*(*(of*(o)x)o)', ['ofxoofxo']); - match(['oofooofo'], '*(of|oof+(o))', ['oofooofo']); - match(['ooo'], '!(f)', ['ooo']); - match(['ooo'], '*(!(f))', ['ooo']); - match(['ooo'], '+(!(f))', ['ooo']); - match(['oxfoxfox'], '*(oxf+(ox))', []); - match(['oxfoxoxfox'], '*(oxf+(ox))', ['oxfoxoxfox']); - match(['xfoooofof'], '*(f*(o))', []); - match(['zoot'], '@(!(z*)|*x)', []); - match(['zoox'], '@(!(z*)|*x)', ['zoox']); + mm(['moo.cow', 'moo', 'cow'], '!(*.*)', ['moo', 'cow']); + mm(['moo.cow', 'moo', 'cow'], '!(*.*).', []); + assert(!mm.isMatch('f', '!(f)')); + assert(!mm.isMatch('f', '+(!(f))')); + assert(!mm.isMatch('f', '*(!(f))')); + assert(!mm.isMatch('mad.moo.cow', '!(*.*).!(*.*)')); + assert(!mm.isMatch('mucca.pazza', 'mu!(*(c))?.pa!(*(z))?')); + assert(!mm.isMatch('zoot', '@(!(z*)|*x)')); + assert(mm.isMatch('foo', '!(x)')); + assert(mm.isMatch('foo', '!(x)*')); + assert(mm.isMatch('foot', '@(!(z*)|*x)')); + assert(mm.isMatch('foox', '@(!(z*)|*x)')); + assert(mm.isMatch('ooo', '!(f)')); + assert(mm.isMatch('ooo', '*(!(f))')); + assert(mm.isMatch('ooo', '+(!(f))')); + assert(mm.isMatch('zoox', '@(!(z*)|*x)')); + mm(['aaac', 'foo'], '*(@(a))a@(c)', ['aaac']); + mm(['aaac'], '*(@(a))a@(c)', ['aaac']); + mm(['aac'], '*(@(a))a@(c)', ['aac']); + mm(['aac'], '*(@(a))b@(c)', []); + mm(['abbcd'], '@(ab|a*(b))*(c)d', ['abbcd']); + mm(['abcd'], '?@(a|b)*@(c)d', ['abcd']); + mm(['abcd'], '@(ab|a*@(b))*(c)d', ['abcd']); + mm(['ac'], '*(@(a))a@(c)', ['ac']); + mm(['acd'], '@(ab|a*(b))*(c)d', ['acd']); + mm(['baaac'], '*(@(a))a@(c)', []); + mm(['c'], '*(@(a))a@(c)', []); + mm(['effgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['effgz']); + mm(['efgz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['efgz']); + mm(['egz'], '@(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['egz']); + mm(['egz'], '@(b+(c)d|e+(f)g?|?(h)i@(j|k))', []); + mm(['egzefffgzbcdij'], '*(b+(c)d|e*(f)g?|?(h)i@(j|k))', ['egzefffgzbcdij']); + mm(['f'], '!(f)', []); + mm(['f'], '*(!(f))', []); + mm(['f'], '+(!(f))', []); + mm(['fa', 'fb', 'f', 'fo'], '!(f!(o))', ['fo']); + mm(['fa', 'fb', 'f', 'fo'], '!(f(o))', ['f', 'fb', 'fa']); + mm(['fff', 'foo', 'ooo', 'f'], '*(!(f))', ['fff', 'ooo', 'foo']); + mm(['fff'], '!(f)', ['fff']); + mm(['fff'], '*(!(f))', ['fff']); + mm(['fff'], '+(!(f))', ['fff']); + mm(['fffooofoooooffoofffooofff'], '*(*(f)*(o))', ['fffooofoooooffoofffooofff']); + mm(['ffo'], '*(f*(o))', ['ffo']); + mm(['fofo'], '*(f*(o))', ['fofo']); + mm(['fofoofoofofoo'], '*(fo|foo)', ['fofoofoofofoo']); + mm(['foo', 'bar'], '!(foo)', ['bar']); + mm(['foo'], '!(!(foo))', ['foo']); + mm(['foo'], '!(f)', ['foo']); + mm(['foo'], '!(x)', ['foo']); + mm(['foo'], '!(x)*', ['foo']); + mm(['foo'], '*(!(f))', ['foo']); + mm(['foo'], '*((foo))', ['foo']); + mm(['foo'], '+(!(f))', ['foo']); + mm(['foo/bar'], 'foo/!(foo)', ['foo/bar']); + mm(['foob', 'foobb'], '(foo)bb', ['foobb']); + mm(['foobar'], '!(foo)', ['foobar']); + mm(['foofoofo'], '@(foo|f|fo)*(f|of+(o))', ['foofoofo']); + mm(['fooofoofofooo'], '*(f*(o))', ['fooofoofofooo']); + mm(['foooofo'], '*(f*(o))', ['foooofo']); + mm(['foooofof'], '*(f*(o))', ['foooofof']); + mm(['foooofof'], '*(f+(o))', []); + mm(['foooofofx'], '*(f*(o))', []); + mm(['foooxfooxfoxfooox'], '*(f*(o)x)', ['foooxfooxfoxfooox']); + mm(['foooxfooxfxfooox'], '*(f*(o)x)', ['foooxfooxfxfooox']); + mm(['foooxfooxofoxfooox'], '*(f*(o)x)', []); + mm(['foot'], '@(!(z*)|*x)', ['foot']); + mm(['foox'], '@(!(z*)|*x)', ['foox']); + mm(['mad.moo.cow'], '!(*.*).!(*.*)', []); + mm(['moo.cow', 'moo', 'cow'], '.!(*.*)', []); + mm(['ofoofo'], '*(of+(o))', ['ofoofo']); + mm(['ofoofo'], '*(of+(o)|f)', ['ofoofo']); + mm(['ofooofoofofooo'], '*(f*(o))', []); + mm(['ofoooxoofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxo']); + mm(['ofoooxoofxoofoooxoofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxo']); + mm(['ofoooxoofxoofoooxoofxofo'], '*(*(of*(o)x)o)', []); + mm(['ofoooxoofxoofoooxoofxoo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxoo']); + mm(['ofoooxoofxoofoooxoofxooofxofxo'], '*(*(of*(o)x)o)', ['ofoooxoofxoofoooxoofxooofxofxo']); + mm(['ofxoofxo'], '*(*(of*(o)x)o)', ['ofxoofxo']); + mm(['oofooofo'], '*(of|oof+(o))', ['oofooofo']); + mm(['ooo'], '!(f)', ['ooo']); + mm(['ooo'], '*(!(f))', ['ooo']); + mm(['ooo'], '+(!(f))', ['ooo']); + mm(['oxfoxfox'], '*(oxf+(ox))', []); + mm(['oxfoxoxfox'], '*(oxf+(ox))', ['oxfoxoxfox']); + mm(['xfoooofof'], '*(f*(o))', []); + mm(['zoot'], '@(!(z*)|*x)', []); + mm(['zoox'], '@(!(z*)|*x)', ['zoox']); }); it('should support basic wildmatch features', function() { - assert(!isMatch('foo', '*f')); - assert(!isMatch('foo', '??')); - assert(!isMatch('foo', 'bar')); - assert(!isMatch('foobar', 'foo\\*bar')); - assert(!isMatch('abc', '\\a\\b\\c')); - assert(isMatch('', '')); - assert(isMatch('?a?b', '\\??\\?b')); - assert(isMatch('aaaaaaabababab', '*ab')); - assert(isMatch('\\x\\y\\z', '\\x\\y\\z')); - assert(isMatch('/x/y/z', '/x/y/z')); - assert(isMatch('f\\oo', 'f\\oo')); - assert(isMatch('foo', '*')); - assert(isMatch('foo', '*foo*')); - assert(isMatch('foo', '???')); - assert(isMatch('foo', 'f*')); - assert(isMatch('foo', 'foo')); - assert(isMatch('foo*', 'foo\\*', {unixify: false})); - assert(isMatch('foobar', '*ob*a*r*')); + assert(!mm.isMatch('foo', '*f')); + assert(!mm.isMatch('foo', '??')); + assert(!mm.isMatch('foo', 'bar')); + assert(!mm.isMatch('foobar', 'foo\\*bar')); + assert(!mm.isMatch('abc', '\\a\\b\\c')); + assert(mm.isMatch('', '')); + assert(mm.isMatch('?a?b', '\\??\\?b')); + assert(mm.isMatch('aaaaaaabababab', '*ab')); + assert(mm.isMatch('\\x\\y\\z', '\\x\\y\\z')); + assert(mm.isMatch('/x/y/z', '/x/y/z')); + assert(mm.isMatch('f\\oo', 'f\\oo')); + assert(mm.isMatch('foo', '*')); + assert(mm.isMatch('foo', '*foo*')); + assert(mm.isMatch('foo', '???')); + assert(mm.isMatch('foo', 'f*')); + assert(mm.isMatch('foo', 'foo')); + assert(mm.isMatch('foo*', 'foo\\*', {unixify: false})); + assert(mm.isMatch('foobar', '*ob*a*r*')); }); it('Test recursion and the abort code', function() { - assert(isMatch('-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); - assert(!isMatch('-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); - assert(!isMatch('-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); - assert(isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*', {unixify: false})); - assert(!isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*')); - assert(isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt', '**/*a*b*g*n*t')); - assert(!isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz', '**/*a*b*g*n*t')); - assert(!isMatch('foo', '*/*/*')); - assert(!isMatch('foo/bar', '*/*/*')); - assert(isMatch('foo/bba/arr', '*/*/*')); - assert(!isMatch('foo/bb/aa/rr', '*/*/*')); - assert(isMatch('foo/bb/aa/rr', '**/**/**')); - assert(isMatch('abcXdefXghi', '*X*i')); - assert(!isMatch('ab/cXd/efXg/hi', '*X*i')); - assert(isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i')); - assert(isMatch('ab/cXd/efXg/hi', '**/*X*/**/*i')); + assert(mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(!mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(!mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(mm.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*', {unixify: false})); + assert(!mm.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*')); + assert(mm.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt', '**/*a*b*g*n*t')); + assert(!mm.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz', '**/*a*b*g*n*t')); + assert(!mm.isMatch('foo', '*/*/*')); + assert(!mm.isMatch('foo/bar', '*/*/*')); + assert(mm.isMatch('foo/bba/arr', '*/*/*')); + assert(!mm.isMatch('foo/bb/aa/rr', '*/*/*')); + assert(mm.isMatch('foo/bb/aa/rr', '**/**/**')); + assert(mm.isMatch('abcXdefXghi', '*X*i')); + assert(!mm.isMatch('ab/cXd/efXg/hi', '*X*i')); + assert(mm.isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i')); + assert(mm.isMatch('ab/cXd/efXg/hi', '**/*X*/**/*i')); }); it('Test pathName option', function() { - assert(!isMatch('ab/cXd/efXg/hi', '*Xg*i')); - assert(!isMatch('foo', '*/*/*')); - assert(!isMatch('foo', 'fo')); - assert(!isMatch('foo/bar', '*/*/*')); - assert(!isMatch('foo/bar', 'foo?bar')); - assert(!isMatch('foo/bb/aa/rr', '*/*/*')); - assert(!isMatch('foo/bba/arr', 'foo*')); - assert(!isMatch('foo/bba/arr', 'foo**')); - assert(!isMatch('foo/bba/arr', 'foo/*')); - assert(!isMatch('foo/bba/arr', 'foo/**arr')); - assert(!isMatch('foo/bba/arr', 'foo/**z')); - assert(!isMatch('foo/bba/arr', 'foo/*arr')); - assert(!isMatch('foo/bba/arr', 'foo/*z')); - assert(isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i')); - assert(isMatch('abcXdefXghi', '*X*i')); - assert(isMatch('foo', 'foo')); - assert(isMatch('foo/bar', 'foo/*')); - assert(isMatch('foo/bar', 'foo/bar')); - assert(isMatch('foo/bar', 'foo[/]bar')); - assert(isMatch('foo/bba/arr', '*/*/*')); - assert(isMatch('foo/bba/arr', 'foo/**')); + assert(!mm.isMatch('ab/cXd/efXg/hi', '*Xg*i')); + assert(!mm.isMatch('foo', '*/*/*')); + assert(!mm.isMatch('foo', 'fo')); + assert(!mm.isMatch('foo/bar', '*/*/*')); + assert(!mm.isMatch('foo/bar', 'foo?bar')); + assert(!mm.isMatch('foo/bb/aa/rr', '*/*/*')); + assert(!mm.isMatch('foo/bba/arr', 'foo*')); + assert(!mm.isMatch('foo/bba/arr', 'foo**')); + assert(!mm.isMatch('foo/bba/arr', 'foo/*')); + assert(!mm.isMatch('foo/bba/arr', 'foo/**arr')); + assert(!mm.isMatch('foo/bba/arr', 'foo/**z')); + assert(!mm.isMatch('foo/bba/arr', 'foo/*arr')); + assert(!mm.isMatch('foo/bba/arr', 'foo/*z')); + assert(mm.isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i')); + assert(mm.isMatch('abcXdefXghi', '*X*i')); + assert(mm.isMatch('foo', 'foo')); + assert(mm.isMatch('foo/bar', 'foo/*')); + assert(mm.isMatch('foo/bar', 'foo/bar')); + assert(mm.isMatch('foo/bar', 'foo[/]bar')); + assert(mm.isMatch('foo/bba/arr', '*/*/*')); + assert(mm.isMatch('foo/bba/arr', 'foo/**')); }); }); diff --git a/test/support/extglob.sh b/test/fixtures/extglob similarity index 94% rename from test/support/extglob.sh rename to test/fixtures/extglob index b49eb478..16412f8e 100644 --- a/test/support/extglob.sh +++ b/test/fixtures/extglob @@ -1,19 +1,3 @@ -# -# More ksh-like extended globbing tests, cribbed from zsh-3.1.5 -# -shopt -s extglob - -failed=0 -while read res str pat; do - [[ $res = '#' ]] && continue - [[ $str = ${pat} ]] - ts=$? - [[ $1 = -q ]] || echo "$ts: [[ $str = $pat ]]" - if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then - echo "Test failed: [[ $str = $pat ]]" - (( failed += 1 )) - fi -done < b ? 1 : -1; -} - -function match(arr, pattern, expected, options) { - var actual = matcher.match(arr, pattern, options); - actual.sort(compare); - expected.sort(compare); - assert.deepEqual(actual, expected); -} +var mm = require('./support/match'); describe('qmarks and stars', function() { it('should correctly handle question marks in globs', function() { - match(['?'], '?', ['?']); - match(['aaa', 'aac', 'abc'], 'a?c', ['abc', 'aac']); - match(['aaa', 'aac', 'abc'], 'a*?c', ['aac', 'abc']); - match(['a', 'aa', 'ab', 'ab?', 'ac', 'ac?', 'abcd', 'abbb'], 'ab?', ['ab?']); - match(['abc', 'abb', 'acc'], 'a**?c', ['abc', 'acc']); - match(['abc'], 'a*****?c', ['abc']); - match(['abc', 'zzz', 'bbb'], '?*****??', ['abc', 'zzz', 'bbb']); - match(['abc', 'zzz', 'bbb'], '*****??', ['abc', 'zzz', 'bbb']); - match(['abc', 'abb', 'zzz'], '?*****?c', ['abc']); - match(['abc', 'bbb', 'zzz'], '?***?****c', ['abc']); - match(['abc', 'bbb', 'zzz'], '?***?****?', ['abc', 'bbb', 'zzz']); - match(['abc'], '?***?****', ['abc']); - match(['abc'], '*******c', ['abc']); - match(['abc'], '*******?', ['abc']); - match(['abcdecdhjk'], 'a*cd**?**??k', ['abcdecdhjk']); - match(['abcdecdhjk'], 'a**?**cd**?**??k', ['abcdecdhjk']); - match(['abcdecdhjk'], 'a**?**cd**?**??k***', ['abcdecdhjk']); - match(['abcdecdhjk'], 'a**?**cd**?**??***k', ['abcdecdhjk']); - match(['abcdecdhjk'], 'a**?**cd**?**??***k**', ['abcdecdhjk']); - match(['abcdecdhjk'], 'a****c**?**??*****', ['abcdecdhjk']); + mm(['?'], '?', ['?']); + mm(['aaa', 'aac', 'abc'], 'a?c', ['abc', 'aac']); + mm(['aaa', 'aac', 'abc'], 'a*?c', ['aac', 'abc']); + mm(['a', 'aa', 'ab', 'ab?', 'ac', 'ac?', 'abcd', 'abbb'], 'ab?', ['ab?']); + mm(['abc', 'abb', 'acc'], 'a**?c', ['abc', 'acc']); + mm(['abc'], 'a*****?c', ['abc']); + mm(['abc', 'zzz', 'bbb'], '?*****??', ['abc', 'zzz', 'bbb']); + mm(['abc', 'zzz', 'bbb'], '*****??', ['abc', 'zzz', 'bbb']); + mm(['abc', 'abb', 'zzz'], '?*****?c', ['abc']); + mm(['abc', 'bbb', 'zzz'], '?***?****c', ['abc']); + mm(['abc', 'bbb', 'zzz'], '?***?****?', ['abc', 'bbb', 'zzz']); + mm(['abc'], '?***?****', ['abc']); + mm(['abc'], '*******c', ['abc']); + mm(['abc'], '*******?', ['abc']); + mm(['abcdecdhjk'], 'a*cd**?**??k', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a**?**cd**?**??k', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a**?**cd**?**??k***', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a**?**cd**?**??***k', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a**?**cd**?**??***k**', ['abcdecdhjk']); + mm(['abcdecdhjk'], 'a****c**?**??*****', ['abcdecdhjk']); }); it('should match one character per question mark', function() { - match(['a/b/c.md'], 'a/?/c.md', ['a/b/c.md']); - match(['a/bb/c.md'], 'a/?/c.md', []); - match(['a/bb/c.md'], 'a/??/c.md', ['a/bb/c.md']); - match(['a/bbb/c.md'], 'a/??/c.md', []); - match(['a/bbb/c.md'], 'a/???/c.md', ['a/bbb/c.md']); - match(['a/bbbb/c.md'], 'a/????/c.md', ['a/bbbb/c.md']); + mm(['a/b/c.md'], 'a/?/c.md', ['a/b/c.md']); + mm(['a/bb/c.md'], 'a/?/c.md', []); + mm(['a/bb/c.md'], 'a/??/c.md', ['a/bb/c.md']); + mm(['a/bbb/c.md'], 'a/??/c.md', []); + mm(['a/bbb/c.md'], 'a/???/c.md', ['a/bbb/c.md']); + mm(['a/bbbb/c.md'], 'a/????/c.md', ['a/bbbb/c.md']); }); it('should match multiple groups of question marks', function() { - match(['a/bb/c/dd/e.md'], 'a/?/c/?/e.md', []); - match(['a/b/c/d/e.md'], 'a/?/c/?/e.md', ['a/b/c/d/e.md']); - match(['a/b/c/d/e.md'], 'a/?/c/???/e.md', []); - match(['a/b/c/zzz/e.md'], 'a/?/c/???/e.md', ['a/b/c/zzz/e.md']); + mm(['a/bb/c/dd/e.md'], 'a/?/c/?/e.md', []); + mm(['a/b/c/d/e.md'], 'a/?/c/?/e.md', ['a/b/c/d/e.md']); + mm(['a/b/c/d/e.md'], 'a/?/c/???/e.md', []); + mm(['a/b/c/zzz/e.md'], 'a/?/c/???/e.md', ['a/b/c/zzz/e.md']); }); it('should use qmarks with other special characters', function() { - match(['a/b/c/d/e.md'], 'a/?/c/?/*/e.md', []); - match(['a/b/c/d/e/e.md'], 'a/?/c/?/*/e.md', ['a/b/c/d/e/e.md']); - match(['a/b/c/d/efghijk/e.md'], 'a/?/c/?/*/e.md', ['a/b/c/d/efghijk/e.md']); - match(['a/b/c/d/efghijk/e.md'], 'a/?/**/e.md', ['a/b/c/d/efghijk/e.md']); - match(['a/bb/e.md'], 'a/?/e.md', []); - match(['a/bb/e.md'], 'a/?/**/e.md', []); - match(['a/b/c/d/efghijk/e.md'], 'a/*/?/**/e.md', ['a/b/c/d/efghijk/e.md']); - match(['a/b/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md', ['a/b/c/d/efgh.ijk/e.md']); - match(['a/b.bb/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md', ['a/b.bb/c/d/efgh.ijk/e.md']); - match(['a/bbb/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md', ['a/bbb/c/d/efgh.ijk/e.md']); + mm(['a/b/c/d/e.md'], 'a/?/c/?/*/e.md', []); + mm(['a/b/c/d/e/e.md'], 'a/?/c/?/*/e.md', ['a/b/c/d/e/e.md']); + mm(['a/b/c/d/efghijk/e.md'], 'a/?/c/?/*/e.md', ['a/b/c/d/efghijk/e.md']); + mm(['a/b/c/d/efghijk/e.md'], 'a/?/**/e.md', ['a/b/c/d/efghijk/e.md']); + mm(['a/bb/e.md'], 'a/?/e.md', []); + mm(['a/bb/e.md'], 'a/?/**/e.md', []); + mm(['a/b/c/d/efghijk/e.md'], 'a/*/?/**/e.md', ['a/b/c/d/efghijk/e.md']); + mm(['a/b/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md', ['a/b/c/d/efgh.ijk/e.md']); + mm(['a/b.bb/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md', ['a/b.bb/c/d/efgh.ijk/e.md']); + mm(['a/bbb/c/d/efgh.ijk/e.md'], 'a/*/?/**/e.md', ['a/bbb/c/d/efgh.ijk/e.md']); }); it('question marks should not match slashes', function() { - assert(!nm.isMatch('aaa/bbb', 'aaa?bbb')); - assert(!nm.isMatch('aaa//bbb', 'aaa?bbb')); - assert(!nm.isMatch('aaa\\bbb', 'aaa?bbb')); - assert(!nm.isMatch('aaa\\\\bbb', 'aaa?bbb')); + assert(!mm.isMatch('aaa/bbb', 'aaa?bbb')); + assert(!mm.isMatch('aaa//bbb', 'aaa?bbb')); + assert(!mm.isMatch('aaa\\bbb', 'aaa?bbb')); + assert(!mm.isMatch('aaa\\\\bbb', 'aaa?bbb')); }); it('question marks should not match dots', function() { - assert(!nm.isMatch('aaa.bbb', 'aaa?bbb')); - assert(!nm.isMatch('aaa/.bbb', 'aaa/?bbb')); + assert(!mm.isMatch('aaa.bbb', 'aaa?bbb')); + assert(!mm.isMatch('aaa/.bbb', 'aaa/?bbb')); }); }); diff --git a/test/regex.ranges.js b/test/regex.ranges.js index dfdc9602..af208648 100644 --- a/test/regex.ranges.js +++ b/test/regex.ranges.js @@ -1,39 +1,23 @@ 'use strict'; -require('mocha'); var assert = require('assert'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var minimatch = require('minimatch'); -var brackets = require('..'); - -var matcher = argv.mm ? minimatch : brackets; -var isMatch = argv.mm ? minimatch : brackets.isMatch.bind(matcher); - -function match(arr, pattern, expected, options) { - var actual = matcher.match(arr, pattern, options).sort(compare); - expected.sort(compare); - assert.deepEqual(actual, expected); -} - -function compare(a, b) { - return a === b ? 0 : a > b ? 1 : -1; -} +var mm = require('./support/match'); describe('ranges', function() { it('should support valid regex ranges', function() { var fixtures = ['a.a', 'a.b', 'a.a.a', 'c.a', 'd.a.d', 'a.bb', 'a.ccc']; - match(fixtures, '[a-b].[a-b]', ['a.a', 'a.b']); - match(fixtures, '[a-d].[a-b]', ['a.a', 'a.b', 'c.a']); - match(fixtures, '[a-d]*.[a-b]', ['a.a', 'a.b', 'c.a']); + mm(fixtures, '[a-b].[a-b]', ['a.a', 'a.b']); + mm(fixtures, '[a-d].[a-b]', ['a.a', 'a.b', 'c.a']); + mm(fixtures, '[a-d]*.[a-b]', ['a.a', 'a.b', 'c.a']); }); it('should support valid regex ranges with negation patterns', function() { var fixtures = ['a.a', 'a.b', 'a.a.a', 'c.a', 'd.a.d', 'a.bb', 'a.ccc']; - match(fixtures, '!*.[a-b]', ['a.bb', 'a.ccc', 'd.a.d']); - match(fixtures, '![a-b].[a-b]', ['a.a.a', 'a.bb', 'a.ccc', 'c.a', 'd.a.d']); - match(fixtures, '![a-b]+.[a-b]+', ['a.a.a', 'a.ccc', 'c.a', 'd.a.d']); - match(fixtures, '!*.[a-b]*', ['a.ccc', 'd.a.d']); - match(fixtures, '*.[^a-b]', ['d.a.d']); - match(fixtures, 'a.[^a-b]*', ['a.ccc']); + mm(fixtures, '!*.[a-b]', ['a.bb', 'a.ccc', 'd.a.d']); + mm(fixtures, '![a-b].[a-b]', ['a.a.a', 'a.bb', 'a.ccc', 'c.a', 'd.a.d']); + mm(fixtures, '![a-b]+.[a-b]+', ['a.a.a', 'a.ccc', 'c.a', 'd.a.d']); + mm(fixtures, '!*.[a-b]*', ['a.ccc', 'd.a.d']); + mm(fixtures, '*.[^a-b]', ['d.a.d']); + mm(fixtures, 'a.[^a-b]*', ['a.ccc']); }); }); diff --git a/test/stars.js b/test/stars.js index d3b32a3c..08dfdd39 100644 --- a/test/stars.js +++ b/test/stars.js @@ -1,84 +1,77 @@ 'use strict'; var assert = require('assert'); -var argv = require('yargs-parser')(process.argv.slice(2)); -var mm = require('..'); -var matcher = argv.mm ? require('multimatch') : mm; - -function match(arr, pattern, expected, options) { - var actual = matcher(arr, pattern, options); - assert.deepEqual(actual.sort(), expected.sort()); -} +var mm = require('./support/match'); describe('stars', function() { it('should match one directory level with a single star (*)', function() { var fixtures = ['a', 'b', 'a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a', 'x/y', 'z/z']; - match(fixtures, '*', ['a', 'b']); - match(fixtures, '*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); - match(fixtures, '*/*/*', ['a/a/a', 'a/a/b']); - match(fixtures, '*/*/*/*', ['a/a/a/a']); - match(fixtures, '*/*/*/*/*', ['a/a/a/a/a']); - match(fixtures, 'a/*', ['a/a', 'a/b', 'a/c', 'a/x']); - match(fixtures, 'a/*/*', ['a/a/a', 'a/a/b']); - match(fixtures, 'a/*/*/*', ['a/a/a/a']); - match(fixtures, 'a/*/*/*/*', ['a/a/a/a/a']); - match(fixtures, 'a/*/a', ['a/a/a']); - match(fixtures, 'a/*/b', ['a/a/b']); + mm(fixtures, '*', ['a', 'b']); + mm(fixtures, '*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); + mm(fixtures, '*/*/*', ['a/a/a', 'a/a/b']); + mm(fixtures, '*/*/*/*', ['a/a/a/a']); + mm(fixtures, '*/*/*/*/*', ['a/a/a/a/a']); + mm(fixtures, 'a/*', ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, 'a/*/*', ['a/a/a', 'a/a/b']); + mm(fixtures, 'a/*/*/*', ['a/a/a/a']); + mm(fixtures, 'a/*/*/*/*', ['a/a/a/a/a']); + mm(fixtures, 'a/*/a', ['a/a/a']); + mm(fixtures, 'a/*/b', ['a/a/b']); }); it('should match one or more characters', function() { var fixtures = ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac', 'a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a', 'x/y', 'z/z']; - match(fixtures, '*', ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac']); - match(fixtures, 'a*', ['a', 'aa', 'aaa', 'aaaa', 'ab']); - match(fixtures, '*b', ['ab', 'b', 'bb']); + mm(fixtures, '*', ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac']); + mm(fixtures, 'a*', ['a', 'aa', 'aaa', 'aaaa', 'ab']); + mm(fixtures, '*b', ['ab', 'b', 'bb']); }); it('should match one or zero characters', function() { var fixtures = ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac', 'a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a', 'x/y', 'z/z']; - match(fixtures, '*', ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac']); - match(fixtures, '*a*', ['a', 'aa', 'aaa', 'aaaa', 'ab', 'cac']); - match(fixtures, '*b*', ['ab', 'b', 'bb']); - match(fixtures, '*c*', ['c', 'cc', 'cac']); + mm(fixtures, '*', ['a', 'aa', 'aaa', 'aaaa', 'ab', 'b', 'bb', 'c', 'cc', 'cac']); + mm(fixtures, '*a*', ['a', 'aa', 'aaa', 'aaaa', 'ab', 'cac']); + mm(fixtures, '*b*', ['ab', 'b', 'bb']); + mm(fixtures, '*c*', ['c', 'cc', 'cac']); }); it('should respect trailing slashes on paterns', function() { var fixtures = ['a', 'a/', 'b', 'b/', 'a/a', 'a/a/', 'a/b', 'a/b/', 'a/c', 'a/c/', 'a/x', 'a/x/', 'a/a/a', 'a/a/b', 'a/a/b/', 'a/a/a/', 'a/a/a/a', 'a/a/a/a/', 'a/a/a/a/a', 'a/a/a/a/a/', 'x/y', 'z/z', 'x/y/', 'z/z/', 'a/b/c/.d/e/']; - match(fixtures, '*/', ['a/', 'b/']); - match(fixtures, '*/*/', ['a/a/', 'a/b/', 'a/c/', 'a/x/', 'x/y/', 'z/z/']); - match(fixtures, '*/*/*/', ['a/a/a/', 'a/a/b/']); - match(fixtures, '*/*/*/*/', ['a/a/a/a/']); - match(fixtures, '*/*/*/*/*/', ['a/a/a/a/a/']); - match(fixtures, 'a/*/', ['a/a/', 'a/b/', 'a/c/', 'a/x/']); - match(fixtures, 'a/*/*/', ['a/a/a/', 'a/a/b/']); - match(fixtures, 'a/*/*/*/', ['a/a/a/a/']); - match(fixtures, 'a/*/*/*/*/', ['a/a/a/a/a/']); - match(fixtures, 'a/*/a/', ['a/a/a/']); - match(fixtures, 'a/*/b/', ['a/a/b/']); + mm(fixtures, '*/', ['a/', 'b/']); + mm(fixtures, '*/*/', ['a/a/', 'a/b/', 'a/c/', 'a/x/', 'x/y/', 'z/z/']); + mm(fixtures, '*/*/*/', ['a/a/a/', 'a/a/b/']); + mm(fixtures, '*/*/*/*/', ['a/a/a/a/']); + mm(fixtures, '*/*/*/*/*/', ['a/a/a/a/a/']); + mm(fixtures, 'a/*/', ['a/a/', 'a/b/', 'a/c/', 'a/x/']); + mm(fixtures, 'a/*/*/', ['a/a/a/', 'a/a/b/']); + mm(fixtures, 'a/*/*/*/', ['a/a/a/a/']); + mm(fixtures, 'a/*/*/*/*/', ['a/a/a/a/a/']); + mm(fixtures, 'a/*/a/', ['a/a/a/']); + mm(fixtures, 'a/*/b/', ['a/a/b/']); }); it('should match a literal star when escaped', function() { var fixtures = ['.md', 'a**a.md', '**a.md', '**/a.md', '**.md', '.md', '*', '**', '*.md']; - match(fixtures, '\\*', ['*']); - match(fixtures, '\\*.md', ['*.md']); - match(fixtures, '\\**.md', ['**a.md', '**.md', '*.md']); - match(fixtures, 'a\\**.md', ['a**a.md']); + mm(fixtures, '\\*', ['*']); + mm(fixtures, '\\*.md', ['*.md']); + mm(fixtures, '\\**.md', ['**a.md', '**.md', '*.md']); + mm(fixtures, 'a\\**.md', ['a**a.md']); }); it('should match leading `./`', function() { var fixtures = ['a', './a', 'b', 'a/a', './a/b', 'a/c', './a/x', './a/a/a', 'a/a/b', './a/a/a/a', './a/a/a/a/a', 'x/y', './z/z']; - match(fixtures, '*', ['a', 'b']); - match(fixtures, '**/a/**', ['a/a', 'a/c', 'a/b', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); - match(fixtures, '*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); - match(fixtures, '*/*/*', ['a/a/a', 'a/a/b']); - match(fixtures, '*/*/*/*', ['a/a/a/a']); - match(fixtures, '*/*/*/*/*', ['a/a/a/a/a']); - match(fixtures, './*', ['a', 'b']); - match(fixtures, './**/a/**', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); - match(fixtures, './a/*/a', ['a/a/a']); - match(fixtures, 'a/*', ['a/a', 'a/b', 'a/c', 'a/x']); - match(fixtures, 'a/*/*', ['a/a/a', 'a/a/b']); - match(fixtures, 'a/*/*/*', ['a/a/a/a']); - match(fixtures, 'a/*/*/*/*', ['a/a/a/a/a']); - match(fixtures, 'a/*/a', ['a/a/a']); + mm(fixtures, '*', ['a', 'b']); + mm(fixtures, '**/a/**', ['a/a', 'a/c', 'a/b', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm(fixtures, '*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); + mm(fixtures, '*/*/*', ['a/a/a', 'a/a/b']); + mm(fixtures, '*/*/*/*', ['a/a/a/a']); + mm(fixtures, '*/*/*/*/*', ['a/a/a/a/a']); + mm(fixtures, './*', ['a', 'b']); + mm(fixtures, './**/a/**', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm(fixtures, './a/*/a', ['a/a/a']); + mm(fixtures, 'a/*', ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, 'a/*/*', ['a/a/a', 'a/a/b']); + mm(fixtures, 'a/*/*/*', ['a/a/a/a']); + mm(fixtures, 'a/*/*/*/*', ['a/a/a/a/a']); + mm(fixtures, 'a/*/a', ['a/a/a']); }); }); diff --git a/test/support/bash.js b/test/support/bash.js deleted file mode 100644 index f5b73ea8..00000000 --- a/test/support/bash.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -var spawn = require('cross-spawn'); -var utils = require('./utils'); - -function bash(str, pattern, options) { - var cmd = pattern; - - if (!/echo/.test(cmd)) { - cmd = `shopt -s extglob && shopt -s globstar && if [[ ${str} == ${pattern} ]]; then echo true; fi`; - } - - var res = spawn.sync(utils.getBashPath(), ['-c', cmd], options); - var err = toString(res.stderr); - if (err) { - console.error(cmd); - throw new Error(err); - } - - return !!toString(res.stdout); -} - -bash.isMatch = function(fixture, pattern, options) { - return bash(fixture, pattern, options); -}; - -bash.match = function(fixtures, pattern) { - var matches = []; - var len = fixtures.length; - var idx = -1; - while (++idx < len) { - var fixture = fixtures[idx]; - if (bash.isMatch(fixture, pattern)) { - matches.push(fixture); - } - } - return matches; -}; - -/** - * Stringify `buf` - */ - -function toString(buf) { - return buf ? buf.toString().trim() : null; -} - -/** - * Expose `bash` - */ - -module.exports = bash; diff --git a/test/support/dotglob.sh b/test/support/dotglob.sh deleted file mode 100644 index 6aea4bfc..00000000 --- a/test/support/dotglob.sh +++ /dev/null @@ -1,44 +0,0 @@ -# -# More ksh-like extended globbing tests, cribbed from zsh-3.1.5 -# -shopt -s extglob - -failed=0 -while read res str pat; do - [[ $res = '#' ]] && continue - [[ $str = ${pat} ]] - ts=$? - [[ $1 = -q ]] || echo "$ts: [[ $str = $pat ]]" - if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then - echo "Test failed: [[ $str = $pat ]]" - (( failed += 1 )) - fi -done < - * - * Copyright (c) 2014 Jon Schlinkert, contributors. - * Licensed under the MIT License - */ - -'use strict'; - -var fs = require('fs'); -var path = require('path'); -var should = require('should'); -var mini = require('minimatch'); -var patterns = require('./patterns'); -var micro = require('../..'); - -writeActual('mini', mini.makeRe); -writeActual('mini-negate', mini.makeRe, {negate: true}); -writeActual('mini-dot', mini.makeRe, {dot: true}); -writeActual('mini-matchBase', mini.makeRe, {matchBase: true}); -writeActual('mini-dot-matchBase', mini.makeRe, {dot: true, matchBase: true}); - -writeActual('micro', micro.makeRe); -writeActual('micro-negate', micro.makeRe, {negate: true}); -writeActual('micro-dot', micro.makeRe, {dot: true}); -writeActual('micro-matchBase', micro.makeRe, {matchBase: true}); -writeActual('micro-dot-matchBase', micro.makeRe, {dot: true, matchBase: true}); - -function unit(fixture, expected) { - return 'var actual = fn("' + fixture + '");\nactual.should.eql(' + expected + ');\n'; -} - -function writeActual(dest, fn, options) { - options = options || {}; - var res = patterns.reduce(function(acc, fixture) { - if (options.negate) { - fixture = '!' + fixture; - } - return acc.concat(unit(fixture, fn(fixture, options))); - }, []).join('\n'); - - fs.writeFileSync(__dirname + '/../actual/' + dest + '.js', res); -} diff --git a/test/support/glob.sh b/test/support/glob.sh deleted file mode 100644 index c9b2aded..00000000 --- a/test/support/glob.sh +++ /dev/null @@ -1,101 +0,0 @@ -# -# More ksh-like extended globbing tests, cribbed from zsh-3.1.5 -# -shopt -s extglob - -failed=0 -while read res str pat; do - [[ $res = '#' ]] && continue - [[ $str = ${pat} ]] - ts=$? - [[ $1 = -q ]] || echo "$ts: [[ $str = $pat ]]" - if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then - echo "Test failed: [[ $str = $pat ]]" - (( failed += 1 )) - fi -done < Date: Thu, 20 Oct 2016 23:13:56 -0400 Subject: [PATCH 10/68] remove debug, lint --- index.js | 3 --- package.json | 7 ++----- roadmap.md | 9 --------- 3 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 roadmap.md diff --git a/index.js b/index.js index 0d69d70b..398de58f 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,6 @@ var braces = require('braces'); var toRegex = require('to-regex'); -var debug = require('debug')('micromatch'); var extend = require('extend-shallow'); /** @@ -37,8 +36,6 @@ var MAX_LENGTH = 1024 * 64; */ function micromatch(list, patterns, options) { - debug('micromatch <%s>', patterns); - patterns = utils.arrayify(patterns); list = utils.arrayify(list); var len = patterns.length; diff --git a/package.json b/package.json index 2958824c..0352fc66 100644 --- a/package.json +++ b/package.json @@ -36,25 +36,23 @@ "arr-diff": "^3.0.0", "arr-union": "^3.1.0", "array-unique": "^0.3.2", - "bash-match": "^0.1.3", + "bash-match": "^0.2.0", "braces": "^2.0.1", "debug": "^2.2.0", "define-property": "^0.2.5", - "expand-brackets": "^2.1.2", "extend-shallow": "^2.0.1", "extglob": "^1.0.0", "for-own": "^0.1.4", "fragment-cache": "^0.2.0", "is-glob": "^3.1.0", "kind-of": "^3.0.4", - "nanomatch": "^0.2.1", + "nanomatch": "^0.3.0", "object.pick": "^1.1.2", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "devDependencies": { - "cross-spawn": "^4.0.2", "export-files": "^2.1.1", "fs-exists-sync": "^0.1.0", "gulp": "^3.9.1", @@ -66,7 +64,6 @@ "minimatch": "^3.0.3", "mocha": "^3.1.2", "multimatch": "^2.1.0", - "should": "^11.1.1", "yargs-parser": "^4.0.2" }, "keywords": [ diff --git a/roadmap.md b/roadmap.md deleted file mode 100644 index 01e1dd8c..00000000 --- a/roadmap.md +++ /dev/null @@ -1,9 +0,0 @@ -# Roadmap - -``` -micromatch - L braces - L nanomatch - L extglob - L expand-brackets (POSIX character classes) -``` \ No newline at end of file From 96837a1a6b687ac776d2611b572fb22744423b16 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Fri, 21 Oct 2016 17:46:37 -0400 Subject: [PATCH 11/68] refactor, add 3,000+ unit tests --- .github/contributing.md | 57 + .github/issue_template.md | 13 + .github/pull_request_template.md | 108 + appveyor.yml | 26 + benchmark/code/match/minimatch.js | 4 +- benchmark/code/match/multimatch.js | 5 + ...large.js => braces-globstar-large-list.js} | 0 benchmark/fixtures/match/braces-multiple.js | 326 +- .../match/{range.js => braces-range.js} | 0 .../match/{braces.js => braces-set.js} | 0 .../fixtures/match/globstar-large-list.js | 7925 +++++++++++++++++ .../match/{long.js => globstar-long-list.js} | 0 ...r-small-list.js => globstar-short-list.js} | 0 .../match/{basename.js => star-basename.js} | 0 .../fixtures/match/{immediate.js => star.js} | 0 benchmark/helper.js | 84 + benchmark/last.md | 108 +- benchmark/package.json | 8 +- index.js | 297 +- lib/compilers.js | 2 +- lib/micromatch.js | 97 - lib/utils.js | 130 +- package.json | 42 +- test/api.isMatch.js | 1 - test/api.match.js | 1 - test/api.not.js | 1 - test/brackets.js | 8 + test/comparison.isMatch.js | 113 + test/comparison.makeRe.js | 113 + test/integration.js | 1 - test/options.js | 14 +- test/{regex.ranges.js => regex-ranges.js} | 1 - test/stars.js | 1 - test/support/parse.js | 1 - test/support/patterns.js | 2 +- 35 files changed, 9018 insertions(+), 471 deletions(-) create mode 100644 .github/contributing.md create mode 100644 .github/issue_template.md create mode 100644 .github/pull_request_template.md create mode 100644 appveyor.yml create mode 100644 benchmark/code/match/multimatch.js rename benchmark/fixtures/match/{large.js => braces-globstar-large-list.js} (100%) rename benchmark/fixtures/match/{range.js => braces-range.js} (100%) rename benchmark/fixtures/match/{braces.js => braces-set.js} (100%) create mode 100644 benchmark/fixtures/match/globstar-large-list.js rename benchmark/fixtures/match/{long.js => globstar-long-list.js} (100%) rename benchmark/fixtures/match/{globstar-small-list.js => globstar-short-list.js} (100%) rename benchmark/fixtures/match/{basename.js => star-basename.js} (100%) rename benchmark/fixtures/match/{immediate.js => star.js} (100%) create mode 100644 benchmark/helper.js delete mode 100644 lib/micromatch.js create mode 100644 test/comparison.isMatch.js create mode 100644 test/comparison.makeRe.js rename test/{regex.ranges.js => regex-ranges.js} (96%) diff --git a/.github/contributing.md b/.github/contributing.md new file mode 100644 index 00000000..0bc32a89 --- /dev/null +++ b/.github/contributing.md @@ -0,0 +1,57 @@ +# Contributing to micromatch + +First and foremost, thank you! We appreciate that you want to contribute to micromatch, your time is valuable, and your contributions mean a lot to us. + +**What does "contributing" mean?** + +Creating an issue is the simplest form of contributing to a project. But there are many ways to contribute, including the following: + +- Updating or correcting documentation +- Feature requests +- Bug reports + +If you'd like to learn more about contributing in general, the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing) has a lot of useful information. + +**Showing support for micromatch** + +Please keep in mind that open source software is built by people like you, who spend their free time creating things the rest the community can use. + +Don't have time to contribute? No worries, here are some other ways to show your support for micromatch: + +- star the [project](https://github.com/jonschlinkert/micromatch) +- tweet your support for micromatch + +## Issues + +### Before creating an issue + +Please try to determine if the issue is caused by an underlying library, and if so, create the issue there. Sometimes this is difficult to know. We only ask that you attempt to give a reasonable attempt to find out. Oftentimes the readme will have advice about where to go to create issues. + +Try to follow these guidelines + +- **Investigate the issue**: There might be an existing issue that covers the bug you experienced. If so, please do not create a new issue, feel free to add comments to the issue that best describes what you're experiencing. +- **Check the readme** - oftentimes you will find notes about creating issues, and where to go depending on the type of issue. +- Create the issue in the appropriate repository: try to find out if the bug you're experiencing is in micromatch or one of its dependencies + +### Creating an issue + +Please be as descriptive as possible when creating an issue. Give us the information we need to successfully answer your question or address your issue by answering the following in your issue: + +- **version**: please note the version of micromatch are you using +- **extensions, plugins, helpers, etc** (if applicable): please list any extensions you're using +- **error messages**: please paste any error messages into the issue, or a [gist](https://gist.github.com/) + +## Above and beyond + +Here are some tips for creating idiomatic issues. Taking just a little bit extra time will make your issue easier to read, easier to resolve, more likely to be found by others who have the same or similar issue in the future. + +- read the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing) +- take some time to learn basic markdown. This [markdown cheatsheet](https://gist.github.com/jonschlinkert/5854601) is super helpful, as is the GitHub guide to [basic markdown](https://help.github.com/articles/markdown-basics/). +- Learn about [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown/). And if you want to really go above and beyond, read [mastering markdown](https://guides.github.com/features/mastering-markdown/). +- use backticks to wrap code. This ensures that code will retain its format, making it much more readable to others +- use syntax highlighting by adding the correct language name after the first "code fence" + + +[node-glob]: https://github.com/isaacs/node-glob +[micromatch]: https://github.com/jonschlinkert/micromatch +[so]: http://stackoverflow.com/questions/tagged/micromatch diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 00000000..c47a6b65 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,13 @@ +_(Thanks for reporting an issue to micromatch! If you haven't already read the [contributor guidelines](contributing.md), Please do that now, then procede to fill out the details below.)_ + +## Please describe the **minimum necessary steps** to reproduce this issue: + +… + +## What is happening (but shouldn't): + +… + +## What should be happening instead? + +… diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..d375759b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,108 @@ +Hello, and thanks for contributing to micromatch! + +## tldr + +There are three main goals in this document, depending on the nature of your pr: + +- [description](#description): please tell us about your pr +- [checklist](#checklist): please review the checklist that is most closly related to your pr +- [contributors list](#packagejson-contributors): you're one of us now, please add yourself to `package.json` and let the world know! + +The following sections provide more detail on each. + +**Improve this document** + +Please don't hesitate to [ask questions][issues] for clarification, or to [make suggestions][issues] (or a pull request) to improve this document. + +## Description + +To help the project's maintainers and community to quickly understand the nature of your pull requeset, please create a description that incorporates the following elements: + +- [] what is accomplished by the pr +- [] if there is something potentially controversial in your pr, please take a moment to tell us about your choices + +## Checklist + +Please use the checklist that is most closely related to your pr _(you only need to use one checklist, and you can skip items that aren't applicable or don't make sense)_: + +- [fixing typos]() +- [documentation]() +- [bug fix]() +- [new feature]() +- [other]() + +### Fixing typos + +- [ ] Please review the [readme advice]() section before submitting changes +- [ ] Add your to the [contributors](#packagejson-contributors) array in package.json! + +### Documentation + +- [ ] Please review the [readme advice](#readme-advice) section before submitting changes +- [ ] Add your info to the [contributors](#packagejson-contributors) array in package.json! + +### Bug Fix + +- [ ] All existing unit tests are still passing (if applicable) +- [ ] Add new passing unit tests to cover the code introduced by your pr +- [ ] Update the readme (see [readme advice](#readme-advice)) +- [ ] Update or add any necessary API documentation +- [ ] Add your info to the [contributors](#packagejson-contributors) array in package.json! + +### New Feature + +- [ ] If this is a big feature with breaking changes, consider [opening an issue][issues] to discuss first. This is completely up to you, but please keep in mind that your pr might not be accepted. +- [ ] Run unit tests to ensure all existing tests are still passing +- [ ] Add new passing unit tests to cover the code introduced by your pr +- [ ] Update the readme (see [readme advice](#readme-advice)) +- [ ] Add your info to the [contributors](#packagejson-contributors) array in package.json! + +Thanks for contributing! + +## Readme advice + +Please review this section if you are updating readme documentation. + +**Readme template** + +This project uses [verb][] for documentation. Verb generates the project's readme documentation from the [.verb.md](../.verb.md) template in the root of this project. + +Make all documentation changes in `.verb.md`, and please _do not edit the readme.md directly_, or your changes might accidentally get overwritten. + +**Code comments** + +Please add code comments (following the same style as existing comments) to describe any code changes or new code introduced by your pull request. + +**Optionally build the readme** + +Any changes made `.verb.md` and/or code comments will be automatically incorporated into the README documentation the next time `verb` is run. + +We can take care of building the documentation for you when we merge in your changes, or feel free to run [verb][] yourself. Whatever you prefer is fine with us. + +## package.json contributors + +**Add yourself!** + +When adding your information to the `contributors` array in package.json, please use the following format (provide your name at minimum, the other fields are optional): + +``` +full name (https://website.com) +``` + +**Example** + +```json +// -- package.json -- +{ + "name": "micromatch", + "contributors": [ + "Brian Woodward (https://github.com/jonschlinkert)", + "Jon Schlinkert (https://github.com/doowb)", + ] +} +``` + +_(If a `contributors` array does not already exist, please feel free to add one wherever you want, and congratulations on being the first to contribute!)_ + +[issues]: ../../issues +[verb]: https://github.com/verbose/verb diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..ce44317a --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,26 @@ +# Test against this version of Node.js +environment: + matrix: + # node.js + - nodejs_version: "6.0" + - nodejs_version: "5.0" + - nodejs_version: "0.12" + - nodejs_version: "0.10" + +# Install scripts. (runs after repo cloning) +install: + # Get the latest stable version of Node.js or io.js + - ps: Install-Product node $env:nodejs_version + # install modules + - npm install + +# Post-install test scripts. +test_script: + # Output useful info for debugging. + - node --version + - npm --version + # run tests + - npm test + +# Don't actually build. +build: off diff --git a/benchmark/code/match/minimatch.js b/benchmark/code/match/minimatch.js index e7a5d6d7..f4e5ee43 100644 --- a/benchmark/code/match/minimatch.js +++ b/benchmark/code/match/minimatch.js @@ -1,5 +1,5 @@ -var multimatch = require('multimatch'); +var minimatch = require('minimatch'); module.exports = function(files, pattern) { - return multimatch(files, pattern); + return minimatch.match(files, pattern); }; diff --git a/benchmark/code/match/multimatch.js b/benchmark/code/match/multimatch.js new file mode 100644 index 00000000..e7a5d6d7 --- /dev/null +++ b/benchmark/code/match/multimatch.js @@ -0,0 +1,5 @@ +var multimatch = require('multimatch'); + +module.exports = function(files, pattern) { + return multimatch(files, pattern); +}; diff --git a/benchmark/fixtures/match/large.js b/benchmark/fixtures/match/braces-globstar-large-list.js similarity index 100% rename from benchmark/fixtures/match/large.js rename to benchmark/fixtures/match/braces-globstar-large-list.js diff --git a/benchmark/fixtures/match/braces-multiple.js b/benchmark/fixtures/match/braces-multiple.js index 0189a1bb..f6672cb7 100644 --- a/benchmark/fixtures/match/braces-multiple.js +++ b/benchmark/fixtures/match/braces-multiple.js @@ -1,167 +1,167 @@ module.exports = [ [ - "a/g-j.txt", - "b/g-j.txt", - "c/g-j.txt", - "a/h-j.txt", - "b/h-j.txt", - "c/h-j.txt", - "a/i-j.txt", - "b/i-j.txt", - "c/i-j.txt", - "a/g-k.txt", - "b/g-k.txt", - "c/g-k.txt", - "a/h-k.txt", - "b/h-k.txt", - "c/h-k.txt", - "a/i-k.txt", - "b/i-k.txt", - "c/i-k.txt", - "a/g-l.txt", - "b/g-l.txt", - "c/g-l.txt", - "a/h-l.txt", - "b/h-l.txt", - "c/h-l.txt", - "a/i-l.txt", - "b/i-l.txt", - "c/i-l.txt", - "a/g-j.js", - "b/g-j.js", - "c/g-j.js", - "a/h-j.js", - "b/h-j.js", - "c/h-j.js", - "a/i-j.js", - "b/i-j.js", - "c/i-j.js", - "a/g-k.js", - "b/g-k.js", - "c/g-k.js", - "a/h-k.js", - "b/h-k.js", - "c/h-k.js", - "a/i-k.js", - "b/i-k.js", - "c/i-k.js", - "a/g-l.js", - "b/g-l.js", - "c/g-l.js", - "a/h-l.js", - "b/h-l.js", - "c/h-l.js", - "a/i-l.js", - "b/i-l.js", - "c/i-l.js", - "a/g-j.md", - "b/g-j.md", - "c/g-j.md", - "a/h-j.md", - "b/h-j.md", - "c/h-j.md", - "a/i-j.md", - "b/i-j.md", - "c/i-j.md", - "a/g-k.md", - "b/g-k.md", - "c/g-k.md", - "a/h-k.md", - "b/h-k.md", - "c/h-k.md", - "a/i-k.md", - "b/i-k.md", - "c/i-k.md", - "a/g-l.md", - "b/g-l.md", - "c/g-l.md", - "a/h-l.md", - "b/h-l.md", - "c/h-l.md", - "a/i-l.md", - "b/i-l.md", - "c/i-l.md", - "a/g-j.hbs", - "b/g-j.hbs", - "c/g-j.hbs", - "a/h-j.hbs", - "b/h-j.hbs", - "c/h-j.hbs", - "a/i-j.hbs", - "b/i-j.hbs", - "c/i-j.hbs", - "a/g-k.hbs", - "b/g-k.hbs", - "c/g-k.hbs", - "a/h-k.hbs", - "b/h-k.hbs", - "c/h-k.hbs", - "a/i-k.hbs", - "b/i-k.hbs", - "c/i-k.hbs", - "a/g-l.hbs", - "b/g-l.hbs", - "c/g-l.hbs", - "a/h-l.hbs", - "b/h-l.hbs", - "c/h-l.hbs", - "a/i-l.hbs", - "b/i-l.hbs", - "c/i-l.hbs", - "a/g-j.json", - "b/g-j.json", - "c/g-j.json", - "a/h-j.json", - "b/h-j.json", - "c/h-j.json", - "a/i-j.json", - "b/i-j.json", - "c/i-j.json", - "a/g-k.json", - "b/g-k.json", - "c/g-k.json", - "a/h-k.json", - "b/h-k.json", - "c/h-k.json", - "a/i-k.json", - "b/i-k.json", - "c/i-k.json", - "a/g-l.json", - "b/g-l.json", - "c/g-l.json", - "a/h-l.json", - "b/h-l.json", - "c/h-l.json", - "a/i-l.json", - "b/i-l.json", - "c/i-l.json", - "a/g-j.coffee", - "b/g-j.coffee", - "c/g-j.coffee", - "a/h-j.coffee", - "b/h-j.coffee", - "c/h-j.coffee", - "a/i-j.coffee", - "b/i-j.coffee", - "c/i-j.coffee", - "a/g-k.coffee", - "b/g-k.coffee", - "c/g-k.coffee", - "a/h-k.coffee", - "b/h-k.coffee", - "c/h-k.coffee", - "a/i-k.coffee", - "b/i-k.coffee", - "c/i-k.coffee", - "a/g-l.coffee", - "b/g-l.coffee", - "c/g-l.coffee", - "a/h-l.coffee", - "b/h-l.coffee", - "c/h-l.coffee", - "a/i-l.coffee", - "b/i-l.coffee", - "c/i-l.coffee" + "a/g-1.txt", + "b/g-1.txt", + "c/g-1.txt", + "a/h-1.txt", + "b/h-1.txt", + "c/h-1.txt", + "a/i-1.txt", + "b/i-1.txt", + "c/i-1.txt", + "a/g-200.txt", + "b/g-200.txt", + "c/g-200.txt", + "a/h-200.txt", + "b/h-200.txt", + "c/h-200.txt", + "a/i-200.txt", + "b/i-200.txt", + "c/i-200.txt", + "a/g-3000.txt", + "b/g-3000.txt", + "c/g-3000.txt", + "a/h-3000.txt", + "b/h-3000.txt", + "c/h-3000.txt", + "a/i-3000.txt", + "b/i-3000.txt", + "c/i-3000.txt", + "a/g-1.js", + "b/g-1.js", + "c/g-1.js", + "a/h-1.js", + "b/h-1.js", + "c/h-1.js", + "a/i-1.js", + "b/i-1.js", + "c/i-1.js", + "a/g-200.js", + "b/g-200.js", + "c/g-200.js", + "a/h-200.js", + "b/h-200.js", + "c/h-200.js", + "a/i-200.js", + "b/i-200.js", + "c/i-200.js", + "a/g-3000.js", + "b/g-3000.js", + "c/g-3000.js", + "a/h-3000.js", + "b/h-3000.js", + "c/h-3000.js", + "a/i-3000.js", + "b/i-3000.js", + "c/i-3000.js", + "a/g-1.md", + "b/g-1.md", + "c/g-1.md", + "a/h-1.md", + "b/h-1.md", + "c/h-1.md", + "a/i-1.md", + "b/i-1.md", + "c/i-1.md", + "a/g-200.md", + "b/g-200.md", + "c/g-200.md", + "a/h-200.md", + "b/h-200.md", + "c/h-200.md", + "a/i-200.md", + "b/i-200.md", + "c/i-200.md", + "a/g-3000.md", + "b/g-3000.md", + "c/g-3000.md", + "a/h-3000.md", + "b/h-3000.md", + "c/h-3000.md", + "a/i-3000.md", + "b/i-3000.md", + "c/i-3000.md", + "a/g-1.hbs", + "b/g-1.hbs", + "c/g-1.hbs", + "a/h-1.hbs", + "b/h-1.hbs", + "c/h-1.hbs", + "a/i-1.hbs", + "b/i-1.hbs", + "c/i-1.hbs", + "a/g-200.hbs", + "b/g-200.hbs", + "c/g-200.hbs", + "a/h-200.hbs", + "b/h-200.hbs", + "c/h-200.hbs", + "a/i-200.hbs", + "b/i-200.hbs", + "c/i-200.hbs", + "a/g-3000.hbs", + "b/g-3000.hbs", + "c/g-3000.hbs", + "a/h-3000.hbs", + "b/h-3000.hbs", + "c/h-3000.hbs", + "a/i-3000.hbs", + "b/i-3000.hbs", + "c/i-3000.hbs", + "a/g-1.json", + "b/g-1.json", + "c/g-1.json", + "a/h-1.json", + "b/h-1.json", + "c/h-1.json", + "a/i-1.json", + "b/i-1.json", + "c/i-1.json", + "a/g-200.json", + "b/g-200.json", + "c/g-200.json", + "a/h-200.json", + "b/h-200.json", + "c/h-200.json", + "a/i-200.json", + "b/i-200.json", + "c/i-200.json", + "a/g-3000.json", + "b/g-3000.json", + "c/g-3000.json", + "a/h-3000.json", + "b/h-3000.json", + "c/h-3000.json", + "a/i-3000.json", + "b/i-3000.json", + "c/i-3000.json", + "a/g-1.coffee", + "b/g-1.coffee", + "c/g-1.coffee", + "a/h-1.coffee", + "b/h-1.coffee", + "c/h-1.coffee", + "a/i-1.coffee", + "b/i-1.coffee", + "c/i-1.coffee", + "a/g-200.coffee", + "b/g-200.coffee", + "c/g-200.coffee", + "a/h-200.coffee", + "b/h-200.coffee", + "c/h-200.coffee", + "a/i-200.coffee", + "b/i-200.coffee", + "c/i-200.coffee", + "a/g-3000.coffee", + "b/g-3000.coffee", + "c/g-3000.coffee", + "a/h-3000.coffee", + "b/h-3000.coffee", + "c/h-3000.coffee", + "a/i-3000.coffee", + "b/i-3000.coffee", + "c/i-3000.coffee" ], - "{a..z}/{a..z}-{a..z}.{txt,md,js}" + "{a..c}/{g..i}-{1..3000}.{md,js}" ]; \ No newline at end of file diff --git a/benchmark/fixtures/match/range.js b/benchmark/fixtures/match/braces-range.js similarity index 100% rename from benchmark/fixtures/match/range.js rename to benchmark/fixtures/match/braces-range.js diff --git a/benchmark/fixtures/match/braces.js b/benchmark/fixtures/match/braces-set.js similarity index 100% rename from benchmark/fixtures/match/braces.js rename to benchmark/fixtures/match/braces-set.js diff --git a/benchmark/fixtures/match/globstar-large-list.js b/benchmark/fixtures/match/globstar-large-list.js new file mode 100644 index 00000000..e63d8818 --- /dev/null +++ b/benchmark/fixtures/match/globstar-large-list.js @@ -0,0 +1,7925 @@ +module.exports = [ + [ + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.js", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.js", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.js", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.md", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.md", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.md", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.txt", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.txt", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.txt", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa01.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa01.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa01.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob01.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob01.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob01.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc01.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc01.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc01.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa02.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa02.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa02.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob02.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob02.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob02.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc02.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc02.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc02.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa03.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa03.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa03.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob03.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob03.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob03.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc03.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc03.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc03.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa04.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa04.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa04.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob04.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob04.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob04.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc04.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc04.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc04.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa05.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa05.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa05.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob05.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob05.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob05.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc05.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc05.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc05.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa06.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa06.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa06.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob06.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob06.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob06.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc06.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc06.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc06.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa07.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa07.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa07.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob07.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob07.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob07.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc07.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc07.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc07.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa08.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa08.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa08.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob08.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob08.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob08.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc08.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc08.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc08.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa09.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa09.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa09.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob09.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob09.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob09.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc09.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc09.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc09.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooa10.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooa10.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooa10.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/foob10.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/foob10.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/foob10.hbs", + "a/b/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/ca/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/e/d/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/da/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/cb/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/db/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/cc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/dc/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/cd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/dd/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/ce/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/de/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/cf/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/df/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/cg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/dg/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/ch/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/dh/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/ci/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/di/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/cj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/dj/f/g/foo/bar-baz-quux/h/fez/bang/klmnop/fooc10.hbs", + "a/b/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/ca/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/e/d/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/da/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/cb/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/db/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/cc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/dc/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/cd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/dd/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/ce/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/de/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/cf/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/df/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/cg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/dg/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/ch/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/dh/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/ci/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/di/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/cj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/dj/f/g/foo/bar-baz-quux/i/fez/bang/klmnop/fooc10.hbs", + "a/b/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/ca/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/e/d/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/da/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/cb/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/db/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/cc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/dc/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/cd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/dd/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/ce/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/de/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/cf/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/df/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/cg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/dg/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/ch/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/dh/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/ci/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/di/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/cj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs", + "a/dj/f/g/foo/bar-baz-quux/j/fez/bang/klmnop/fooc10.hbs" + ], + "**/fooc09.js" +]; \ No newline at end of file diff --git a/benchmark/fixtures/match/long.js b/benchmark/fixtures/match/globstar-long-list.js similarity index 100% rename from benchmark/fixtures/match/long.js rename to benchmark/fixtures/match/globstar-long-list.js diff --git a/benchmark/fixtures/match/globstar-small-list.js b/benchmark/fixtures/match/globstar-short-list.js similarity index 100% rename from benchmark/fixtures/match/globstar-small-list.js rename to benchmark/fixtures/match/globstar-short-list.js diff --git a/benchmark/fixtures/match/basename.js b/benchmark/fixtures/match/star-basename.js similarity index 100% rename from benchmark/fixtures/match/basename.js rename to benchmark/fixtures/match/star-basename.js diff --git a/benchmark/fixtures/match/immediate.js b/benchmark/fixtures/match/star.js similarity index 100% rename from benchmark/fixtures/match/immediate.js rename to benchmark/fixtures/match/star.js diff --git a/benchmark/helper.js b/benchmark/helper.js new file mode 100644 index 00000000..1b2de391 --- /dev/null +++ b/benchmark/helper.js @@ -0,0 +1,84 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var size = require('window-size'); +var repeat = require('repeat-string'); + +function bench() { + var filepath = path.join(__dirname, 'last.md'); + var str = fs.readFileSync(filepath, 'utf8'); + var sections = str.split(/(?=\n?(?:# benchmark))/); + sections.shift(); + + var len = sections.length; + var idx = -1; + var res = []; + + while (++idx < len) { + var section = sections[idx].trim(); + var tok = parseSection(section); + if (tok) res.push(tok); + } + + return res.join('\n'); +} + +function parseSection(str) { + var lines = str.split('\n').filter(Boolean); + if (!lines.length) return; + var title = lines.shift().trim(); + var m = /^.*\/fixtures\/match\/([^(]+)/.exec(title); + + var tok = {title: (m ? m[1] : title).trim()}; + tok.title = tok.title.slice(0, tok.title.length - 3); + + tok.micromatch = parseStats(lines); + tok['minimatch '] = parseStats(lines); + tok.multimatch = parseStats(lines); + var vals = values(tok); + var max = Math.max.apply(Math, vals); + + var str = ''; + str += ['#', tok.title].join(' ') + '\n'; + str += format('micromatch', tok, max, 100); + str += format('minimatch ', tok, max, 100); + str += format('multimatch', tok, max, 100); + // console.log(str) + return str; +} + +function parseStats(lines) { + var str = lines.shift().trim(); + var m = /^([^\s]+)\s*x\s*([\d,.]+)/.exec(str); + if (!m) return 0; + var str = m[2]; + var num = String(str).split(',').join(''); + return { + num: num, + str: str + }; +} + +function values(obj) { + var vals = []; + for (var key in obj) { + if (key === 'title') continue; + vals.push(obj[key].num); + } + return vals; +} + +function bar(tok, longest, diff) { + return repeat('█', (tok.num / longest) * (size.width - diff)); +} + +function format(name, tok, max, diff) { + return [name, bar(tok[name], max, diff), '(' + tok[name].str + ' ops/sec)', '\n'].join(' '); +} + +/** + * Expose `.bench` helper + */ + +module.exports.bench = bench; diff --git a/benchmark/last.md b/benchmark/last.md index 1f32b461..c363b793 100644 --- a/benchmark/last.md +++ b/benchmark/last.md @@ -1,51 +1,81 @@ -#1: basename-braces - micromatch x 26,420 ops/sec ±0.89% (91 runs sampled) - minimatch x 3,507 ops/sec ±0.64% (97 runs sampled) +Benchmarking: (10 of 10) + · braces-globstar-large-list + · braces-multiple + · braces-range + · braces-set + · globstar-large-list + · globstar-long-list + · globstar-short-list + · no-glob + · star-basename + · star -#2: basename - micromatch x 25,315 ops/sec ±0.82% (93 runs sampled) - minimatch x 4,398 ops/sec ±0.86% (94 runs sampled) +# benchmark/fixtures/match/braces-globstar-large-list.js (485691 bytes) + micromatch x 395 ops/sec ±0.54% (84 runs sampled) + minimatch x 13.75 ops/sec ±0.67% (37 runs sampled) + multimatch x 13.90 ops/sec ±0.53% (37 runs sampled) -#3: braces-no-glob - micromatch x 341,254 ops/sec ±0.78% (93 runs sampled) - minimatch x 30,197 ops/sec ±1.12% (91 runs sampled) + fastest is micromatch -#4: braces - micromatch x 54,649 ops/sec ±0.74% (94 runs sampled) - minimatch x 3,095 ops/sec ±0.82% (95 runs sampled) +# benchmark/fixtures/match/braces-multiple.js (3143 bytes) + micromatch x 35,630 ops/sec ±1.39% (88 runs sampled) + minimatch x 1.58 ops/sec ±4.05% (7 runs sampled) + multimatch x 1.47 ops/sec ±2.40% (7 runs sampled) -#5: immediate - micromatch x 16,719 ops/sec ±0.79% (95 runs sampled) - minimatch x 4,348 ops/sec ±0.86% (96 runs sampled) + fastest is micromatch -#6: large - micromatch x 721 ops/sec ±0.77% (94 runs sampled) - minimatch x 17.73 ops/sec ±1.08% (50 runs sampled) +# benchmark/fixtures/match/braces-range.js (727 bytes) + micromatch x 192,168 ops/sec ±0.33% (90 runs sampled) + minimatch x 8,167 ops/sec ±0.45% (88 runs sampled) + multimatch x 8,227 ops/sec ±1.25% (86 runs sampled) -#7: long - micromatch x 5,051 ops/sec ±0.87% (97 runs sampled) - minimatch x 628 ops/sec ±0.83% (94 runs sampled) + fastest is micromatch -#8: mid - micromatch x 51,280 ops/sec ±0.80% (95 runs sampled) - minimatch x 1,923 ops/sec ±0.84% (95 runs sampled) +# benchmark/fixtures/match/braces-set.js (2858 bytes) + micromatch x 24,648 ops/sec ±1.11% (87 runs sampled) + minimatch x 1,960 ops/sec ±1.37% (88 runs sampled) + multimatch x 1,841 ops/sec ±1.41% (87 runs sampled) -#9: multi-patterns - micromatch x 22,440 ops/sec ±0.97% (94 runs sampled) - minimatch x 2,481 ops/sec ±1.10% (94 runs sampled) + fastest is micromatch -#10: no-glob - micromatch x 722,823 ops/sec ±1.30% (87 runs sampled) - minimatch x 52,967 ops/sec ±1.09% (94 runs sampled) +# benchmark/fixtures/match/globstar-large-list.js (485686 bytes) + micromatch x 396 ops/sec ±0.47% (85 runs sampled) + minimatch x 25.49 ops/sec ±1.39% (44 runs sampled) + multimatch x 25.61 ops/sec ±0.57% (44 runs sampled) -#11: range - micromatch x 243,471 ops/sec ±0.79% (94 runs sampled) - minimatch x 11,736 ops/sec ±0.82% (96 runs sampled) + fastest is micromatch -#12: shallow - micromatch x 190,874 ops/sec ±0.98% (95 runs sampled) - minimatch x 21,699 ops/sec ±0.81% (97 runs sampled) +# benchmark/fixtures/match/globstar-long-list.js (90647 bytes) + micromatch x 3,337 ops/sec ±0.73% (89 runs sampled) + minimatch x 504 ops/sec ±0.91% (87 runs sampled) + multimatch x 493 ops/sec ±1.23% (86 runs sampled) -#13: short - micromatch x 496,393 ops/sec ±3.86% (90 runs sampled) - minimatch x 53,765 ops/sec ±0.75% (95 runs sampled) + fastest is micromatch + +# benchmark/fixtures/match/globstar-short-list.js (182 bytes) + micromatch x 465,408 ops/sec ±1.51% (88 runs sampled) + minimatch x 32,763 ops/sec ±1.52% (88 runs sampled) + multimatch x 28,196 ops/sec ±0.92% (88 runs sampled) + + fastest is micromatch + +# benchmark/fixtures/match/no-glob.js (701 bytes) + micromatch x 642,909 ops/sec ±1.13% (88 runs sampled) + minimatch x 33,682 ops/sec ±1.29% (85 runs sampled) + multimatch x 29,675 ops/sec ±1.41% (88 runs sampled) + + fastest is micromatch + +# benchmark/fixtures/match/star-basename.js (12339 bytes) + micromatch x 11,012 ops/sec ±0.47% (87 runs sampled) + minimatch x 3,076 ops/sec ±1.71% (85 runs sampled) + multimatch x 3,001 ops/sec ±1.59% (89 runs sampled) + + fastest is micromatch + +# benchmark/fixtures/match/star.js (12338 bytes) + micromatch x 9,786 ops/sec ±0.58% (87 runs sampled) + minimatch x 2,976 ops/sec ±1.58% (87 runs sampled) + multimatch x 2,791 ops/sec ±1.17% (88 runs sampled) + + fastest is micromatch diff --git a/benchmark/package.json b/benchmark/package.json index faac8343..735754cc 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -8,13 +8,13 @@ }, "devDependencies": { "ansi-cyan": "^0.1.1", - "benchmarked": "^0.2.2", - "braces": "^1.8.5", + "benchmarked": "^0.2.5", + "braces": "^2.0.2", "is-object": "^1.0.1", "is-primitive": "^2.0.0", - "minimatch": "^3.0.0", + "minimatch": "^3.0.3", "multimatch": "^2.1.0", "write": "^0.3.2", - "yargs-parser": "^3.2.0" + "yargs-parser": "^4.0.2" } } diff --git a/index.js b/index.js index 398de58f..5e41511f 100644 --- a/index.js +++ b/index.js @@ -12,25 +12,26 @@ var extend = require('extend-shallow'); * Local dependencies */ -var Micromatch = require('./lib/micromatch'); var compilers = require('./lib/compilers'); var parsers = require('./lib/parsers'); -var cache = require('./lib/cache'); var utils = require('./lib/utils'); var MAX_LENGTH = 1024 * 64; +var cache = {}; /** * The main function takes a list of strings and one or more * glob patterns to use for matching. * * ```js - * var micromatch = require('micromatch'); - * console.log(micromatch(['a.js', 'a.txt'], ['*.js'])); + * var mm = require('micromatch'); + * mm(list, patterns[, options]); + * + * console.log(mm(['a.js', 'a.txt'], ['*.js'])); * //=> [ 'a.js' ] * ``` - * @param {Array} `list` - * @param {String|Array} `patterns` Glob patterns - * @param {Object} `options` + * @param {Array} `list` A list of strings to match + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` Any [options](#options) to change how matches are performed * @return {Array} Returns an array of matches * @api public */ @@ -90,20 +91,22 @@ micromatch.clearCache = function() { * Similar to the main function, but `pattern` must be a string. * * ```js - * var micromatch = require('micromatch'); - * console.log(micromatch.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); + * var mm = require('micromatch'); + * mm.match(list, pattern[, options]); + * + * console.log(mm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); * //=> ['a.a', 'a.aa'] * ``` * @param {Array} `list` Array of strings to match - * @param {String} `pattern` Glob pattern - * @param {Object} `options` + * @param {String} `pattern` Glob pattern to use for matching. + * @param {Object} `options` Any [options](#options) to change how matches are performed * @return {Array} Returns an array of matches * @api public */ micromatch.match = function(list, pattern, options) { var unixify = utils.unixify(options); - var isMatch = micromatch.matcher(pattern, options); + var isMatch = memoize('isMatch', pattern, options, micromatch.matcher); list = utils.arrayify(list); var len = list.length; @@ -150,15 +153,17 @@ micromatch.match = function(list, pattern, options) { * Returns true if the specified `string` matches the given glob `pattern`. * * ```js - * var micromatch = require('micromatch'); - * console.log(micromatch.isMatch('a.a', '*.a')); + * var mm = require('micromatch'); + * mm.isMatch(string, pattern[, options]); + * + * console.log(mm.isMatch('a.a', '*.a')); * //=> true - * console.log(micromatch.isMatch('a.b', '*.a')); + * console.log(mm.isMatch('a.b', '*.a')); * //=> false * ``` * @param {String} `string` String to match - * @param {String} `pattern` Glob pattern - * @param {String} `options` + * @param {String} `pattern` Glob pattern to use for matching. + * @param {Object} `options` Any [options](#options) to change how matches are performed * @return {Boolean} Returns true if the string matches the glob pattern. * @api public */ @@ -172,21 +177,24 @@ micromatch.isMatch = function(str, pattern, options) { return str === pattern; } - return micromatch.matcher(pattern, options)(str); + var isMatch = memoize('isMatch', pattern, options, micromatch.matcher); + return isMatch(str); }; /** - * Returns a list of strings that do _not_ match any of the given `patterns`. + * Returns a list of strings that _DO NOT MATCH_ any of the given `patterns`. * * ```js - * var micromatch = require('micromatch'); - * console.log(micromatch.not(['a.a', 'b.b', 'c.c'], '*.a')); + * var mm = require('micromatch'); + * mm.not(list, patterns[, options]); + * + * console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); * //=> ['b.b', 'c.c'] * ``` * @param {Array} `list` Array of strings to match. - * @param {String} `pattern` One or more glob patterns. - * @param {Object} `options` - * @return {Array} Returns an array of strings that do not match the given patterns. + * @param {String|Array} `patterns` One or more glob pattern to use for matching. + * @param {Object} `options` Any [options](#options) to change how matches are performed + * @return {Array} Returns an array of strings that **do not match** the given patterns. * @api public */ @@ -212,23 +220,22 @@ micromatch.not = function(list, patterns, options) { * Returns true if the given `string` matches any of the given glob `patterns`. * * ```js - * var micromatch = require('micromatch'); - * console.log(micromatch.any('a.a', ['b.*', '*.a'])); + * var mm = require('micromatch'); + * mm.any(string, patterns[, options]); + * + * console.log(mm.any('a.a', ['b.*', '*.a'])); * //=> true - * console.log(micromatch.any('a.a', 'b.*')); + * console.log(mm.any('a.a', 'b.*')); * //=> false * ``` * @param {String} `str` The string to test. - * @param {String|Array} `patterns` Glob patterns to use. - * @param {Object} `options` Options to pass to the `matcher()` function. + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` Any [options](#options) to change how matches are performed * @return {Boolean} Returns true if any patterns match `str` * @api public */ micromatch.any = function(str, patterns, options) { - var unixify = utils.unixify(options); - str = unixify(str); - patterns = utils.arrayify(patterns); for (var i = 0; i < patterns.length; i++) { if (micromatch.isMatch(str, patterns[i], options)) { @@ -239,19 +246,21 @@ micromatch.any = function(str, patterns, options) { }; /** - * Returns true if the given `string` contains the given pattern. Similar to `.isMatch` but - * the pattern can match any part of the string. + * Returns true if the given `string` contains the given pattern. Similar + * to [.isMatch](#isMatch) but the pattern can match any part of the string. * * ```js - * var micromatch = require('micromatch'); - * console.log(micromatch.contains('aa/bb/cc', '*b')); + * var mm = require('micromatch'); + * mm.contains(string, pattern[, options]); + * + * console.log(mm.contains('aa/bb/cc', '*b')); * //=> true - * console.log(micromatch.contains('aa/bb/cc', '*d')); + * console.log(mm.contains('aa/bb/cc', '*d')); * //=> false * ``` * @param {String} `str` The string to match. * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` + * @param {Object} `options` Any [options](#options) to change how matches are performed * @return {Boolean} Returns true if the patter matches any part of `str`. * @api public */ @@ -265,9 +274,10 @@ micromatch.contains = function(str, pattern, options) { return str === pattern; } - var opts = extend({}, options, {contains: true}); + var opts = extend({}, options); opts.strictClose = false; opts.strictOpen = false; + opts.contains = true; return micromatch(str, pattern, opts).length > 0; }; @@ -276,6 +286,7 @@ micromatch.contains = function(str, pattern, options) { * Returns true if the given pattern and options should enable * the `matchBase` option. * @return {Boolean} + * @api private */ micromatch.matchBase = function(pattern, options) { @@ -289,13 +300,16 @@ micromatch.matchBase = function(pattern, options) { * use [glob-object][] instead. * * ```js - * var micromatch = require('micromatch'); + * var mm = require('micromatch'); + * mm.matchKeys(object, patterns[, options]); + * * var obj = { aa: 'a', ab: 'b', ac: 'c' }; - * console.log(micromatch.matchKeys(obj, '*b')); + * console.log(mm.matchKeys(obj, '*b')); * //=> { ab: 'b' } * ``` - * @param {Object} `object` - * @param {Array|String} `patterns` One or more glob patterns. + * @param {Object} `object` The object with keys to filter. + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` Any [options](#options) to change how matches are performed * @return {Object} Returns an object with only keys that match the given patterns. * @api public */ @@ -309,20 +323,22 @@ micromatch.matchKeys = function(obj, patterns, options) { }; /** - * Creates a matcher function from the given glob `pattern` and `options`. The returned - * function takes a string to match as its only argument. + * Returns a memoized matcher function from the given glob `pattern` and `options`. + * The returned function takes a string to match as its only argument and returns + * true if the string is a match. * * ```js - * var micromatch = require('micromatch'); - * var isMatch = micromatch.matcher('*.!(*a)'); + * var mm = require('micromatch'); + * mm.matcher(pattern[, options]); * + * var isMatch = mm.matcher('*.!(*a)'); * console.log(isMatch('a.a')); * //=> false * console.log(isMatch('a.b')); * //=> true * ``` * @param {String} `pattern` Glob pattern - * @param {String} `options` + * @param {Object} `options` Any [options](#options) to change how matches are performed. * @return {Function} Returns a matcher function. * @api public */ @@ -372,12 +388,14 @@ micromatch.matcher = function(pattern, options) { * Create a regular expression from the given glob `pattern`. * * ```js - * var micromatch = require('micromatch'); - * console.log(micromatch.makeRe('*.js')); + * var mm = require('micromatch'); + * mm.makeRe(pattern[, options]); + * + * console.log(mm.makeRe('*.js')); * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ * ``` - * @param {String} `pattern` The pattern to convert to regex. - * @param {Object} `options` + * @param {String} `pattern` A glob pattern to convert to regex. + * @param {Object} `options` Any [options](#options) to change how matches are performed. * @return {RegExp} Returns a regex created from the given pattern. * @api public */ @@ -396,21 +414,16 @@ micromatch.makeRe = function(pattern, options) { } function makeRe() { - var opts = extend({strictErrors: false}, options); - if (opts.strictErrors === true) opts.strict = true; - - var patterns = micromatch.create(pattern, opts).map(function(obj) { - return obj.output; - }); - return toRegex(patterns.join('|'), opts); - } + var patterns = micromatch + .create(pattern, options) + .map(function(obj) { + return obj.output; + }); - var regex = memoize('makeRe', pattern, options, makeRe); - if (regex.source.length > MAX_LENGTH) { - throw new SyntaxError('potentially malicious regex detected'); + return toRegex(patterns.join('|'), options); } - return regex; + return memoize('makeRe', pattern, options, makeRe); }; /** @@ -424,22 +437,24 @@ micromatch.makeRe = function(pattern, options) { * console.log(micromatch.braces('foo/{a,b}/bar', {expand: true})); * //=> ['foo/(a|b)/bar'] * ``` - * @param {String} pattern - * @param {Object} options + * @param {String} `pattern` String with brace pattern to expand. + * @param {Object} `options` Any [options](#options) to change how expansion is performed. See the [braces][] library for all available options. * @return {Array} * @api public */ micromatch.braces = function(pattern, options) { - return memoize('braces', pattern, options, function() { - if (options && options.nobrace === true) { - return [pattern]; - } - if (!/\{.*\}/.test(pattern)) { - return [pattern]; - } + if (typeof pattern !== 'string') { + throw new TypeError('expected a string'); + } + + function expand() { + if (options && options.nobrace === true) return [pattern]; + if (!/\{.*\}/.test(pattern)) return [pattern]; return braces(pattern, options); - }); + } + + return memoize('braces', pattern, options, expand); }; /** @@ -447,8 +462,10 @@ micromatch.braces = function(pattern, options) { * and optional source `map`. * * ```js - * var micromatch = require('micromatch'); - * console.log(micromatch.create('abc/*.js')); + * var mm = require('micromatch'); + * mm.create(pattern[, options]); + * + * console.log(mm.create('abc/*.js')); * // { options: { source: 'string', sourcemap: true }, * // state: {}, * // compilers: @@ -473,18 +490,16 @@ micromatch.braces = function(pattern, options) { * // files: {}, * // idx: 6 } * ``` - * @param {String} `pattern` Glob pattern - * @param {Object} `options` + * @param {String} `pattern` Glob pattern to parse and compile. + * @param {Object} `options` Any [options](#options) to change how parsing and compiling is performed. * @return {Object} Returns an object with the parsed AST, compiled string and optional source map. * @api public */ micromatch.create = function(pattern, options) { return memoize('create', pattern, options, function() { - function compile(str, opts) { - var mm = new Micromatch(opts); - var ast = mm.parse(str, opts); - return mm.compile(ast, opts); + function create(str, opts) { + return micromatch.compile(micromatch.parse(str, opts), opts); } if (pattern.slice(0, 2) === './') { @@ -500,33 +515,129 @@ micromatch.create = function(pattern, options) { var res = []; while (++idx < len) { - res.push(compile(pattern[idx], options)); + res.push(create(pattern[idx], options)); } return res; } - return compile(pattern, options); + return create(pattern, options); }); }; /** - * Memoize a generated regex or function + * Parse the given `str` with the given `options`. + * + * ```js + * var mm = require('micromatch'); + * mm.parse(pattern[, options]); + * + * var ast = mm.parse('a/{b,c}/d'); + * console.log(ast); + * // { type: 'root', + * // errors: [], + * // input: 'a/{b,c}/d', + * // nodes: + * // [ { type: 'bos', val: '' }, + * // { type: 'text', val: 'a/' }, + * // { type: 'brace', + * // nodes: + * // [ { type: 'brace.open', val: '{' }, + * // { type: 'text', val: 'b,c' }, + * // { type: 'brace.close', val: '}' } ] }, + * // { type: 'text', val: '/d' }, + * // { type: 'eos', val: '' } ] } + * ``` + * @param {String} `str` + * @param {Object} `options` + * @return {Object} Returns an AST + * @api public */ -function memoize(type, pattern, options, fn) { - var key = utils.createKey(type + pattern, options); +micromatch.parse = function(pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected a string'); + } + + function parse() { + var snapdragon = utils.instantiate(null, options); + parsers(snapdragon, options); + + if (pattern.slice(0, 2) === './') { + pattern = pattern.slice(2); + } - if (cache.has(type, key)) { - return cache.get(type, key); + pattern = utils.combineDuplicates(pattern, '\\*\\*\\/|\\/\\*\\*'); + var ast = snapdragon.parse(pattern, options); + utils.define(ast, 'snapdragon', snapdragon); + ast.input = pattern; + return ast; } - var val = fn(pattern, options); + return memoize('parse', pattern, options, parse); +}; + +/** + * Compile the given `ast` or string with the given `options`. + * + * ```js + * var micromatch = require('micromatch'); + * mm.compile(ast[, options]); + * + * var ast = micromatch.parse('a/{b,c}/d'); + * console.log(micromatch.compile(ast)); + * // { options: { source: 'string' }, + * // state: {}, + * // compilers: + * // { eos: [Function], + * // noop: [Function], + * // bos: [Function], + * // brace: [Function], + * // 'brace.open': [Function], + * // text: [Function], + * // 'brace.close': [Function] }, + * // output: [ 'a/(b|c)/d' ], + * // ast: + * // { ... }, + * // parsingErrors: [] } + * ``` + * @param {Object|String} `ast` + * @param {Object} `options` + * @return {Object} Returns an object that has an `output` property with the compiled string. + * @api public + */ + +micromatch.compile = function(ast, options) { + if (typeof ast === 'string') { + ast = micromatch.parse(ast, options); + } + + function compile() { + var snapdragon = utils.instantiate(ast, options); + compilers(snapdragon, options); + return snapdragon.compile(ast, options); + } + + return memoize('compile', ast.input, options, compile); +}; + +/** + * Memoize a generated regex or function. A unique key + * from the `type` (usually method name), the `pattern`, and + * user-defined options. + */ + +function memoize(type, pattern, options, fn) { + var key = utils.createKey(type + '=' + pattern, options); + if (options && options.cache === false) { - return val; + return fn(pattern, options); + } + + if (cache.hasOwnProperty(key)) { + return cache[key]; } - cache.set(type, key, val); - return val; + return (cache[key] = fn(pattern, options)); } /** diff --git a/lib/compilers.js b/lib/compilers.js index 7ff4ae8e..c9b38b44 100644 --- a/lib/compilers.js +++ b/lib/compilers.js @@ -32,5 +32,5 @@ module.exports = function(micromatch) { this.output += '\\/?'; } return this.emit(node.val, node); - }) + }); }; diff --git a/lib/micromatch.js b/lib/micromatch.js deleted file mode 100644 index b0e68bcc..00000000 --- a/lib/micromatch.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; - -/** - * Module dependencies - */ - -var debug = require('debug')('micromatch'); -var Snapdragon = require('snapdragon'); -var define = require('define-property'); -var extend = require('extend-shallow'); - -/** - * Local dependencies - */ - -var compilers = require('./compilers'); -var parsers = require('./parsers'); - -/** - * Customize Snapdragon parser and renderer - */ - -function Micromatch(options) { - debug('initializing from <%s>', __filename); - this.options = extend({}, options); - this.snapdragon = this.options.snapdragon || new Snapdragon(this.options); - this.compiler = this.snapdragon.compiler; - this.parser = this.snapdragon.parser; - - /** - * Override Snapdragon `.parse` method - */ - - define(this.snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - parsed.input = str; - - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strictErrors !== true) { - var open = last.nodes[0]; - var inner = last.nodes[1]; - if (last.type === 'bracket') { - if (inner.val.charAt(0) === '[') { - inner.val = '\\' + inner.val; - } - - } else { - open.val = '\\' + open.val; - var sibling = open.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } - } - } - - // add non-enumerable parser reference - define(parsed, 'parser', this.parser); - return parsed; - }); -} - -/** - * Initialize defaults - */ - -Micromatch.prototype.init = function() { - if (!this.isInitialized) { - this.isInitialized = true; - compilers(this.snapdragon); - parsers(this.snapdragon); - } -}; - -/** -* Decorate `.parse` method -*/ - -Micromatch.prototype.parse = function(ast, options) { - this.init(); - return this.snapdragon.parse.apply(this.snapdragon, arguments); -}; - -/** -* Decorate `.compile` method -*/ - -Micromatch.prototype.compile = function(ast, options) { - this.init(); - return this.snapdragon.compile.apply(this.snapdragon, arguments); -}; - -/** - * Expose `Micromatch` - */ - -module.exports = Micromatch; diff --git a/lib/utils.js b/lib/utils.js index c62194a4..36b380a1 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,20 +1,68 @@ 'use strict'; +var utils = module.exports; var path = require('path'); var cache = {}; /** - * Utils + * Module dependencies */ -exports.define = require('define-property'); -exports.diff = require('arr-diff'); -exports.extend = require('extend-shallow'); -exports.isGlob = require('is-glob'); -exports.typeOf = require('kind-of'); -exports.pick = require('object.pick'); -exports.union = require('arr-union'); -exports.unique = require('array-unique'); +var Snapdragon = require('snapdragon'); +utils.define = require('define-property'); +utils.diff = require('arr-diff'); +utils.extend = require('extend-shallow'); +utils.typeOf = require('kind-of'); +utils.pick = require('object.pick'); +utils.unique = require('array-unique'); + +/** + * Get the `Snapdragon` instance to use + */ + +utils.instantiate = function(ast, options) { + var snapdragon; + // if an instance was created by `.parse`, use that instance + if (utils.typeOf(ast) === 'object' && ast.snapdragon) { + snapdragon = ast.snapdragon; + // if the user supplies an instance on options, use that instance + } else if (utils.typeOf(options) === 'object' && options.snapdragon) { + snapdragon = options.snapdragon; + // create a new instance + } else { + snapdragon = new Snapdragon(options); + } + + utils.define(snapdragon, 'parse', function(str, options) { + var parsed = Snapdragon.prototype.parse.apply(this, arguments); + parsed.input = str; + + // escape unmatched brace/bracket/parens + var last = this.parser.stack.pop(); + if (last && this.options.strictErrors !== true) { + var open = last.nodes[0]; + var inner = last.nodes[1]; + if (last.type === 'bracket') { + if (inner.val.charAt(0) === '[') { + inner.val = '\\' + inner.val; + } + + } else { + open.val = '\\' + open.val; + var sibling = open.parent.nodes[1]; + if (sibling.type === 'star') { + sibling.loose = true; + } + } + } + + // add non-enumerable parser reference + utils.define(parsed, 'parser', this.parser); + return parsed; + }); + + return snapdragon; +}; /** * Create the key to use for memoization. The key is generated @@ -22,7 +70,7 @@ exports.unique = require('array-unique'); * to the pattern string. */ -exports.createKey = function(pattern, options) { +utils.createKey = function(pattern, options) { var key = pattern; if (typeof options === 'undefined') { return key; @@ -40,7 +88,7 @@ exports.createKey = function(pattern, options) { * @return {Array} */ -exports.arrayify = function(val) { +utils.arrayify = function(val) { if (typeof val === 'string') return [val]; return val ? (Array.isArray(val) ? val : [val]) : []; }; @@ -49,7 +97,7 @@ exports.arrayify = function(val) { * Return true if `val` is a non-empty string */ -exports.isString = function(val) { +utils.isString = function(val) { return typeof val === 'string'; }; @@ -57,23 +105,23 @@ exports.isString = function(val) { * Return true if `val` is a non-empty string */ -exports.isRegex = function(val) { - return exports.typeOf(val) === 'regexp'; +utils.isRegex = function(val) { + return utils.typeOf(val) === 'regexp'; }; /** * Return true if `val` is a non-empty string */ -exports.isObject = function(val) { - return exports.typeOf(val) === 'object'; +utils.isObject = function(val) { + return utils.typeOf(val) === 'object'; }; /** * Escape regex characters in the given string */ -exports.escapeRegex = function(str) { +utils.escapeRegex = function(str) { return str.replace(/[\-\[\]{}()^$|\s*+?.\\\/]/g, '\\$&'); }; @@ -83,7 +131,7 @@ exports.escapeRegex = function(str) { * @returns {String} */ -exports.combineDuplicates = function(str, val) { +utils.combineDuplicates = function(str, val) { if (typeof val === 'string') { var re = new RegExp('(' + val + ')(?=(?:' + val + ')*\\1)', 'g'); return str.replace(re, ''); @@ -95,7 +143,7 @@ exports.combineDuplicates = function(str, val) { * Returns true if the given `str` has special characters */ -exports.hasSpecialChars = function(str) { +utils.hasSpecialChars = function(str) { return /(?:(^|\/)[!.]|[*?+()|\[\]{}]|[+@]\()/.test(str); }; @@ -106,8 +154,8 @@ exports.hasSpecialChars = function(str) { * @return {String} */ -exports.unescape = function(str) { - return exports.normalize(str.replace(/\\(\W)/g, '$1')); +utils.unescape = function(str) { + return utils.normalize(str.replace(/\\(\W)/g, '$1')); }; /** @@ -117,7 +165,7 @@ exports.unescape = function(str) { * @return {String} */ -exports.normalize = function(filepath) { +utils.normalize = function(filepath) { return filepath.replace(/[\\\/]+(?=[\w._-])(?![*?+\\!])/g, '/'); }; @@ -128,11 +176,11 @@ exports.normalize = function(filepath) { * @return {Boolean} */ -exports.isSimpleChar = function(str) { +utils.isSimpleChar = function(str) { return str === '' || str === ' ' || str === '.'; }; -exports.isSlash = function(str) { +utils.isSlash = function(str) { return str === '/' || str === '\\' || str === '\\\\'; }; @@ -144,10 +192,10 @@ exports.isSlash = function(str) { * @return {Function} */ -exports.matchPath = function(pattern, options) { +utils.matchPath = function(pattern, options) { return (options && options.contains) - ? exports.containsPattern(pattern, options) - : exports.equalsPattern(pattern, options); + ? utils.containsPattern(pattern, options) + : utils.equalsPattern(pattern, options); }; /** @@ -158,8 +206,8 @@ exports.matchPath = function(pattern, options) { * @return {Function} */ -exports.equalsPattern = function(pattern, options) { - var unixify = exports.unixify(options); +utils.equalsPattern = function(pattern, options) { + var unixify = utils.unixify(options); return function(filepath) { if (options && options.nocase === true) { @@ -177,8 +225,8 @@ exports.equalsPattern = function(pattern, options) { * @return {Function} */ -exports.containsPattern = function(pattern, options) { - var unixify = exports.unixify(options); +utils.containsPattern = function(pattern, options) { + var unixify = utils.unixify(options); return function(filepath) { if (options && options.nocase === true) { return unixify(filepath.toLowerCase()).indexOf(pattern) !== -1; @@ -196,7 +244,7 @@ exports.containsPattern = function(pattern, options) { * @return {Function} */ -exports.matchBasename = function(re) { +utils.matchBasename = function(re) { return function(filepath) { return re.test(filepath) || re.test(path.basename(filepath)); }; @@ -208,7 +256,7 @@ exports.matchBasename = function(re) { * @return {String} */ -exports.stripPrefix = function(fp) { +utils.stripPrefix = function(fp) { if (typeof fp !== 'string') { return fp; } @@ -225,28 +273,26 @@ exports.stripPrefix = function(fp) { * forward slashes. */ -exports.unixify = function(options) { - var key = exports.createKey('unixify', options); +utils.unixify = function(options) { + var key = utils.createKey('unixify', options); if (cache.hasOwnProperty(key) && path.sep === '/') { return cache[key]; } - var opts = exports.extend({}, options); - var unixify = function(filepath) { - return exports.stripPrefix(filepath); + return utils.stripPrefix(filepath); }; - if (path.sep !== '/' || opts.unixify === true || opts.normalize === true) { + if (path.sep !== '/' || (options && (options.unixify === true || options.normalize === true))) { unixify = function(filepath) { - return exports.stripPrefix(exports.normalize(filepath)); + return utils.stripPrefix(utils.normalize(filepath)); }; } - if (opts.unescape === true) { + if (options && options.unescape === true) { unixify = function(filepath) { - return exports.stripPrefix(exports.normalize(exports.unescape(filepath))); + return utils.stripPrefix(utils.normalize(utils.unescape(filepath))); }; } diff --git a/package.json b/package.json index 0352fc66..13a97ad7 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,7 @@ "arr-union": "^3.1.0", "array-unique": "^0.3.2", "bash-match": "^0.2.0", - "braces": "^2.0.1", - "debug": "^2.2.0", + "braces": "^2.0.2", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "extglob": "^1.0.0", @@ -46,7 +45,7 @@ "fragment-cache": "^0.2.0", "is-glob": "^3.1.0", "kind-of": "^3.0.4", - "nanomatch": "^0.3.0", + "nanomatch": "^0.3.1", "object.pick": "^1.1.2", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", @@ -61,6 +60,7 @@ "gulp-istanbul": "^1.1.1", "gulp-mocha": "^3.0.1", "gulp-unused": "^0.2.0", + "is-windows": "^0.2.0", "minimatch": "^3.0.3", "mocha": "^3.1.2", "multimatch": "^2.1.0", @@ -96,36 +96,38 @@ "wildcard" ], "verb": { + "toc": true, + "layout": "default", + "tasks": [ + "readme" + ], + "plugins": [ + "gulp-format-md" + ], + "helpers": [ + "./benchmark/helper.js" + ], "related": { "list": [ "braces", "expand-brackets", - "expand-range", "extglob", "fill-range", - "gulp-micromatch", - "is-glob", - "parse-glob" + "nanomatch" ] }, + "lint": { + "reflinks": true + }, "reflinks": [ "braces", "expand-brackets", "extglob", + "glob-object", "minimatch", "multimatch", - "verb" - ], - "toc": false, - "layout": false, - "tasks": [ - "readme" - ], - "plugins": [ - "gulp-format-md" - ], - "lint": { - "reflinks": true - } + "verb", + "verb-generate-readme" + ] } } \ No newline at end of file diff --git a/test/api.isMatch.js b/test/api.isMatch.js index 4c5c600b..fe518cfa 100644 --- a/test/api.isMatch.js +++ b/test/api.isMatch.js @@ -3,7 +3,6 @@ var assert = require('assert'); var mm = require('./support/match'); - describe('.isMatch():', function() { describe('error handling:', function() { it('should throw on bad args', function() { diff --git a/test/api.match.js b/test/api.match.js index ab9d6c19..ef749b6d 100644 --- a/test/api.match.js +++ b/test/api.match.js @@ -1,6 +1,5 @@ 'use strict'; -var assert = require('assert'); var mm = require('./support/match'); describe('.match method', function() { diff --git a/test/api.not.js b/test/api.not.js index 67956700..c133a1c0 100644 --- a/test/api.not.js +++ b/test/api.not.js @@ -2,7 +2,6 @@ var path = require('path'); var sep = path.sep; -var assert = require('assert'); var mm = require('./support/match'); describe('.not method', function() { diff --git a/test/brackets.js b/test/brackets.js index 5ee5f58f..13c86ac8 100644 --- a/test/brackets.js +++ b/test/brackets.js @@ -44,6 +44,14 @@ describe('brackets', function() { mm(fixtures, 'a[a-z]+c', ['abbbbc', 'abbbc', 'abbc', 'abc', 'axyzc']); }); + it('should match literal brackets', function() { + mm(['a [b]'], 'a \\[b\\]', ['a [b]']); + mm(['a [b] c'], 'a [b] c', ['a [b] c']); + mm(['a [b]'], 'a \\[b\\]*', ['a [b]']); + mm(['a [bc]'], 'a \\[bc\\]*', ['a [bc]']); + mm(['a [b]', 'a [b].js'], 'a \\[b\\].*', ['a [b].js']); + }); + it('should match character classes', function() { mm(['abc', 'abd'], 'a[bc]d', ['abd']); }); diff --git a/test/comparison.isMatch.js b/test/comparison.isMatch.js new file mode 100644 index 00000000..6003caf9 --- /dev/null +++ b/test/comparison.isMatch.js @@ -0,0 +1,113 @@ +'use strict'; + +var assert = require('assert'); +var bash = require('bash-match'); +var isWindows = require('is-windows'); +var mm = require('minimatch'); +var nm = require('..'); + +var fixtures = [ + // common file patterns + 'abc', + 'abd', + 'abbbz', + 'a', + 'a.md', + 'a/b/c.md', + + 'z.js', + 'za.js', + 'a/b/c/z.js', + 'a/b/c/d/e/f/z.js', + + // directories + 'a/', + 'a/b', + 'a/cb', + 'a/bb', + 'a/b/c/d', + 'a/b/c/d/', + + // cwd + '.', + './', + + // ancestor directories + '..', + '../c', + '../c', + './../c', + '/..', + '/../c', + + // bad paths + './a/../c', + '/a/../c', + 'a/../c', + + // dot files + './.b/.c', + './b/.c', + '../.b/.c', + '../b/.c', + '.b', + '.b/', + '.b', + '.b.c', + '.b.c/', + '.b/', + '.b/c', + 'b/.c', + + // dot directories + 'b/.c/', + '.b/.c', +]; + +var patterns = [ + '!**/*.md', + '!*.*', + '!*.js', + '*', + '**', + '**/', + '**/*', + '**/*.md', + '**/z*.js', + '*.js', + '*/*', + '/**', + '/**/', + '/**/*', + 'a/**/', + 'a/**/b', + 'a/**b', + 'a/b/c/**/*.js', + 'a/b/c/*.js', +]; + +describe('.isMatch', function() { + if (isWindows()) { + console.log('comparisons are done using bash, these tests cannot run on windows'); + return; + } + + patterns.forEach(function(pattern) { + fixtures.forEach(function(fixture) { + it('should match ' + fixture + ' with ' + pattern, function() { + var mmRes = mm(fixture, pattern); + var nmRes = nm.isMatch(fixture, pattern); + var bRes = bash.isMatch(fixture, pattern); + + assert(nmRes === bRes || nmRes === mmRes, fixture + ' ' + pattern); + }); + + it('should match ' + fixture + ' with ' + pattern + ' and {dot: true}', function() { + var mmRes = mm(fixture, pattern, {dot: true}); + var nmRes = nm.isMatch(fixture, pattern, {dot: true}); + var bRes = bash.isMatch(fixture, pattern, {dot: true}); + assert(nmRes === bRes || nmRes === mmRes, fixture + ' ' + pattern); + }); + }); + }); +}); diff --git a/test/comparison.makeRe.js b/test/comparison.makeRe.js new file mode 100644 index 00000000..5c6b7cc2 --- /dev/null +++ b/test/comparison.makeRe.js @@ -0,0 +1,113 @@ +'use strict'; + +var assert = require('assert'); +var isWindows = require('is-windows'); +var bash = require('bash-match'); +var mm = require('minimatch'); +var nm = require('..'); + +var fixtures = [ + // common file patterns + 'abc', + 'abd', + 'abbbz', + 'a', + 'a.md', + 'a/b/c.md', + + 'z.js', + 'za.js', + 'a/b/c/z.js', + 'a/b/c/d/e/f/z.js', + + // directories + 'a/', + 'a/b', + 'a/cb', + 'a/bb', + 'a/b/c/d', + 'a/b/c/d/', + + // cwd + '.', + './', + + // ancestor directories + '..', + '../c', + '../c', + './../c', + '/..', + '/../c', + + // bad paths + './a/../c', + '/a/../c', + 'a/../c', + + // dot files + './.b/.c', + './b/.c', + '../.b/.c', + '../b/.c', + '.b', + '.b/', + '.b', + '.b.c', + '.b.c/', + '.b/', + '.b/c', + 'b/.c', + + // dot directories + 'b/.c/', + '.b/.c', +]; + +var patterns = [ + '!**/*.md', + '!*.*', + '!*.js', + '*', + '**', + '**/', + '**/*', + '**/*.md', + '**/z*.js', + '*.js', + '*/*', + '/**', + '/**/', + '/**/*', + 'a/**/', + 'a/**/b', + 'a/**b', + 'a/b/c/**/*.js', + 'a/b/c/*.js', +]; + +describe('.makeRe', function() { + if (isWindows()) { + console.log('comparisons are done using bash, these tests cannot run on windows'); + return; + } + + patterns.forEach(function(pattern) { + fixtures.forEach(function(fixture) { + it('should match ' + fixture + ' with ' + pattern, function() { + var mmRes = mm(fixture, pattern); + var nmRes = nm.makeRe(pattern).test(fixture); + var bRes = bash.isMatch(fixture, pattern); + + assert(nmRes === bRes || nmRes === mmRes, fixture + ' ' + pattern); + }); + + it('should match ' + fixture + ' with ' + pattern + ' and {dot: true}', function() { + var mmRes = mm(fixture, pattern, {dot: true}); + var nmRes = nm.makeRe(pattern, {dot: true}).test(fixture); + var bRes = bash.isMatch(fixture, pattern, {dot: true}); + assert(nmRes === bRes || nmRes === mmRes, fixture + ' ' + pattern); + }); + }); + }); +}); diff --git a/test/integration.js b/test/integration.js index 88c6f46a..f0d773c4 100644 --- a/test/integration.js +++ b/test/integration.js @@ -1,6 +1,5 @@ 'use strict'; -var assert = require('assert'); var mm = require('./support/match'); describe('globstars', function() { diff --git a/test/options.js b/test/options.js index 9e1b4102..88b21325 100644 --- a/test/options.js +++ b/test/options.js @@ -8,7 +8,7 @@ var mm = require('./support/match'); describe('options', function() { describe('options.ignore', function() { var negations = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c', 'a/d', 'a/e']; - var globs = ['a', 'a/a', 'a/a/a', 'a/a/a/a', 'a/a/a/a/a', 'a/a/b', 'a/b', 'a/b/c', 'a/c', 'a/x', 'b', 'b/b/b', 'b/b/c', 'c/c/c', 'e/f/g', 'h/i/a', 'x/x/x', 'x/y', 'z/z', 'z/z/z']; + var globs = ['a', 'a/a', 'a/a/a', 'a/a/a/a', '.a', 'a/.a', '.a/a', '.a/a/a', 'a/a/.a', '.a/a/a/a', 'a/a/a/a/a', 'a/a/b', 'a/b', 'a/b/c', 'a/c', 'a/x', 'b', 'b/b/b', 'b/b/c', 'c/c/c', 'e/f/g', 'h/i/a', 'x/x/x', 'x/y', 'z/z', 'z/z/z']; it('should filter out ignored patterns', function() { var opts = {ignore: ['a/**']}; @@ -21,6 +21,16 @@ describe('options', function() { mm(globs, '*/*/*/*/*', [], opts); mm(globs, 'a/*', [], opts); mm(globs, '**/*/x', ['x/x/x'], opts); + mm(globs, '**/*/[b-z]', ['b/b/b', 'b/b/c', 'c/c/c', 'e/f/g', 'x/x/x', 'x/y', 'z/z', 'z/z/z'], opts); + + mm(globs, '*', ['a', '.a', 'b'], {ignore: 'a/**', dot: true}); + mm(globs, '*', ['b', '.a'], {ignore: '**/a', dot: true}); + mm(globs, '*/*', ['.a/a', 'x/y', 'z/z'], {ignore: 'a/**', dot: true}); + mm(globs, '*/*/*', ['.a/a/a', 'b/b/b', 'b/b/c', 'c/c/c', 'e/f/g', 'h/i/a', 'x/x/x', 'z/z/z'], {ignore: 'a/**', dot: true}); + mm(globs, '*/*/*/*', ['.a/a/a/a'], {ignore: 'a/**', dot: true}); + mm(globs, '*/*/*/*/*', [], {ignore: 'a/**', dot: true}); + mm(globs, 'a/*', [], {ignore: 'a/**', dot: true}); + mm(globs, '**/*/x', ['x/x/x'], {ignore: 'a/**', dot: true}); mm(negations, '!b/a', ['b/b', 'b/c'], opts); mm(negations, '!b/(a)', ['b/b', 'b/c'], opts); @@ -141,7 +151,7 @@ describe('options', function() { describe('options.nonegate', function() { it('should support the `nonegate` option:', function() { mm(['a/a/a', 'a/b/a', 'b/b/a', 'c/c/a', 'c/c/b'], '!**/a', ['c/c/b']); - mm(['.dotfile.txt', 'a/b/.dotfile'], '!*.md', [], {nonegate: true}); + mm(['a.md', '!a.md', 'a.txt'], '!*.md', ['!a.md'], {nonegate: true}); mm(['!a/a/a', 'a/b/a', 'b/b/a', '!c/c/a'], '!**/a', ['!a/a/a', '!c/c/a'], {nonegate: true}); mm(['!*.md', '.dotfile.txt', 'a/b/.dotfile'], '!*.md', ['!*.md'], {nonegate: true}); }); diff --git a/test/regex.ranges.js b/test/regex-ranges.js similarity index 96% rename from test/regex.ranges.js rename to test/regex-ranges.js index af208648..bdc970a4 100644 --- a/test/regex.ranges.js +++ b/test/regex-ranges.js @@ -1,6 +1,5 @@ 'use strict'; -var assert = require('assert'); var mm = require('./support/match'); describe('ranges', function() { diff --git a/test/stars.js b/test/stars.js index 08dfdd39..4e4add01 100644 --- a/test/stars.js +++ b/test/stars.js @@ -1,6 +1,5 @@ 'use strict'; -var assert = require('assert'); var mm = require('./support/match'); describe('stars', function() { diff --git a/test/support/parse.js b/test/support/parse.js index 60527fd4..31a8cbcc 100644 --- a/test/support/parse.js +++ b/test/support/parse.js @@ -2,7 +2,6 @@ var fs = require('fs'); var path = require('path'); -var util = require('util'); var nm = require('../..'); function parseFiles(pattern, options) { diff --git a/test/support/patterns.js b/test/support/patterns.js index d4ab01ad..fc79aac4 100644 --- a/test/support/patterns.js +++ b/test/support/patterns.js @@ -102,5 +102,5 @@ module.exports = [ 'E:**/*.js', 'E:**/*.md', 'E:\\\\**/*.js', - 'E:\\\\**/*.md', + 'E:\\\\**/*.md' ]; From 21047558f9670e6b837393e811520f50952cfacc Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Fri, 21 Oct 2016 17:47:18 -0400 Subject: [PATCH 12/68] update docs --- .verb.md | 545 +++++-------------------------- README.md | 774 +++++++++++++++++++++++---------------------- docs/comparison.md | 130 -------- 3 files changed, 476 insertions(+), 973 deletions(-) mode change 100644 => 100755 README.md delete mode 100644 docs/comparison.md diff --git a/.verb.md b/.verb.md index aafb8c8e..0deffb83 100755 --- a/.verb.md +++ b/.verb.md @@ -1,65 +1,61 @@ -# {%= name %} {%= badge('npm') %} {%= badge('downloads') %} {%= badge('travis') %} +## Quickstart -> {%= description %} - -Micromatch supports all of the same matching features as [minimatch][] and [multimatch][]. +```js +var mm = require('micromatch'); +mm(list, patterns[, options]); +``` -* [mm()](#usage) is the same as [multimatch()][multimatch] -* [mm.match()](#match) is the same as [minimatch.match()][minimatch] -* use [mm.isMatch()](#ismatch) instead of [minimatch()][minimatch] +The [main export](#micromatch) takes a list of strings and one or more glob patterns: -## Install -{%= include("install-npm", {save: true}) %} +```js +console.log(mm(['foo', 'bar', 'qux'], ['f*', 'b*'])); // ['foo', 'bar'] +``` -## Start matching! +Use [.isMatch](#ismatch) to get true/false: ```js -var mm = require('{%= name %}'); -console.log(mm([''])) +console.log(mm.isMatch('foo', 'f*')); // true ``` -## Table of contents +**Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-minimatch) is easy**: - +* [mm()](#usage) is the same as [multimatch()][multimatch] +* [mm.match()](#match) is the same as [minimatch.match()][minimatch] +* use [mm.isMatch()](#ismatch) instead of [minimatch()][minimatch] -*** +## Why use micromatch? -### Features +> micromatch is a [drop-in replacement][switch] for minimatch and multimatch + +Micromatch is [safer][braces]{#braces-is-safe}, [faster](#benchmarks), more accurate, and supports all of the same matching features as [minimatch][] and [multimatch][]. + +Moreover, micromatch has: -+ [Drop-in replacement][switch] for [minimatch][] and [multimatch][] -+ Built-in support for multiple glob patterns, like `['foo/*.js', '!bar.js']` -+ [Brace Expansion][braces] (`foo/bar-{1..5}.md`, `one/{two,three}/four.md`) -+ Typical glob patterns, like `**/*`, `a/b/*.js`, or `['foo/*.js', '!bar.js']` -+ Methods like `.isMatch()`, `.contains()` and `.any()` +* Better support for the Bash 4.3 specification than minimatch and multimatch +* More than 3,600 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) +* Better windows support than minimatch and multimatch -**Extended globbing features:** +### Features -+ Logical `OR` (`foo/bar/(abc|xyz).js`) -+ Regex character classes (`foo/bar/baz-[1-5].js`) -+ POSIX [bracket expressions][expand-brackets] (`**/[[:alpha:][:digit:]]/`) -+ [extglobs][extglob] (`**/+(x|y)`, `!(a|b)`, etc). +* Native support for multiple glob patterns (no need for wrappers like multimatch) +* Glob pattern support (`**/*`, `a/b/*.js`, or `['a/*.js', '!b.js']`) +* [extglob][] support (`+(x|y)`, `!(a|b)`, etc) +* [POSIX character class][brackets] support (`**/[[:alpha:][:digit:]]/`) +* [brace expansion][braces] support (`a/b-{1..5}.md`, `one/{two,three}/four.md`) +* regex character classes (`a/b/baz-[1-5].js`) +* regex logical or (`a/b/(abc|xyz).js`) -You can combine these to create whatever matching patterns you need. +You can mix and match these features to create whatever patterns you need! **Example** ```js -// double-negation! -mm(['fa', 'fb', 'f', 'fo'], '!(f!(o))'); -//=> ['fo'] +mm(['a/b.js', 'a/b.md'], 'a/*.!(js)'); +//=> ['a/b.md'] ``` -## Why switch to micromatch? - -- Native support for multiple glob patterns, no need for wrappers like [multimatch][] -- [10-55x faster](#benchmarks) and more performant than [minimatch][] and [multimatch][]. This is achieved through a combination of caching and regex optimization strategies, a fundamentally different approach than minimatch. -- More extensive support for the Bash 4.3 specification -- More complete extglob support -- Extensive [unit tests](./test) (approx. 1,300 tests). Minimatch fails many of the tests. - - -### Switch from minimatch +## Switching from minimatch Use `mm.isMatch()` instead of `minimatch()`: @@ -75,7 +71,7 @@ mm.match(['foo', 'bar'], 'b*'); //=> 'bar' ``` -### Switch from multimatch +## Switching from multimatch Same signature: @@ -84,311 +80,25 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); //=> ['foo', 'baz'] ``` - -*** - - -## Usage - -Add micromatch to your node.js project: - -```js -var mm = require('{%= name %}'); -``` - -**Signature** - -```js -mm(array_of_strings, glob_patterns[, options]); -``` - -**Example** - - -```js -mm(['foo', 'bar', 'baz'], 'b*'); -//=> ['bar', 'baz'] -``` - - -### Usage examples - -**Brace expansion** - -Match files with `.js` or `.txt` extensions. - -```js -mm(['a.js', 'b.md', 'c.txt'], '*.{js,txt}'); -//=> ['a.js', 'c.txt'] -``` - -**Extglobs** - -Match anything except for files with the `.md` extension. - -```js -mm(files, '**/*.!(md)'); - -//=> ['a.js', 'c.txt'] -``` - -**Multiple patterns** - -Match using an array of patterns. - -```js -mm(['a.md', 'b.js', 'c.txt', 'd.json'], ['*.md', '*.txt']); -//=> ['a.md', 'c.txt'] -``` - -**Negation patterns:** - -Behavior is designed to be what users would expect, based on conventions that are already well-established. - -- [minimatch][] behavior is used when the pattern is a string, so patterns are **inclusive by default**. -- [multimatch][] behavior is used when an array of patterns is passed, so patterns are **exclusive by default**. - -```js -mm(['a.js', 'b.md', 'c.txt'], '!*.{js,txt}'); -//=> ['b.md'] - -mm(['a.md', 'b.js', 'c.txt', 'd.json'], ['*.*', '!*.{js,txt}']); -//=> ['a.md', 'd.json'] -``` - -*** - - -## API methods - -```js -var mm = require('micromatch'); -``` - -### .match - -```js -mm.match(array, globString); -``` - - -Return an array of files that match the given glob pattern. Useful if you only need to use a single glob pattern. - -**Example** - -```js -mm.match(['ab', 'a/b', 'bb', 'b/c'], '?b'); -//=> ['ab', 'bb'] - -mm.match(['ab', 'a/b', 'bb', 'b/c'], '*/b'); -//=> ['a/b'] -``` - -### .isMatch - -```js -mm.isMatch(filepath, globString); -``` - -Returns true if a file path matches the given glob pattern. - - -**Example** - -```js -mm.isMatch('.verb.md', '*.md'); -//=> false - -mm.isMatch('.verb.md', '*.md', {dot: true}); -//=> true -``` - -### .contains - -Returns true if any part of a file path matches the given glob pattern. Think of this is "has path" versus "is path". - -**Example** - -`.isMatch()` would return false for both of the following: - -```js -mm.contains('a/b/c', 'a/b'); -//=> true - -mm.contains('a/b/c', 'a/*'); -//=> true -``` - -### .matcher - -Returns a function for matching using the supplied pattern. e.g. create your own "matcher". The advantage of this method is that the pattern can be compiled outside of a loop. - -**Pattern** - -Can be any of the following: - -- `glob/string` -- `regex` -- `function` - -**Example** - -```js -var isMatch = mm.matcher('*.md'); -var files = []; - -['a.md', 'b.txt', 'c.md'].forEach(function(fp) { - if (isMatch(fp)) { - files.push(fp); - } -}); -``` - -### .filter - -Returns a function that can be passed to `Array#filter()`. - -**Params** - -- `patterns` **{String|Array}**: - -**Examples** - -Single glob: - -```js -var fn = mm.filter('*.md'); -['a.js', 'b.txt', 'c.md'].filter(fn); -//=> ['c.md'] - -var fn = mm.filter('[a-c]'); -['a', 'b', 'c', 'd', 'e'].filter(fn); -//=> ['a', 'b', 'c'] -``` - -Array of glob patterns: - -```js -var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; - -var fn = mm.filter(['{1..10}', '![7-9]', '!{3..4}']); -arr.filter(fn); -//=> [1, 2, 5, 6, 10] -``` - -_(Internally this function generates the matching function by using the [matcher](#matcher) method. You can use the [matcher](#matcher) method directly to create your own filter function)_ - - -### .any - -Returns true if a file path matches any of the given patterns. - -```js -mm.any(filepath, patterns, options); -``` - -**Params** - -- filepath `{String}`: The file path to test. -- patterns `{String|Array}`: One or more glob patterns -- options: `{Object}`: options to pass to the `.matcher()` method. - - -**Example** - -```js -mm.any('abc', ['!*z']); -//=> true -mm.any('abc', ['a*', 'z*']); -//=> true -mm.any('abc', 'a*'); -//=> true -mm.any('abc', ['z*']); -//=> false -``` - - -### .expand - -Returns an object with a regex-compatible string and tokens. - -```js -mm.expand('*.js'); - -// when `track` is enabled (for debugging), the `history` array is used -// to record each mutation to the glob pattern as it's converted to regex -{ options: { track: false, dot: undefined, makeRe: true, negated: false }, - pattern: '(.*\\/|^)bar\\/(?:(?!(?:^|\\/)\\.).)*?', - history: [], - tokens: - { path: - { whole: '**/bar/**', - dirname: '**/bar/', - filename: '**', - basename: '**', - extname: '', - ext: '' }, - is: - { glob: true, - negated: false, - globstar: true, - dotfile: false, - dotdir: false }, - match: {}, - original: '**/bar/**', - pattern: '**/bar/**', - base: '' } } -``` - -### .makeRe - -Create a regular expression for matching file paths based on the given pattern: - -```js -mm.makeRe('*.js'); -//=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ -``` +## API +{%= apidocs("index.js") %} ## Options -### options.unixify - -Normalize slashes in file paths and glob patterns to forward slashes. - -Type: `{Boolean}` - -Default: `undefined` on non-windows, `true` on windows. - - ### options.dot Match dotfiles. Same behavior as [minimatch]. -Type: `{Boolean}` +Type: `Boolean` Default: `false` -### options.unescape - -Unescape slashes in glob patterns. Use cautiously, especially on windows. - -Type: `{Boolean}` - -Default: `undefined` - -**Example** - -```js -mm.isMatch('abc', '\\a\\b\\c', {unescape: true}); -//=> true -``` - ### options.nodupes Remove duplicate elements from the result array. -Type: `{Boolean}` +Type: `Boolean` Default: `undefined` @@ -408,7 +118,7 @@ mm.match(['abc', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true, nodupes: true}); Allow glob patterns without slashes to match a file path based on its basename. . Same behavior as [minimatch]. -Type: `{Boolean}` +Type: `Boolean` Default: `false` @@ -422,22 +132,22 @@ mm(['a/b.js', 'a/c.md'], '*.js', {matchBase: true}); //=> ['a/b.js'] ``` -### options.nobraces +### options.nobrace -Don't expand braces in glob patterns. Same behavior as [minimatch][] `nobrace`. +Disable expansion of brace patterns. Same behavior as [minimatch][] `nobrace`. -Type: `{Boolean}` +Type: `Boolean` Default: `undefined` See [braces][] for more information about extended brace expansion. -### options.nobrackets +### options.nobracket -Don't expand POSIX bracket expressions. +Disable expansion of POSIX bracket expressions. -Type: `{Boolean}` +Type: `Boolean` Default: `undefined` @@ -446,9 +156,9 @@ See [expand-brackets][] for more information about extended bracket expressions. ### options.noextglob -Don't expand extended globs. +Disable expansion of extglobs. -Type: `{Boolean}` +Type: `Boolean` Default: `undefined` @@ -459,118 +169,60 @@ See [extglob][] for more information about extended globs. Use a case-insensitive regex for matching files. Same behavior as [minimatch][]. -Type: `{Boolean}` +Type: `Boolean` -Default: `false` +Default: `undefined` ### options.nonegate -Disallow negation (`!`) patterns. +Disallow negation (`!`) patterns, and treat leading `!` as a literal character to match. -Type: `{Boolean}` +Type: `Boolean` -Default: `false` +Default: `undefined` ### options.nonull -If `true`, when no matches are found the actual (array-ified) glob pattern is returned instead of an empty array. Same behavior as [minimatch][]. - -Type: `{Boolean}` - -Default: `false` - - -### options.cache - -Cache the platform (e.g. `win32`) to prevent this from being looked up for every filepath. - -Type: `{Boolean}` - -Default: `true` - - -*** - -## Other features - -Micromatch also supports the following. - -### Extended globbing +If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch][]. -#### extglobs - -Extended globbing, as described by the bash man page: - -| **pattern** | **regex equivalent** | **description** | -| --- | --- | --- | -| `?(pattern-list)` | `(...|...)?` | Matches zero or one occurrence of the given patterns | -| `*(pattern-list)` | `(...|...)*` | Matches zero or more occurrences of the given patterns | -| `+(pattern-list)` | `(...|...)+` | Matches one or more occurrences of the given patterns | -| `@(pattern-list)` | `(...|...)` * | Matches one of the given patterns | -| `!(pattern-list)` | N/A | Matches anything except one of the given patterns | - -* `@` isn't a RegEx character. - -Powered by [extglob][]. Visit that library for the full range of options or to report extglob related issues. - -See [extglob][] for more information about extended globs. - -#### brace expansion - -In simple cases, brace expansion appears to work the same way as the logical `OR` operator. For example, `(a|b)` will achieve the same result as `{a,b}`. - -Here are some powerful features unique to brace expansion (versus character classes): - - - range expansion: `a{1..3}b/*.js` expands to: `['a1b/*.js', 'a2b/*.js', 'a3b/*.js']` - - nesting: `a{c,{d,e}}b/*.js` expands to: `['acb/*.js', 'adb/*.js', 'aeb/*.js']` - - -Visit [braces][braces] to ask questions and create an issue related to brace-expansion, or to see the full range of features and options related to brace expansion. +Type: `Boolean` +Default: `undefined` -#### regex character classes -With the exception of brace expansion (`{a,b}`, `{1..5}`, etc), most of the special characters convert directly to regex, so you can expect them to follow the same rules and produce the same results as regex. +### options.unixify -For example, given the list: `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: +Normalize slashes in file paths and glob patterns to forward slashes. - - `[ac].js`: matches both `a` and `c`, returning `['a.js', 'c.js']` - - `[b-d].js`: matches from `b` to `d`, returning `['b.js', 'c.js', 'd.js']` - - `[b-d].js`: matches from `b` to `d`, returning `['b.js', 'c.js', 'd.js']` - - `a/[A-Z].js`: matches and uppercase letter, returning `['a/E.md']` +Type: `Boolean` -Learn about [regex character classes][character-classes]. +Default: `undefined` on non-windows, `true` on windows. -#### regex groups -Given `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: +### options.cache - - `(a|c).js`: would match either `a` or `c`, returning `['a.js', 'c.js']` - - `(b|d).js`: would match either `b` or `d`, returning `['b.js', 'd.js']` - - `(b|[A-Z]).js`: would match either `b` or an uppercase letter, returning `['b.js', 'E.js']` +Disable memoization of matching functions and generated regex. -As with regex, parenthese can be nested, so patterns like `((a|b)|c)/b` will work. But it might be easier to achieve your goal using brace expansion. +Type: `Boolean` -#### POSIX bracket expressions +Default: `undefined` -**Example** -```js -mm.isMatch('a1', '[[:alpha:][:digit:]]'); -//=> true -``` +## Notes -See [expand-brackets][] for more information about extended bracket expressions. +**Bash 4.3 parity** +Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3. Patterns that aren't described by Bash follow wildmatch spec (used by git). -*** +**Escaping** -## Notes +Backslashes are exclusively and explicitly reserved for escaping characters in a glob pattern, even on windows. This is also the case in minimatch and node-glob, although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212). -Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3. Patterns that aren't described by Bash follow wildmatch spec (used by git). +To be clear, _a glob pattern is not a filepath_. When you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting for it to work as a glob pattern. The problem is that on windows the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. But since `\\` is an escape character in globs, this means that on windows `path.join('foo', '*')` results in `foo\\*` which tells micromatch that `*` is escaped. +Thus you'll need to either do the joining manually or find a lib on npm that does this. ## Benchmarks @@ -580,59 +232,16 @@ Run the [benchmarks](./benchmark): node benchmark ``` -As of {%= date() %}: - -```bash -{%= docs("benchmark/last.md") %} -``` - -## Tests - -### Running tests -{%= include("tests") %} - -### Coverage -As of {%= date() %}: +As of {%= date() %} (longer bars are better): ```sh -Statements : 100% (441/441) -Branches : 100% (270/270) -Functions : 100% (54/54) -Lines : 100% (429/429) +{%= bench() %} ``` -## Contributing -{%= include("contributing") %} - -Please be sure to run the benchmarks before/after any code changes to judge the impact before you do a PR. thanks! - -## Related -{%= related(verb.related.list) %} - -## Contributing -{%= include("contributing") %} - -## Building docs -{%= include("build-docs") %} - -## Running tests -{%= include("tests") %} - -## Author -{%= include("author") %} - -## License -{%= copyright({linkify: true}) %} -{%= license %} - -*** - -{%= include("footer") %} - -{%= reflinks(verb.reflinks) %} - [switch]: #switch-from-minimatch [expand]: #expand [character-classes]: http://www.regular-expressions.info/charclass.html [extended]: http://mywiki.wooledge.org/BashGuide/Patterns#Extended_Globs +[brackets]: https://github.com/jonschlinkert/expand-brackets +[braces]: https://github.com/jonschlinkert/braces diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 8fb39191..1abb2dc2 --- a/README.md +++ b/README.md @@ -1,12 +1,41 @@ -# micromatch [![NPM version](https://img.shields.io/npm/v/micromatch.svg?style=flat)](https://www.npmjs.com/package/micromatch) [![NPM downloads](https://img.shields.io/npm/dm/micromatch.svg?style=flat)](https://npmjs.org/package/micromatch) [![Build Status](https://img.shields.io/travis/jonschlinkert/micromatch.svg?style=flat)](https://travis-ci.org/jonschlinkert/micromatch) +# micromatch [![NPM version](https://img.shields.io/npm/v/micromatch.svg?style=flat)](https://www.npmjs.com/package/micromatch) [![NPM monthly downloads](https://img.shields.io/npm/dm/micromatch.svg?style=flat)](https://npmjs.org/package/micromatch) [![NPM total downloads](https://img.shields.io/npm/dt/micromatch.svg?style=flat)](https://npmjs.org/package/micromatch) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/micromatch.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/micromatch) [![Windows Build Status](https://img.shields.io/appveyor/ci/jonschlinkert/micromatch.svg?style=flat&label=AppVeyor)](https://ci.appveyor.com/project/jonschlinkert/micromatch) > Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch. -Micromatch supports all of the same matching features as [minimatch](https://github.com/isaacs/minimatch) and [multimatch](https://github.com/sindresorhus/multimatch). - -* [mm()](#usage) is the same as [multimatch()](https://github.com/sindresorhus/multimatch) -* [mm.match()](#match) is the same as [minimatch.match()](https://github.com/isaacs/minimatch) -* use [mm.isMatch()](#ismatch) instead of [minimatch()](https://github.com/isaacs/minimatch) +## Table of Contents + +- [Install](#install) +- [Quickstart](#quickstart) +- [Why use micromatch?](#why-use-micromatch) + * [Features](#features) +- [Switching from minimatch](#switching-from-minimatch) +- [Switching from multimatch](#switching-from-multimatch) +- [API](#api) +- [Options](#options) + * [options.dot](#optionsdot) + * [options.nodupes](#optionsnodupes) + * [options.matchBase](#optionsmatchbase) + * [options.nobrace](#optionsnobrace) + * [options.nobracket](#optionsnobracket) + * [options.noextglob](#optionsnoextglob) + * [options.nocase](#optionsnocase) + * [options.nonegate](#optionsnonegate) + * [options.nonull](#optionsnonull) + * [options.unixify](#optionsunixify) + * [options.cache](#optionscache) +- [Notes](#notes) +- [Benchmarks](#benchmarks) +- [About](#about) + * [Related projects](#related-projects) + * [Contributing](#contributing) + * [Contributors](#contributors) + * [Release history](#release-history) + * [Building docs](#building-docs) + * [Running tests](#running-tests) + * [Author](#author) + * [License](#license) + +_(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_ ## Install @@ -16,49 +45,63 @@ Install with [npm](https://www.npmjs.com/): $ npm install --save micromatch ``` -## Start matching! +## Quickstart ```js var mm = require('micromatch'); -console.log(mm([''])) +mm(list, patterns[, options]); ``` -*** +The [main export](#micromatch) takes a list of strings and one or more glob patterns: -### Features +```js +console.log(mm(['foo', 'bar', 'qux'], ['f*', 'b*'])); // ['foo', 'bar'] +``` + +Use [.isMatch](#ismatch) to get true/false: + +```js +console.log(mm.isMatch('foo', 'f*')); // true +``` -* [Drop-in replacement](#switch-from-minimatch) for [minimatch](https://github.com/isaacs/minimatch) and [multimatch](https://github.com/sindresorhus/multimatch) -* Built-in support for multiple glob patterns, like `['foo/*.js', '!bar.js']` -* [Brace Expansion](https://github.com/jonschlinkert/braces) (`foo/bar-{1..5}.md`, `one/{two,three}/four.md`) -* Typical glob patterns, like `**/*`, `a/b/*.js`, or `['foo/*.js', '!bar.js']` -* Methods like `.isMatch()`, `.contains()` and `.any()` +**Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-minimatch) is easy**: -**Extended globbing features:** +* [mm()](#usage) is the same as [multimatch()](https://github.com/sindresorhus/multimatch) +* [mm.match()](#match) is the same as [minimatch.match()](https://github.com/isaacs/minimatch) +* use [mm.isMatch()](#ismatch) instead of [minimatch()](https://github.com/isaacs/minimatch) + +## Why use micromatch? + +> micromatch is a [drop-in replacement](#switch-from-minimatch) for minimatch and multimatch + +Micromatch is [safer](https://github.com/jonschlinkert/braces#braces-is-safe), [faster](#benchmarks), more accurate, and supports all of the same matching features as [minimatch](https://github.com/isaacs/minimatch) and [multimatch](https://github.com/sindresorhus/multimatch). -* Logical `OR` (`foo/bar/(abc|xyz).js`) -* Regex character classes (`foo/bar/baz-[1-5].js`) -* POSIX [bracket expressions](https://github.com/jonschlinkert/expand-brackets) (`**/[[:alpha:][:digit:]]/`) -* [extglobs](https://github.com/jonschlinkert/extglob) (`**/+(x|y)`, `!(a|b)`, etc). +Moreover, micromatch has: -You can combine these to create whatever matching patterns you need. +* Better support for the Bash 4.3 specification than minimatch and multimatch +* More than 3,600 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) +* Better windows support than minimatch and multimatch + +### Features + +* Native support for multiple glob patterns (no need for wrappers like multimatch) +* Glob pattern support (`**/*`, `a/b/*.js`, or `['a/*.js', '!b.js']`) +* [extglob](https://github.com/jonschlinkert/extglob) support (`+(x|y)`, `!(a|b)`, etc) +* [POSIX character class](https://github.com/jonschlinkert/expand-brackets) support (`**/[[:alpha:][:digit:]]/`) +* [brace expansion](https://github.com/jonschlinkert/braces) support (`a/b-{1..5}.md`, `one/{two,three}/four.md`) +* regex character classes (`a/b/baz-[1-5].js`) +* regex logical or (`a/b/(abc|xyz).js`) + +You can mix and match these features to create whatever patterns you need! **Example** ```js -// double-negation! -mm(['fa', 'fb', 'f', 'fo'], '!(f!(o))'); -//=> ['fo'] +mm(['a/b.js', 'a/b.md'], 'a/*.!(js)'); +//=> ['a/b.md'] ``` -## Why switch to micromatch? - -* Native support for multiple glob patterns, no need for wrappers like [multimatch](https://github.com/sindresorhus/multimatch) -* [10-55x faster](#benchmarks) and more performant than [minimatch](https://github.com/isaacs/minimatch) and [multimatch](https://github.com/sindresorhus/multimatch). This is achieved through a combination of caching and regex optimization strategies, a fundamentally different approach than minimatch. -* More extensive support for the Bash 4.3 specification -* More complete extglob support -* Extensive [unit tests](./test) (approx. 1,300 tests). Minimatch fails many of the tests. - -### Switch from minimatch +## Switching from minimatch Use `mm.isMatch()` instead of `minimatch()`: @@ -74,7 +117,7 @@ mm.match(['foo', 'bar'], 'b*'); //=> 'bar' ``` -### Switch from multimatch +## Switching from multimatch Same signature: @@ -83,299 +126,350 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); //=> ['foo', 'baz'] ``` -*** +## API + +### [micromatch](index.js#L39) -## Usage +The main function takes a list of strings and one or more glob patterns to use for matching. -Add micromatch to your node.js project: +**Example** ```js var mm = require('micromatch'); +mm(list, patterns[, options]); + +console.log(mm(['a.js', 'a.txt'], ['*.js'])); +//=> [ 'a.js' ] ``` -**Signature** +**Params** -```js -mm(array_of_strings, glob_patterns[, options]); -``` +* `list` **{Array}**: A list of strings to match +* `patterns` **{String|Array}**: One or more glob patterns to use for matching. +* `options` **{Object}**: Any [options](#options) to change how matches are performed +* `returns` **{Array}**: Returns an array of matches + +### [.match](index.js#L107) + +Similar to the main function, but `pattern` must be a string. **Example** ```js -mm(['foo', 'bar', 'baz'], 'b*'); -//=> ['bar', 'baz'] -``` +var mm = require('micromatch'); +mm.match(list, pattern[, options]); -### Usage examples +console.log(mm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); +//=> ['a.a', 'a.aa'] +``` -**Brace expansion** +**Params** -Match files with `.js` or `.txt` extensions. +* `list` **{Array}**: Array of strings to match +* `pattern` **{String}**: Glob pattern to use for matching. +* `options` **{Object}**: Any [options](#options) to change how matches are performed +* `returns` **{Array}**: Returns an array of matches -```js -mm(['a.js', 'b.md', 'c.txt'], '*.{js,txt}'); -//=> ['a.js', 'c.txt'] -``` +### [.isMatch](index.js#L171) -**Extglobs** +Returns true if the specified `string` matches the given glob `pattern`. -Match anything except for files with the `.md` extension. +**Example** ```js -mm(files, '**/*.!(md)'); +var mm = require('micromatch'); +mm.isMatch(string, pattern[, options]); -//=> ['a.js', 'c.txt'] +console.log(mm.isMatch('a.a', '*.a')); +//=> true +console.log(mm.isMatch('a.b', '*.a')); +//=> false ``` -**Multiple patterns** - -Match using an array of patterns. +**Params** -```js -mm(['a.md', 'b.js', 'c.txt', 'd.json'], ['*.md', '*.txt']); -//=> ['a.md', 'c.txt'] -``` +* `string` **{String}**: String to match +* `pattern` **{String}**: Glob pattern to use for matching. +* `options` **{Object}**: Any [options](#options) to change how matches are performed +* `returns` **{Boolean}**: Returns true if the string matches the glob pattern. -**Negation patterns:** +### [.not](index.js#L201) -Behavior is designed to be what users would expect, based on conventions that are already well-established. +Returns a list of strings that _DO NOT MATCH_ any of the given `patterns`. -* [minimatch](https://github.com/isaacs/minimatch) behavior is used when the pattern is a string, so patterns are **inclusive by default**. -* [multimatch](https://github.com/sindresorhus/multimatch) behavior is used when an array of patterns is passed, so patterns are **exclusive by default**. +**Example** ```js -mm(['a.js', 'b.md', 'c.txt'], '!*.{js,txt}'); -//=> ['b.md'] +var mm = require('micromatch'); +mm.not(list, patterns[, options]); -mm(['a.md', 'b.js', 'c.txt', 'd.json'], ['*.*', '!*.{js,txt}']); -//=> ['a.md', 'd.json'] +console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); +//=> ['b.b', 'c.c'] ``` -*** +**Params** + +* `list` **{Array}**: Array of strings to match. +* `patterns` **{String|Array}**: One or more glob pattern to use for matching. +* `options` **{Object}**: Any [options](#options) to change how matches are performed +* `returns` **{Array}**: Returns an array of strings that **do not match** the given patterns. + +### [.any](index.js#L238) + +Returns true if the given `string` matches any of the given glob `patterns`. -## API methods +**Example** ```js var mm = require('micromatch'); +mm.any(string, patterns[, options]); + +console.log(mm.any('a.a', ['b.*', '*.a'])); +//=> true +console.log(mm.any('a.a', 'b.*')); +//=> false ``` -### .match +**Params** -```js -mm.match(array, globString); -``` +* `str` **{String}**: The string to test. +* `patterns` **{String|Array}**: One or more glob patterns to use for matching. +* `options` **{Object}**: Any [options](#options) to change how matches are performed +* `returns` **{Boolean}**: Returns true if any patterns match `str` + +### [.contains](index.js#L268) -Return an array of files that match the given glob pattern. Useful if you only need to use a single glob pattern. +Returns true if the given `string` contains the given pattern. Similar to [.isMatch](#isMatch) but the pattern can match any part of the string. **Example** ```js -mm.match(['ab', 'a/b', 'bb', 'b/c'], '?b'); -//=> ['ab', 'bb'] +var mm = require('micromatch'); +mm.contains(string, pattern[, options]); -mm.match(['ab', 'a/b', 'bb', 'b/c'], '*/b'); -//=> ['a/b'] +console.log(mm.contains('aa/bb/cc', '*b')); +//=> true +console.log(mm.contains('aa/bb/cc', '*d')); +//=> false ``` -### .isMatch +**Params** + +* `str` **{String}**: The string to match. +* `pattern` **{String}**: Glob pattern to use for matching. +* `options` **{Object}**: Any [options](#options) to change how matches are performed +* `returns` **{Boolean}**: Returns true if the patter matches any part of `str`. -```js -mm.isMatch(filepath, globString); -``` +### [.matchKeys](index.js#L317) -Returns true if a file path matches the given glob pattern. +Filter the keys of the given object with the given `glob` pattern and `options`. Does not attempt to match nested keys. If you need this feature, use [glob-object](https://github.com/jonschlinkert/glob-object) instead. **Example** ```js -mm.isMatch('.verb.md', '*.md'); -//=> false +var mm = require('micromatch'); +mm.matchKeys(object, patterns[, options]); -mm.isMatch('.verb.md', '*.md', {dot: true}); -//=> true +var obj = { aa: 'a', ab: 'b', ac: 'c' }; +console.log(mm.matchKeys(obj, '*b')); +//=> { ab: 'b' } ``` -### .contains +**Params** -Returns true if any part of a file path matches the given glob pattern. Think of this is "has path" versus "is path". +* `object` **{Object}**: The object with keys to filter. +* `patterns` **{String|Array}**: One or more glob patterns to use for matching. +* `options` **{Object}**: Any [options](#options) to change how matches are performed +* `returns` **{Object}**: Returns an object with only keys that match the given patterns. -**Example** +### [.matcher](index.js#L346) + +Returns a memoized matcher function from the given glob `pattern` and `options`. The returned function takes a string to match as its only argument and returns true if the string is a match. -`.isMatch()` would return false for both of the following: +**Example** ```js -mm.contains('a/b/c', 'a/b'); -//=> true +var mm = require('micromatch'); +mm.matcher(pattern[, options]); -mm.contains('a/b/c', 'a/*'); +var isMatch = mm.matcher('*.!(*a)'); +console.log(isMatch('a.a')); +//=> false +console.log(isMatch('a.b')); //=> true ``` -### .matcher - -Returns a function for matching using the supplied pattern. e.g. create your own "matcher". The advantage of this method is that the pattern can be compiled outside of a loop. +**Params** -**Pattern** +* `pattern` **{String}**: Glob pattern +* `options` **{Object}**: Any [options](#options) to change how matches are performed. +* `returns` **{Function}**: Returns a matcher function. -Can be any of the following: +### [.makeRe](index.js#L403) -* `glob/string` -* `regex` -* `function` +Create a regular expression from the given glob `pattern`. **Example** ```js -var isMatch = mm.matcher('*.md'); -var files = []; - -['a.md', 'b.txt', 'c.md'].forEach(function(fp) { - if (isMatch(fp)) { - files.push(fp); - } -}); -``` - -### .filter +var mm = require('micromatch'); +mm.makeRe(pattern[, options]); -Returns a function that can be passed to `Array#filter()`. +console.log(mm.makeRe('*.js')); +//=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ +``` **Params** -* `patterns` **{String|Array}**: +* `pattern` **{String}**: A glob pattern to convert to regex. +* `options` **{Object}**: Any [options](#options) to change how matches are performed. +* `returns` **{RegExp}**: Returns a regex created from the given pattern. + +### [.braces](index.js#L446) -**Examples** +Expand the given brace `pattern`. -Single glob: +**Example** ```js -var fn = mm.filter('*.md'); -['a.js', 'b.txt', 'c.md'].filter(fn); -//=> ['c.md'] +var micromatch = require('micromatch'); +console.log(micromatch.braces('foo/{a,b}/bar')); +//=> ['foo/(a|b)/bar'] -var fn = mm.filter('[a-c]'); -['a', 'b', 'c', 'd', 'e'].filter(fn); -//=> ['a', 'b', 'c'] +console.log(micromatch.braces('foo/{a,b}/bar', {expand: true})); +//=> ['foo/(a|b)/bar'] ``` -Array of glob patterns: - -```js -var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; +**Params** -var fn = mm.filter(['{1..10}', '![7-9]', '!{3..4}']); -arr.filter(fn); -//=> [1, 2, 5, 6, 10] -``` +* `pattern` **{String}**: String with brace pattern to expand. +* `options` **{Object}**: Any [options](#options) to change how expansion is performed. See the [braces](https://github.com/jonschlinkert/braces) library for all available options. +* `returns` **{Array}** -_(Internally this function generates the matching function by using the [matcher](#matcher) method. You can use the [matcher](#matcher) method directly to create your own filter function)_ +### [.create](index.js#L499) -### .any +Parses the given glob `pattern` and returns an object with the compiled `output` and optional source `map`. -Returns true if a file path matches any of the given patterns. +**Example** ```js -mm.any(filepath, patterns, options); +var mm = require('micromatch'); +mm.create(pattern[, options]); + +console.log(mm.create('abc/*.js')); +// { options: { source: 'string', sourcemap: true }, +// state: {}, +// compilers: +// { ... }, +// output: '(\\.[\\\\\\/])?abc\\/(?!\\.)(?=.)[^\\/]*?\\.js', +// ast: +// { type: 'root', +// errors: [], +// nodes: +// [ ... ], +// dot: false, +// input: 'abc/*.js' }, +// parsingErrors: [], +// map: +// { version: 3, +// sources: [ 'string' ], +// names: [], +// mappings: 'AAAA,GAAG,EAAC,kBAAC,EAAC,EAAE', +// sourcesContent: [ 'abc/*.js' ] }, +// position: { line: 1, column: 28 }, +// content: {}, +// files: {}, +// idx: 6 } ``` **Params** -* filepath `{String}`: The file path to test. -* patterns `{String|Array}`: One or more glob patterns -* options: `{Object}`: options to pass to the `.matcher()` method. +* `pattern` **{String}**: Glob pattern to parse and compile. +* `options` **{Object}**: Any [options](#options) to change how parsing and compiling is performed. +* `returns` **{Object}**: Returns an object with the parsed AST, compiled string and optional source map. + +### [.parse](index.js#L556) + +Parse the given `str` with the given `options`. **Example** ```js -mm.any('abc', ['!*z']); -//=> true -mm.any('abc', ['a*', 'z*']); -//=> true -mm.any('abc', 'a*'); -//=> true -mm.any('abc', ['z*']); -//=> false +var mm = require('micromatch'); +mm.parse(pattern[, options]); + +var ast = mm.parse('a/{b,c}/d'); +console.log(ast); +// { type: 'root', +// errors: [], +// input: 'a/{b,c}/d', +// nodes: +// [ { type: 'bos', val: '' }, +// { type: 'text', val: 'a/' }, +// { type: 'brace', +// nodes: +// [ { type: 'brace.open', val: '{' }, +// { type: 'text', val: 'b,c' }, +// { type: 'brace.close', val: '}' } ] }, +// { type: 'text', val: '/d' }, +// { type: 'eos', val: '' } ] } ``` -### .expand +**Params** -Returns an object with a regex-compatible string and tokens. +* `str` **{String}** +* `options` **{Object}** +* `returns` **{Object}**: Returns an AST -```js -mm.expand('*.js'); - -// when `track` is enabled (for debugging), the `history` array is used -// to record each mutation to the glob pattern as it's converted to regex -{ options: { track: false, dot: undefined, makeRe: true, negated: false }, - pattern: '(.*\\/|^)bar\\/(?:(?!(?:^|\\/)\\.).)*?', - history: [], - tokens: - { path: - { whole: '**/bar/**', - dirname: '**/bar/', - filename: '**', - basename: '**', - extname: '', - ext: '' }, - is: - { glob: true, - negated: false, - globstar: true, - dotfile: false, - dotdir: false }, - match: {}, - original: '**/bar/**', - pattern: '**/bar/**', - base: '' } } -``` +### [.compile](index.js#L609) -### .makeRe +Compile the given `ast` or string with the given `options`. -Create a regular expression for matching file paths based on the given pattern: +**Example** ```js -mm.makeRe('*.js'); -//=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ +var micromatch = require('micromatch'); +mm.compile(ast[, options]); + +var ast = micromatch.parse('a/{b,c}/d'); +console.log(micromatch.compile(ast)); +// { options: { source: 'string' }, +// state: {}, +// compilers: +// { eos: [Function], +// noop: [Function], +// bos: [Function], +// brace: [Function], +// 'brace.open': [Function], +// text: [Function], +// 'brace.close': [Function] }, +// output: [ 'a/(b|c)/d' ], +// ast: +// { ... }, +// parsingErrors: [] } ``` -## Options - -### options.unixify - -Normalize slashes in file paths and glob patterns to forward slashes. +**Params** -Type: `{Boolean}` +* `ast` **{Object|String}** +* `options` **{Object}** +* `returns` **{Object}**: Returns an object that has an `output` property with the compiled string. -Default: `undefined` on non-windows, `true` on windows. +## Options ### options.dot Match dotfiles. Same behavior as [minimatch](https://github.com/isaacs/minimatch). -Type: `{Boolean}` +Type: `Boolean` Default: `false` -### options.unescape - -Unescape slashes in glob patterns. Use cautiously, especially on windows. - -Type: `{Boolean}` - -Default: `undefined` - -**Example** - -```js -mm.isMatch('abc', '\\a\\b\\c', {unescape: true}); -//=> true -``` - ### options.nodupes Remove duplicate elements from the result array. -Type: `{Boolean}` +Type: `Boolean` Default: `undefined` @@ -395,7 +489,7 @@ mm.match(['abc', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true, nodupes: true}); Allow glob patterns without slashes to match a file path based on its basename. . Same behavior as [minimatch](https://github.com/isaacs/minimatch). -Type: `{Boolean}` +Type: `Boolean` Default: `false` @@ -409,21 +503,21 @@ mm(['a/b.js', 'a/c.md'], '*.js', {matchBase: true}); //=> ['a/b.js'] ``` -### options.nobraces +### options.nobrace -Don't expand braces in glob patterns. Same behavior as [minimatch](https://github.com/isaacs/minimatch) `nobrace`. +Disable expansion of brace patterns. Same behavior as [minimatch](https://github.com/isaacs/minimatch) `nobrace`. -Type: `{Boolean}` +Type: `Boolean` Default: `undefined` See [braces](https://github.com/jonschlinkert/braces) for more information about extended brace expansion. -### options.nobrackets +### options.nobracket -Don't expand POSIX bracket expressions. +Disable expansion of POSIX bracket expressions. -Type: `{Boolean}` +Type: `Boolean` Default: `undefined` @@ -431,9 +525,9 @@ See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more ### options.noextglob -Don't expand extended globs. +Disable expansion of extglobs. -Type: `{Boolean}` +Type: `Boolean` Default: `undefined` @@ -443,110 +537,55 @@ See [extglob](https://github.com/jonschlinkert/extglob) for more information abo Use a case-insensitive regex for matching files. Same behavior as [minimatch](https://github.com/isaacs/minimatch). -Type: `{Boolean}` +Type: `Boolean` -Default: `false` +Default: `undefined` ### options.nonegate -Disallow negation (`!`) patterns. +Disallow negation (`!`) patterns, and treat leading `!` as a literal character to match. -Type: `{Boolean}` +Type: `Boolean` -Default: `false` +Default: `undefined` ### options.nonull -If `true`, when no matches are found the actual (array-ified) glob pattern is returned instead of an empty array. Same behavior as [minimatch](https://github.com/isaacs/minimatch). - -Type: `{Boolean}` - -Default: `false` - -### options.cache - -Cache the platform (e.g. `win32`) to prevent this from being looked up for every filepath. - -Type: `{Boolean}` - -Default: `true` - -*** - -## Other features - -Micromatch also supports the following. - -### Extended globbing - -#### extglobs - -Extended globbing, as described by the bash man page: - -| **pattern** | **regex equivalent** | **description** | -| --- | --- | --- | -| `?(pattern-list)` | `(... | ...)?` | Matches zero or one occurrence of the given patterns | -| `*(pattern-list)` | `(... | ...)*` | Matches zero or more occurrences of the given patterns | -| `+(pattern-list)` | `(... | ...)+` | Matches one or more occurrences of the given patterns | -| `@(pattern-list)` | `(... | ...)` * | Matches one of the given patterns | -| `!(pattern-list)` | N/A | Matches anything except one of the given patterns | - -* `@` isn't a RegEx character. +If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch](https://github.com/isaacs/minimatch). -Powered by [extglob](https://github.com/jonschlinkert/extglob). Visit that library for the full range of options or to report extglob related issues. +Type: `Boolean` -See [extglob](https://github.com/jonschlinkert/extglob) for more information about extended globs. - -#### brace expansion - -In simple cases, brace expansion appears to work the same way as the logical `OR` operator. For example, `(a|b)` will achieve the same result as `{a,b}`. - -Here are some powerful features unique to brace expansion (versus character classes): - -* range expansion: `a{1..3}b/*.js` expands to: `['a1b/*.js', 'a2b/*.js', 'a3b/*.js']` -* nesting: `a{c,{d,e}}b/*.js` expands to: `['acb/*.js', 'adb/*.js', 'aeb/*.js']` - -Visit [braces](https://github.com/jonschlinkert/braces) to ask questions and create an issue related to brace-expansion, or to see the full range of features and options related to brace expansion. - -#### regex character classes +Default: `undefined` -With the exception of brace expansion (`{a,b}`, `{1..5}`, etc), most of the special characters convert directly to regex, so you can expect them to follow the same rules and produce the same results as regex. +### options.unixify -For example, given the list: `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: +Normalize slashes in file paths and glob patterns to forward slashes. -* `[ac].js`: matches both `a` and `c`, returning `['a.js', 'c.js']` -* `[b-d].js`: matches from `b` to `d`, returning `['b.js', 'c.js', 'd.js']` -* `[b-d].js`: matches from `b` to `d`, returning `['b.js', 'c.js', 'd.js']` -* `a/[A-Z].js`: matches and uppercase letter, returning `['a/E.md']` +Type: `Boolean` -Learn about [regex character classes](http://www.regular-expressions.info/charclass.html). +Default: `undefined` on non-windows, `true` on windows. -#### regex groups +### options.cache -Given `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: +Disable memoization of matching functions and generated regex. -* `(a|c).js`: would match either `a` or `c`, returning `['a.js', 'c.js']` -* `(b|d).js`: would match either `b` or `d`, returning `['b.js', 'd.js']` -* `(b|[A-Z]).js`: would match either `b` or an uppercase letter, returning `['b.js', 'E.js']` +Type: `Boolean` -As with regex, parenthese can be nested, so patterns like `((a|b)|c)/b` will work. But it might be easier to achieve your goal using brace expansion. +Default: `undefined` -#### POSIX bracket expressions +## Notes -**Example** +**Bash 4.3 parity** -```js -mm.isMatch('a1', '[[:alpha:][:digit:]]'); -//=> true -``` +Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3. Patterns that aren't described by Bash follow wildmatch spec (used by git). -See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more information about extended bracket expressions. +**Escaping** -*** +Backslashes are exclusively and explicitly reserved for escaping characters in a glob pattern, even on windows. This is also the case in minimatch and node-glob, although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212). -## Notes +To be clear, _a glob pattern is not a filepath_. When you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting for it to work as a glob pattern. The problem is that on windows the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. But since `\\` is an escape character in globs, this means that on windows `path.join('foo', '*')` results in `foo\\*` which tells micromatch that `*` is escaped. -Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3. Patterns that aren't described by Bash follow wildmatch spec (used by git). +Thus you'll need to either do the joining manually or find a lib on npm that does this. ## Benchmarks @@ -556,105 +595,90 @@ Run the [benchmarks](./benchmark): node benchmark ``` -As of July 15, 2016: - -```bash -#1: basename-braces - micromatch x 26,420 ops/sec ±0.89% (91 runs sampled) - minimatch x 3,507 ops/sec ±0.64% (97 runs sampled) - -#2: basename - micromatch x 25,315 ops/sec ±0.82% (93 runs sampled) - minimatch x 4,398 ops/sec ±0.86% (94 runs sampled) - -#3: braces-no-glob - micromatch x 341,254 ops/sec ±0.78% (93 runs sampled) - minimatch x 30,197 ops/sec ±1.12% (91 runs sampled) - -#4: braces - micromatch x 54,649 ops/sec ±0.74% (94 runs sampled) - minimatch x 3,095 ops/sec ±0.82% (95 runs sampled) - -#5: immediate - micromatch x 16,719 ops/sec ±0.79% (95 runs sampled) - minimatch x 4,348 ops/sec ±0.86% (96 runs sampled) - -#6: large - micromatch x 721 ops/sec ±0.77% (94 runs sampled) - minimatch x 17.73 ops/sec ±1.08% (50 runs sampled) +As of October 21, 2016 (longer bars are better): -#7: long - micromatch x 5,051 ops/sec ±0.87% (97 runs sampled) - minimatch x 628 ops/sec ±0.83% (94 runs sampled) - -#8: mid - micromatch x 51,280 ops/sec ±0.80% (95 runs sampled) - minimatch x 1,923 ops/sec ±0.84% (95 runs sampled) - -#9: multi-patterns - micromatch x 22,440 ops/sec ±0.97% (94 runs sampled) - minimatch x 2,481 ops/sec ±1.10% (94 runs sampled) - -#10: no-glob - micromatch x 722,823 ops/sec ±1.30% (87 runs sampled) - minimatch x 52,967 ops/sec ±1.09% (94 runs sampled) - -#11: range - micromatch x 243,471 ops/sec ±0.79% (94 runs sampled) - minimatch x 11,736 ops/sec ±0.82% (96 runs sampled) +```sh +# braces-globstar-large-list +micromatch ██████████████████████████████████ (395 ops/sec) +minimatch █ (13.75 ops/sec) +multimatch █ (13.90 ops/sec) -#12: shallow - micromatch x 190,874 ops/sec ±0.98% (95 runs sampled) - minimatch x 21,699 ops/sec ±0.81% (97 runs sampled) +# braces-multiple +micromatch ██████████████████████████████████ (35,630 ops/sec) +minimatch (1.58 ops/sec) +multimatch (1.47 ops/sec) -#13: short - micromatch x 496,393 ops/sec ±3.86% (90 runs sampled) - minimatch x 53,765 ops/sec ±0.75% (95 runs sampled) -``` +# braces-range +micromatch ██████████████████████████████████ (192,168 ops/sec) +minimatch █ (8,167 ops/sec) +multimatch █ (8,227 ops/sec) -## Tests +# braces-set +micromatch ██████████████████████████████████ (24,648 ops/sec) +minimatch ██ (1,960 ops/sec) +multimatch ██ (1,841 ops/sec) -### Running tests +# globstar-large-list +micromatch ██████████████████████████████████ (396 ops/sec) +minimatch ██ (25.49 ops/sec) +multimatch ██ (25.61 ops/sec) -Install dev dependencies: +# globstar-long-list +micromatch ██████████████████████████████████ (3,337 ops/sec) +minimatch █████ (504 ops/sec) +multimatch █████ (493 ops/sec) -```sh -$ npm install -d && npm test -``` +# globstar-short-list +micromatch ██████████████████████████████████ (465,408 ops/sec) +minimatch ██ (32,763 ops/sec) +multimatch ██ (28,196 ops/sec) -### Coverage +# no-glob +micromatch ██████████████████████████████████ (642,909 ops/sec) +minimatch █ (33,682 ops/sec) +multimatch █ (29,675 ops/sec) -As of July 15, 2016: +# star-basename +micromatch ██████████████████████████████████ (11,012 ops/sec) +minimatch █████████ (3,076 ops/sec) +multimatch █████████ (3,001 ops/sec) -```sh -Statements : 100% (441/441) -Branches : 100% (270/270) -Functions : 100% (54/54) -Lines : 100% (429/429) +# star +micromatch ██████████████████████████████████ (9,786 ops/sec) +minimatch ██████████ (2,976 ops/sec) +multimatch █████████ (2,791 ops/sec) ``` -## Contributing +## About -Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). - -Please be sure to run the benchmarks before/after any code changes to judge the impact before you do a PR. thanks! - -## Related +### Related projects * [braces](https://www.npmjs.com/package/braces): Fastest brace expansion for node.js, with the most complete support for the Bash 4.3 braces… [more](https://github.com/jonschlinkert/braces) | [homepage](https://github.com/jonschlinkert/braces "Fastest brace expansion for node.js, with the most complete support for the Bash 4.3 braces specification.") * [expand-brackets](https://www.npmjs.com/package/expand-brackets): Expand POSIX bracket expressions (character classes) in glob patterns. | [homepage](https://github.com/jonschlinkert/expand-brackets "Expand POSIX bracket expressions (character classes) in glob patterns.") -* [expand-range](https://www.npmjs.com/package/expand-range): Fast, bash-like range expansion. Expand a range of numbers or letters, uppercase or lowercase. See… [more](https://github.com/jonschlinkert/expand-range) | [homepage](https://github.com/jonschlinkert/expand-range "Fast, bash-like range expansion. Expand a range of numbers or letters, uppercase or lowercase. See the benchmarks. Used by micromatch.") * [extglob](https://www.npmjs.com/package/extglob): Convert extended globs to regex-compatible strings. Add (almost) the expressive power of regular expressions to… [more](https://github.com/jonschlinkert/extglob) | [homepage](https://github.com/jonschlinkert/extglob "Convert extended globs to regex-compatible strings. Add (almost) the expressive power of regular expressions to glob patterns.") -* [fill-range](https://www.npmjs.com/package/fill-range): Fill in a range of numbers or letters, optionally passing an increment or multiplier to… [more](https://github.com/jonschlinkert/fill-range) | [homepage](https://github.com/jonschlinkert/fill-range "Fill in a range of numbers or letters, optionally passing an increment or multiplier to use.") -* [gulp-micromatch](https://www.npmjs.com/package/gulp-micromatch): Filter vinyl files with glob patterns, string, regexp, array, object or matcher function. micromatch stream. | [homepage](https://github.com/tunnckocore/gulp-micromatch#readme "Filter vinyl files with glob patterns, string, regexp, array, object or matcher function. micromatch stream.") -* [is-glob](https://www.npmjs.com/package/is-glob): Returns `true` if the given string looks like a glob pattern or an extglob pattern… [more](https://github.com/jonschlinkert/is-glob) | [homepage](https://github.com/jonschlinkert/is-glob "Returns `true` if the given string looks like a glob pattern or an extglob pattern. This makes it easy to create code that only uses external modules like node-glob when necessary, resulting in much faster code execution and initialization time, and a bet") -* [parse-glob](https://www.npmjs.com/package/parse-glob): Parse a glob pattern into an object of tokens. | [homepage](https://github.com/jonschlinkert/parse-glob "Parse a glob pattern into an object of tokens.") +* [fill-range](https://www.npmjs.com/package/fill-range): Fill in a range of numbers or letters, optionally passing an increment or `step` to… [more](https://github.com/jonschlinkert/fill-range) | [homepage](https://github.com/jonschlinkert/fill-range "Fill in a range of numbers or letters, optionally passing an increment or `step` to use, or create a regex-compatible range with `options.toRegex`") +* [nanomatch](https://www.npmjs.com/package/nanomatch): Fast, minimal glob matcher for node.js. Similar to micromatch, minimatch and multimatch, but complete Bash… [more](https://github.com/jonschlinkert/nanomatch) | [homepage](https://github.com/jonschlinkert/nanomatch "Fast, minimal glob matcher for node.js. Similar to micromatch, minimatch and multimatch, but complete Bash 4.3 wildcard support only (no support for exglobs, posix brackets or braces)") -## Contributing +### Contributing Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). -## Building docs +### Contributors + +| **Commits** | **Contributor**
| +| --- | --- | +| 345 | [jonschlinkert](https://github.com/jonschlinkert) | +| 12 | [es128](https://github.com/es128) | +| 3 | [paulmillr](https://github.com/paulmillr) | +| 2 | [TrySound](https://github.com/TrySound) | +| 2 | [doowb](https://github.com/doowb) | +| 2 | [tunnckoCore](https://github.com/tunnckoCore) | +| 2 | [MartinKolarik](https://github.com/MartinKolarik) | +| 1 | [amilajack](https://github.com/amilajack) | +| 1 | [UltCombo](https://github.com/UltCombo) | +| 1 | [tomByrer](https://github.com/tomByrer) | + +### Building docs _(This document was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme) (a [verb](https://github.com/verbose/verb) generator), please don't edit the readme directly. Any changes to the readme must be made in [.verb.md](.verb.md).)_ @@ -664,7 +688,7 @@ To generate the readme and API documentation with [verb](https://github.com/verb $ npm install -g verb verb-generate-readme && verb ``` -## Running tests +### Running tests Install dev dependencies: @@ -672,18 +696,18 @@ Install dev dependencies: $ npm install -d && npm test ``` -## Author +### Author **Jon Schlinkert** * [github/jonschlinkert](https://github.com/jonschlinkert) * [twitter/jonschlinkert](http://twitter.com/jonschlinkert) -## License +### License Copyright © 2016, [Jon Schlinkert](https://github.com/jonschlinkert). Released under the [MIT license](https://github.com/jonschlinkert/micromatch/blob/master/LICENSE). *** -_This file was generated by [verb](https://github.com/verbose/verb), v0.9.0, on July 15, 2016._ \ No newline at end of file +_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on October 21, 2016._ \ No newline at end of file diff --git a/docs/comparison.md b/docs/comparison.md deleted file mode 100644 index 266677e8..00000000 --- a/docs/comparison.md +++ /dev/null @@ -1,130 +0,0 @@ -# micromatch vs. minimatch - -> Can micromatch be used as a drop-in replacement for minimatch? - -For mainstream features, I tried to keep as much parity as possible between micromatch and minimatch. But there are some differences. - -## Key differences - -- the main minimatch function, `minimatch()`, works like `micromatch.isMatch()` -- the main micromatch function, `micromatch()`, works like [multimatch](https://github.com/sindresorhus/multimatch), with support for multiple patterns. -- micromatch optimizes patterns to generate the leanest possible regex to use for matching without sacrificing accuracy. - -## Caching - -Micromatch uses multiple levels of caching, each basic and specifically designed for where it's being used. Glob patterns are parsed into tokens, which are then used to generate the regex to be used for matching. Like Minimatch, these patterns, tokens and resulting regex are cached to avoid repeatedly parsing the same pattern and options. - -It's worth noting that in the past minimatch used caching as well, but using a different strategy that offered little advantage. - -## Tokenization strategy - -Key points: - -- **faster regex**: spend more time tokenizing the glob pattern since the time to parse and compile to regex is a fraction of the time it takes to do the actual matching against large sets. In other words, the "easy" way is to use a small set of replacement patterns for a given set of glob characters, but the end result is a huge un-optimized regex that takes much longer to do the actual matching. We want fast regex matching. -- **avoid parsing entirely**: use [is-glob] and similar checks to avoid completely parsing the pattern when it's not necessary -- **specialized functions**: for brace expansiona and range expansion, dedication libraries were created along with extensive unit tests and granular benchmarks. In some of these benchmarks, micromatch is more than 100x faster than minimatch. - - -## Optimized regular expressions - -Micromatch's optimizations are achieved in a number of different ways. - -**Brace expansion** - -It's not uncommon to do this in a gulp or Grunt task: - -```js -src('*.{yml,json}'); -``` - - -## Features - -| **feature** | **micromatch** | **minimatch** | **notes** | -| --- | --- | --- | --- | -| multiple patterns | yes | no | ex: `['*.js', '!foo']` | -| `#` comments in file paths | no | yes | | -| [brace expansion] | yes | yes | ex: `*.{txt,md}` | -| regex character classes | yes | sort of | ex: `[a-c]*.js`, match file names starting with `a` through `c` | -| [extglobs] | yes | yes | ex: `+(foo|bar)` | -| POSIX [bracket expressions] | yes | no | (character classes) ex: `[[:alpha:][:lower:]]` | -| regex or string | yes | no | Micromatch will take a regex or a glob pattern to use for matching. | - - -### multiple pattern support - -Support for matching against multiple patterns, like `['*.js', '!foo']`: - -- Minimatch: **no** -- Micromatch: **yes** - -Because of this, there is also a [_key difference_](#main-export-key-differences) in how the main exported function from each library is used. - -**Key difference** - -- `micromatch()`: the main `micromatch()` function works like [multimatch](https://github.com/sindresorhus/multimatch), and supports matching with multiple patterns (e.g. `['*.js', '!foo']`). -- `minimatch()`: the main `minimatch()` function works like `micromatch.isMatch()`, returning true if a single path matches the given pattern. - - -## API - -### Methods - -| **method** | **micromatch** | **minimatch** | **notes** | -| --- | --- | --- | --- | -| `matchOne` | no | yes | like match, but only the first file | -| `makeRe` | yes | yes | create a regular expression from the pattern. | -| `match` | yes | yes | return an array of matches from a single pattern | -| `filter` | yes | yes | like match but returns a function that can be passed to `Array.filter` | -| `contains` | yes | no | like match, but matches any part of a path, not just the entire path | -| `expand` | yes | no | returns an [object of tokens][expand], which are passed to `.makeRe()` | -| `matcher` | yes | no | returns a function to use for matching | -| `isMatch` | yes | no | returns true if a path matches the given pattern. Works like `minimatch()` | -| `matchKeys` | yes | no | match the keys in an object | - - -## Options - -| option | micromatch | minimatch | description | -| --- | --- | --- | --- | -| `flipNegate` | no | yes | | -| `failglob` | yes | no | throw when no matches are found (bash parity) | -| `ignore` | yes | no | string or array of patterns to ignore. like negate, but passed on options. | -| `nocase` | yes | yes | ... | -| `nonull` | yes | yes | ... | -| `nullglob` | yes | yes | ... | -| `nonegate` | yes | yes | ... | - - - -## Other differences - -**benchmarks** - -micromatch is faster in every benchmark by a significant margin. One significant case that stands out is matching on arrays with thousands of items (like filepaths in a project). Here are the results from the benchmarks for matching against an array of ~7-8k items: - -```js -micromatch.js x 773 ops/sec ±0.62% (98 runs sampled) -minimatch.js x 27.52 ops/sec ±0.66% (49 runs sampled) -``` - -**Bash 4.3** - -micromatch has better Bash 4.3 coverage along with extensive, organized unit tests - -**micromatch isn't a constructor** - -However, if you're using `new Minimatch()` because you need to do some kind of customization to the pre-regex pattern or whatever, then you should be able to achieve the same or similar results with micromatch. - -In particular, `micromatch.expand()` parses the glob pattern and [returns an object][expand]. You can then pass that to the `.makeRe()` method to generate the regex for matching. - - -## Notes - -_(nothing yet)_ - - -[expand]: https://github.com/jonschlinkert/micromatch#expand -[brace expansion]: https://github.com/jonschlinkert/braces -[extglobs]: https://github.com/jonschlinkert/extglob -[bracket expressions]: https://github.com/jonschlinkert/expand-brackets From 82b4b3615231e8f942d61d123d667559898a7364 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Fri, 21 Oct 2016 18:38:39 -0400 Subject: [PATCH 13/68] update examples --- examples/extglob.js | 9 +++++---- examples/source-map.js | 11 +++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/examples/extglob.js b/examples/extglob.js index 26ecc08a..b0e2a7e7 100644 --- a/examples/extglob.js +++ b/examples/extglob.js @@ -1,8 +1,9 @@ 'use strict'; -var nanomatch = require('..'); +var mm = require('..'); var pattern = '*(*(of*(a)x)z)'; -var res = nanomatch(pattern); -console.log(res.ast.nodes); -console.log(res); +// var res = mm(pattern); +// console.log(res.ast.nodes); +// console.log(res); +console.log(mm(['a/b.js', 'a/b.md'], 'a/*.!(js)')) diff --git a/examples/source-map.js b/examples/source-map.js index 106f97c9..845d61c3 100644 --- a/examples/source-map.js +++ b/examples/source-map.js @@ -1,7 +1,14 @@ 'use strict'; -var extglob = require('..'); +var mm = require('..'); var pattern = '*(*(of*(a)x)z)'; -var res = extglob(pattern, {sourcemap: true}); +var ast = mm.parse(pattern, {sourcemap: true}); +var res = mm.compile(ast); console.log(res); +// { map: +// { version: 3, +// sources: [ 'string' ], +// names: [], +// mappings: 'AAAA,CAAE,CAAE,EAAE,CAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC', +// sourcesContent: [ '*(*(of*(a)x)z)' ] }}, From 3c1c7ae9e44db7fb05ef76f48d9f499b3625c4a9 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Fri, 21 Oct 2016 18:42:25 -0400 Subject: [PATCH 14/68] use es5 - tell travis to install bash (thanks to @doowb for that snippet) - lint --- .travis.yml | 11 +++++++++++ package.json | 2 -- test/comparison.isMatch.js | 4 ++-- test/comparison.makeRe.js | 4 ++-- test/support/parse.js | 3 ++- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index f28113ae..4cb811cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,14 @@ node_js: - '5' - '0.12' - '0.10' +# addons will be installed when running on linux +addons: + apt: + packages: + - bash + +# when running on "osx" upgrade bash +before_install: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall --force bash; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install bash; fi diff --git a/package.json b/package.json index 13a97ad7..43cbd537 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ }, "dependencies": { "arr-diff": "^3.0.0", - "arr-union": "^3.1.0", "array-unique": "^0.3.2", "bash-match": "^0.2.0", "braces": "^2.0.2", @@ -43,7 +42,6 @@ "extglob": "^1.0.0", "for-own": "^0.1.4", "fragment-cache": "^0.2.0", - "is-glob": "^3.1.0", "kind-of": "^3.0.4", "nanomatch": "^0.3.1", "object.pick": "^1.1.2", diff --git a/test/comparison.isMatch.js b/test/comparison.isMatch.js index 6003caf9..1fe31aa5 100644 --- a/test/comparison.isMatch.js +++ b/test/comparison.isMatch.js @@ -1,8 +1,8 @@ 'use strict'; +var isWindows = require('is-windows'); var assert = require('assert'); var bash = require('bash-match'); -var isWindows = require('is-windows'); var mm = require('minimatch'); var nm = require('..'); @@ -88,7 +88,7 @@ var patterns = [ describe('.isMatch', function() { if (isWindows()) { - console.log('comparisons are done using bash, these tests cannot run on windows'); + console.log('these tests use bash to test for bash parity. since bash does not work on most versions of windows, these tests are skipped on windows'); return; } diff --git a/test/comparison.makeRe.js b/test/comparison.makeRe.js index 5c6b7cc2..0ec66fb8 100644 --- a/test/comparison.makeRe.js +++ b/test/comparison.makeRe.js @@ -1,7 +1,7 @@ 'use strict'; -var assert = require('assert'); var isWindows = require('is-windows'); +var assert = require('assert'); var bash = require('bash-match'); var mm = require('minimatch'); var nm = require('..'); @@ -88,7 +88,7 @@ var patterns = [ describe('.makeRe', function() { if (isWindows()) { - console.log('comparisons are done using bash, these tests cannot run on windows'); + console.log('these tests use bash to test for bash parity. since bash does not work on most versions of windows, these tests are skipped on windows'); return; } diff --git a/test/support/parse.js b/test/support/parse.js index 31a8cbcc..08070ddb 100644 --- a/test/support/parse.js +++ b/test/support/parse.js @@ -2,10 +2,11 @@ var fs = require('fs'); var path = require('path'); +var extend = require('extend-shallow'); var nm = require('../..'); function parseFiles(pattern, options) { - var opts = Object.assign({cwd: process.cwd()}, options); + var opts = extend({cwd: process.cwd()}, options); var cwd = opts.cwd; var files = nm(fs.readdirSync(cwd), pattern); From 30f40ff39ec22bd6b8b39001ef725adf5655836b Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Fri, 21 Oct 2016 18:43:04 -0400 Subject: [PATCH 15/68] rebuild docs --- .verb.md | 42 ++++++++++-------------------------------- README.md | 48 ++++++++++++++---------------------------------- 2 files changed, 24 insertions(+), 66 deletions(-) diff --git a/.verb.md b/.verb.md index 0deffb83..502afd87 100755 --- a/.verb.md +++ b/.verb.md @@ -94,26 +94,6 @@ Type: `Boolean` Default: `false` -### options.nodupes - -Remove duplicate elements from the result array. - -Type: `Boolean` - -Default: `undefined` - -**Example** - -Example of using the `unescape` and `nodupes` options together: - -```js -mm.match(['abc', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true}); -//=> ['abc', 'abc'] - -mm.match(['abc', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true, nodupes: true}); -//=> ['abc'] -``` - ### options.matchBase Allow glob patterns without slashes to match a file path based on its basename. . Same behavior as [minimatch]. @@ -143,27 +123,25 @@ Default: `undefined` See [braces][] for more information about extended brace expansion. -### options.nobracket +### options.nodupes -Disable expansion of POSIX bracket expressions. +Remove duplicate elements from the result array. Type: `Boolean` Default: `undefined` -See [expand-brackets][] for more information about extended bracket expressions. - - -### options.noextglob - -Disable expansion of extglobs. - -Type: `Boolean` +**Example** -Default: `undefined` +Example of using the `unescape` and `nodupes` options together: -See [extglob][] for more information about extended globs. +```js +mm.match(['a/b/c', 'a/b/c'], 'a/b/c'); +//=> ['a/b/c', 'a/b/c'] +mm.match(['a/b/c', 'a/b/c'], 'a/b/c', {nodupes: true}); +//=> ['abc'] +``` ### options.nocase diff --git a/README.md b/README.md index 1abb2dc2..598ba56b 100755 --- a/README.md +++ b/README.md @@ -13,11 +13,9 @@ - [API](#api) - [Options](#options) * [options.dot](#optionsdot) - * [options.nodupes](#optionsnodupes) * [options.matchBase](#optionsmatchbase) * [options.nobrace](#optionsnobrace) - * [options.nobracket](#optionsnobracket) - * [options.noextglob](#optionsnoextglob) + * [options.nodupes](#optionsnodupes) * [options.nocase](#optionsnocase) * [options.nonegate](#optionsnonegate) * [options.nonull](#optionsnonull) @@ -465,26 +463,6 @@ Type: `Boolean` Default: `false` -### options.nodupes - -Remove duplicate elements from the result array. - -Type: `Boolean` - -Default: `undefined` - -**Example** - -Example of using the `unescape` and `nodupes` options together: - -```js -mm.match(['abc', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true}); -//=> ['abc', 'abc'] - -mm.match(['abc', '\\a\\b\\c'], '\\a\\b\\c', {unescape: true, nodupes: true}); -//=> ['abc'] -``` - ### options.matchBase Allow glob patterns without slashes to match a file path based on its basename. . Same behavior as [minimatch](https://github.com/isaacs/minimatch). @@ -513,25 +491,25 @@ Default: `undefined` See [braces](https://github.com/jonschlinkert/braces) for more information about extended brace expansion. -### options.nobracket +### options.nodupes -Disable expansion of POSIX bracket expressions. +Remove duplicate elements from the result array. Type: `Boolean` Default: `undefined` -See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more information about extended bracket expressions. - -### options.noextglob - -Disable expansion of extglobs. +**Example** -Type: `Boolean` +Example of using the `unescape` and `nodupes` options together: -Default: `undefined` +```js +mm.match(['a/b/c', 'a/b/c'], 'a/b/c'); +//=> ['a/b/c', 'a/b/c'] -See [extglob](https://github.com/jonschlinkert/extglob) for more information about extended globs. +mm.match(['a/b/c', 'a/b/c'], 'a/b/c', {nodupes: true}); +//=> ['abc'] +``` ### options.nocase @@ -663,6 +641,8 @@ multimatch █████████ (2,791 ops/sec) Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). +Please read the [contributing guide](.github/contributing.md) for avice on opening issues, pull requests, and coding standards. + ### Contributors | **Commits** | **Contributor**
| @@ -672,8 +652,8 @@ Pull requests and stars are always welcome. For bugs and feature requests, [plea | 3 | [paulmillr](https://github.com/paulmillr) | | 2 | [TrySound](https://github.com/TrySound) | | 2 | [doowb](https://github.com/doowb) | -| 2 | [tunnckoCore](https://github.com/tunnckoCore) | | 2 | [MartinKolarik](https://github.com/MartinKolarik) | +| 2 | [tunnckoCore](https://github.com/tunnckoCore) | | 1 | [amilajack](https://github.com/amilajack) | | 1 | [UltCombo](https://github.com/UltCombo) | | 1 | [tomByrer](https://github.com/tomByrer) | From 0d577d54f6532f59fec08a833cfec5f4fc5f9105 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Fri, 21 Oct 2016 20:27:35 -0400 Subject: [PATCH 16/68] don't check for bash parity on travis --- test/comparison.isMatch.js | 3 ++- test/comparison.makeRe.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/comparison.isMatch.js b/test/comparison.isMatch.js index 1fe31aa5..7fb91d8d 100644 --- a/test/comparison.isMatch.js +++ b/test/comparison.isMatch.js @@ -1,5 +1,6 @@ 'use strict'; +var isTravis = process.env.CI || process.env.TRAVIS; var isWindows = require('is-windows'); var assert = require('assert'); var bash = require('bash-match'); @@ -87,7 +88,7 @@ var patterns = [ ]; describe('.isMatch', function() { - if (isWindows()) { + if (isWindows() || isTravis) { console.log('these tests use bash to test for bash parity. since bash does not work on most versions of windows, these tests are skipped on windows'); return; } diff --git a/test/comparison.makeRe.js b/test/comparison.makeRe.js index 0ec66fb8..a4717665 100644 --- a/test/comparison.makeRe.js +++ b/test/comparison.makeRe.js @@ -1,5 +1,6 @@ 'use strict'; +var isTravis = process.env.CI || process.env.TRAVIS; var isWindows = require('is-windows'); var assert = require('assert'); var bash = require('bash-match'); @@ -87,7 +88,7 @@ var patterns = [ ]; describe('.makeRe', function() { - if (isWindows()) { + if (isWindows() || isTravis) { console.log('these tests use bash to test for bash parity. since bash does not work on most versions of windows, these tests are skipped on windows'); return; } From 0cf21261712c9f4bb6c944b32ea2f8eb5c366313 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 3 Nov 2016 15:02:33 -0400 Subject: [PATCH 17/68] move bash-match to devDeps --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 43cbd537..cecb2356 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "dependencies": { "arr-diff": "^3.0.0", "array-unique": "^0.3.2", - "bash-match": "^0.2.0", "braces": "^2.0.2", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", @@ -43,13 +42,14 @@ "for-own": "^0.1.4", "fragment-cache": "^0.2.0", "kind-of": "^3.0.4", - "nanomatch": "^0.3.1", - "object.pick": "^1.1.2", + "nanomatch": "^0.3.4", + "object.pick": "^1.2.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "devDependencies": { + "bash-match": "^0.2.0", "export-files": "^2.1.1", "fs-exists-sync": "^0.1.0", "gulp": "^3.9.1", @@ -128,4 +128,4 @@ "verb-generate-readme" ] } -} \ No newline at end of file +} From aafec780dc7fd4005ecd0bbd159630e0487c42c1 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 3 Nov 2016 15:04:11 -0400 Subject: [PATCH 18/68] reformat regex string, minor edits --- lib/compilers.js | 6 ++++-- lib/parsers.js | 20 +++++++------------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/lib/compilers.js b/lib/compilers.js index c9b38b44..8b902fbf 100644 --- a/lib/compilers.js +++ b/lib/compilers.js @@ -28,8 +28,10 @@ module.exports = function(micromatch) { .set('star', star) .set('text', text) .set('eos', function(node) { - if (micromatch.state.metachar && this.output.slice(-3) !== '\\/?') { - this.output += '\\/?'; + var suffix = '\\/?'; + var len = suffix.length; + if (micromatch.state.metachar && this.output.slice(-len) !== suffix) { + this.output += suffix; } return this.emit(node.val, node); }); diff --git a/lib/parsers.js b/lib/parsers.js index 056f9bc9..64dfbc7c 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -11,16 +11,8 @@ var toRegex = require('to-regex'); */ var cached; -var patterns = [ - '[!@*?+]?\\(', - '\\)', - '\\[:?(?=.*?:?\\])', - ':?\\]', - '[*+?!^$.\\\\/]' -]; - -var NOT_REGEX = '(' + patterns.join('|') + ')+'; -var not = textRegex(NOT_REGEX); +var TEXT = '([!@*?+]?\\(|\\)|\\[:?(?=.*?:?\\])|:?\\]|[*+?!^$.\\\\/])+'; +var not = textRegex(TEXT); module.exports = function(micromatch) { var parsers = micromatch.parser.parsers; @@ -36,6 +28,7 @@ module.exports = function(micromatch) { micromatch.use(extglob.parsers); micromatch.parser .use(function() { + // override "notRegex" used in nanomatch this.notRegex = /^\!+(?!\()/; }) .capture('escape', escape) @@ -46,7 +39,7 @@ module.exports = function(micromatch) { .capture('dot', dot) /** - * Text + * Override `text` parser */ .capture('text', function() { @@ -55,7 +48,8 @@ module.exports = function(micromatch) { var m = this.match(not); if (!m || !m[0]) return; - var val = m[0].replace(/([\[\]^$])/g, '\\$1'); + // escape brackets and regex boundary characters + var val = m[0].replace(/([[\]^$])/g, '\\$1'); return pos({ type: 'text', val: val @@ -71,6 +65,6 @@ function textRegex(pattern) { if (cached) return cached; var opts = {contains: true, strictClose: false}; var not = regexNot.create(pattern, opts); - var re = toRegex('^(?:[\\^]|\\\\|' + not + ')', opts); + var re = toRegex('(?:[\\^]|\\\\|' + not + ')', {strictClose: false}); return (cached = re); } From da85bfc879ba282e3a0cf9bbedef23b5ff854aba Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 3 Nov 2016 15:04:41 -0400 Subject: [PATCH 19/68] adds lots of dotfile and qmark tests --- examples/dot.js | 19 ++++++++++++++----- test/comparison.isMatch.js | 38 ++++++++++++++++++++++++++++++++++++-- test/dotfiles.js | 6 ++++++ test/globstars.js | 8 ++++---- test/qmarks.js | 6 ++++++ 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/examples/dot.js b/examples/dot.js index 5d1be25a..e7ba61db 100644 --- a/examples/dot.js +++ b/examples/dot.js @@ -1,7 +1,16 @@ -var mm = require('..'); +var nm = require('..'); +var mm = require('minimatch'); -console.log(mm.makeRe('.a/{,*/}xyz.md')) -console.log(mm.isMatch('.a/xyz.md', '.a/{,*/}xyz.md')); +console.log(nm.makeRe('.a/{,*/}xyz.md')) +console.log(nm.isMatch('.a/xyz.md', '.a/{,*/}xyz.md')); -console.log(mm.makeRe('.a/**/xyz.md')) -console.log(mm.isMatch('.a/xyz.md', '.a/**/xyz.md')); +console.log(nm.makeRe('.a/**/xyz.md')) +console.log(nm.isMatch('.a/xyz.md', '.a/**/xyz.md')); +console.log(nm.isMatch('./b/.c', '?/.?')); +console.log(nm.isMatch('./b/.c', '?/.?*')); +console.log(nm.isMatch('b/.c', '?/.?*')); +console.log(nm.isMatch('./', '?', {dot: true})); + +// this is wrong +console.log(mm('./', '?/', {dot: true})); +console.log(mm('./b/.c', '?/.?*')); diff --git a/test/comparison.isMatch.js b/test/comparison.isMatch.js index 7fb91d8d..15646245 100644 --- a/test/comparison.isMatch.js +++ b/test/comparison.isMatch.js @@ -15,6 +15,7 @@ var fixtures = [ 'a', 'a.md', 'a/b/c.md', + 'a/b/.c.md', 'z.js', 'za.js', @@ -69,20 +70,40 @@ var patterns = [ '!**/*.md', '!*.*', '!*.js', + '!a/*?b', + '!a/?', + '!a/?*b', + '!a/??b', + '!a/?b', '*', '**', '**/', '**/*', '**/*.md', + '**/?.md', + '**/*?.md', + '**/.?.md', '**/z*.js', '*.js', '*/*', '/**', '/**/', '/**/*', + '?', + '?/', + '?/.?', + '?/.?*', + '?/?', + '??', + '??/??', 'a/**/', 'a/**/b', 'a/**b', + 'a/*?b', + 'a/?', + 'a/?*b', + 'a/??b', + 'a/?b', 'a/b/c/**/*.js', 'a/b/c/*.js', ]; @@ -99,15 +120,28 @@ describe('.isMatch', function() { var mmRes = mm(fixture, pattern); var nmRes = nm.isMatch(fixture, pattern); var bRes = bash.isMatch(fixture, pattern); + var actual = nmRes === bRes || nmRes === mmRes; - assert(nmRes === bRes || nmRes === mmRes, fixture + ' ' + pattern); + // minimatch is wrong on these + if (actual !== nmRes && /^\?/.test(pattern)) { + actual = true; + } + + assert(actual, fixture + ' ' + pattern); }); it('should match ' + fixture + ' with ' + pattern + ' and {dot: true}', function() { var mmRes = mm(fixture, pattern, {dot: true}); var nmRes = nm.isMatch(fixture, pattern, {dot: true}); var bRes = bash.isMatch(fixture, pattern, {dot: true}); - assert(nmRes === bRes || nmRes === mmRes, fixture + ' ' + pattern); + var actual = nmRes === bRes || nmRes === mmRes; + + // minimatch is wrong on these + if (actual !== nmRes && /^\?/.test(pattern)) { + actual = true; + } + + assert(actual, fixture + ' ' + pattern); }); }); }); diff --git a/test/dotfiles.js b/test/dotfiles.js index 0ba44406..6bcbb45f 100644 --- a/test/dotfiles.js +++ b/test/dotfiles.js @@ -7,7 +7,13 @@ describe('dotfiles', function() { describe('file name matching', function() { it('should not match a dot when the dot is not explicitly defined', function() { assert(!mm.isMatch('.dot', '*dot')); + assert(!mm.isMatch('a/.dot', 'a/*dot')); + }); + + it('should not match leading dots with question marks', function() { assert(!mm.isMatch('.dot', '?dot')); + assert(!mm.isMatch('/.dot', '/?dot')); + assert(!mm.isMatch('a/.dot', 'a/?dot')); }); it('should match with double dots', function() { diff --git a/test/globstars.js b/test/globstars.js index 4b06ee4e..2f56f54f 100644 --- a/test/globstars.js +++ b/test/globstars.js @@ -5,12 +5,12 @@ var nm = require('./support/match'); describe('globstars', function() { it('should support globstars (**)', function() { - var fixtures = ['.a/a', 'a/a', 'a/.a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z', 'a/../a', 'ab/../ac', '../a', 'a', '../../b', '../c', '../c/d']; + var fixtures = ['.a/a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/.a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z', 'a/../a', 'ab/../ac', '../a', 'a', '../../b', '../c', '../c/d']; - nm(fixtures, '**', ['a', 'a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); - nm(fixtures, '**/**', ['a', 'a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + nm(fixtures, '**', ['a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + nm(fixtures, '**/**', ['a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); nm(fixtures, '**/', []); - nm(fixtures, '**/**/*', ['a', 'a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + nm(fixtures, '**/**/*', ['a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); nm(fixtures, '**/**/x', ['a/x']); nm(fixtures, '**/x', ['a/x']); nm(fixtures, '**/x/*', ['a/x/y']); diff --git a/test/qmarks.js b/test/qmarks.js index 44cd47fd..6c9e5cc5 100644 --- a/test/qmarks.js +++ b/test/qmarks.js @@ -67,4 +67,10 @@ describe('qmarks and stars', function() { assert(!mm.isMatch('aaa.bbb', 'aaa?bbb')); assert(!mm.isMatch('aaa/.bbb', 'aaa/?bbb')); }); + + it('question marks should match characters preceding a dot', function() { + assert(mm.isMatch('a/bbb/abcd.md', 'a/*/ab??.md')); + assert(mm.isMatch('a/bbb/abcd.md', 'a/bbb/ab??.md')); + assert(mm.isMatch('a/bbb/abcd.md', 'a/bbb/ab???md')); + }); }); From 042d98514d3c6f85ec632e7c98d2a8d43b377655 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 3 Nov 2016 15:19:21 -0400 Subject: [PATCH 20/68] fix chart formatting --- benchmark/helper.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/benchmark/helper.js b/benchmark/helper.js index 1b2de391..a4f0cb6e 100644 --- a/benchmark/helper.js +++ b/benchmark/helper.js @@ -2,7 +2,6 @@ var fs = require('fs'); var path = require('path'); -var size = require('window-size'); var repeat = require('repeat-string'); function bench() { @@ -70,7 +69,7 @@ function values(obj) { } function bar(tok, longest, diff) { - return repeat('█', (tok.num / longest) * (size.width - diff)); + return repeat('█', (tok.num / longest) * 70); } function format(name, tok, max, diff) { From ecec5ba798ea03f1ee68b8c9ccceaa6417a99948 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 3 Nov 2016 15:19:47 -0400 Subject: [PATCH 21/68] adds `options.nonegate` tests --- test/comparison.isMatch.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/comparison.isMatch.js b/test/comparison.isMatch.js index 15646245..19e073c9 100644 --- a/test/comparison.isMatch.js +++ b/test/comparison.isMatch.js @@ -16,7 +16,9 @@ var fixtures = [ 'a.md', 'a/b/c.md', 'a/b/.c.md', + '!a/b/.c.md', + '!a.js', 'z.js', 'za.js', 'a/b/c/z.js', @@ -143,6 +145,20 @@ describe('.isMatch', function() { assert(actual, fixture + ' ' + pattern); }); + + it('should match ' + fixture + ' with ' + pattern + ' and {nonegate: true}', function() { + var mmRes = mm(fixture, pattern, {nonegate: true}); + var nmRes = nm.isMatch(fixture, pattern, {nonegate: true}); + var bRes = bash.isMatch(fixture, pattern, {nonegate: true}); + var actual = nmRes === bRes || nmRes === mmRes; + + // minimatch is wrong on these + if (actual !== nmRes && /^\?/.test(pattern)) { + actual = true; + } + + assert(actual, fixture + ' ' + pattern); + }); }); }); }); From 947539c4418141d8ca89baacba75c80cb0539d1a Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 3 Nov 2016 15:19:56 -0400 Subject: [PATCH 22/68] typo --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 5e41511f..38838100 100644 --- a/index.js +++ b/index.js @@ -621,7 +621,7 @@ micromatch.compile = function(ast, options) { }; /** - * Memoize a generated regex or function. A unique key + * Memoize a generated regex or function. A unique key is generated * from the `type` (usually method name), the `pattern`, and * user-defined options. */ From faf18cb61f104408b92cfecd204a3e51c4317b2a Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 3 Nov 2016 15:20:04 -0400 Subject: [PATCH 23/68] generate docs --- .verb.md | 2 +- README.md | 68 +++++++++++++++++++++++++++---------------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/.verb.md b/.verb.md index 502afd87..08328b2f 100755 --- a/.verb.md +++ b/.verb.md @@ -33,7 +33,7 @@ Micromatch is [safer][braces]{#braces-is-safe}, [faster](#benchmarks), more accu Moreover, micromatch has: * Better support for the Bash 4.3 specification than minimatch and multimatch -* More than 3,600 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) +* More than 7,200 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) * Better windows support than minimatch and multimatch ### Features diff --git a/README.md b/README.md index 598ba56b..ae093419 100755 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ Micromatch is [safer](https://github.com/jonschlinkert/braces#braces-is-safe), [ Moreover, micromatch has: * Better support for the Bash 4.3 specification than minimatch and multimatch -* More than 3,600 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) +* More than 7,200 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) * Better windows support than minimatch and multimatch ### Features @@ -573,67 +573,67 @@ Run the [benchmarks](./benchmark): node benchmark ``` -As of October 21, 2016 (longer bars are better): +As of November 03, 2016 (longer bars are better): ```sh # braces-globstar-large-list -micromatch ██████████████████████████████████ (395 ops/sec) -minimatch █ (13.75 ops/sec) -multimatch █ (13.90 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (395 ops/sec) +minimatch ██ (13.75 ops/sec) +multimatch ██ (13.90 ops/sec) # braces-multiple -micromatch ██████████████████████████████████ (35,630 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (35,630 ops/sec) minimatch (1.58 ops/sec) multimatch (1.47 ops/sec) # braces-range -micromatch ██████████████████████████████████ (192,168 ops/sec) -minimatch █ (8,167 ops/sec) -multimatch █ (8,227 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (192,168 ops/sec) +minimatch ██ (8,167 ops/sec) +multimatch ██ (8,227 ops/sec) # braces-set -micromatch ██████████████████████████████████ (24,648 ops/sec) -minimatch ██ (1,960 ops/sec) -multimatch ██ (1,841 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (24,648 ops/sec) +minimatch █████ (1,960 ops/sec) +multimatch █████ (1,841 ops/sec) # globstar-large-list -micromatch ██████████████████████████████████ (396 ops/sec) -minimatch ██ (25.49 ops/sec) -multimatch ██ (25.61 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (396 ops/sec) +minimatch ████ (25.49 ops/sec) +multimatch ████ (25.61 ops/sec) # globstar-long-list -micromatch ██████████████████████████████████ (3,337 ops/sec) -minimatch █████ (504 ops/sec) -multimatch █████ (493 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (3,337 ops/sec) +minimatch ██████████ (504 ops/sec) +multimatch ██████████ (493 ops/sec) # globstar-short-list -micromatch ██████████████████████████████████ (465,408 ops/sec) -minimatch ██ (32,763 ops/sec) -multimatch ██ (28,196 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (465,408 ops/sec) +minimatch ████ (32,763 ops/sec) +multimatch ████ (28,196 ops/sec) # no-glob -micromatch ██████████████████████████████████ (642,909 ops/sec) -minimatch █ (33,682 ops/sec) -multimatch █ (29,675 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (642,909 ops/sec) +minimatch ███ (33,682 ops/sec) +multimatch ███ (29,675 ops/sec) # star-basename -micromatch ██████████████████████████████████ (11,012 ops/sec) -minimatch █████████ (3,076 ops/sec) -multimatch █████████ (3,001 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (11,012 ops/sec) +minimatch ███████████████████ (3,076 ops/sec) +multimatch ███████████████████ (3,001 ops/sec) # star -micromatch ██████████████████████████████████ (9,786 ops/sec) -minimatch ██████████ (2,976 ops/sec) -multimatch █████████ (2,791 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (9,786 ops/sec) +minimatch █████████████████████ (2,976 ops/sec) +multimatch ███████████████████ (2,791 ops/sec) ``` ## About ### Related projects -* [braces](https://www.npmjs.com/package/braces): Fastest brace expansion for node.js, with the most complete support for the Bash 4.3 braces… [more](https://github.com/jonschlinkert/braces) | [homepage](https://github.com/jonschlinkert/braces "Fastest brace expansion for node.js, with the most complete support for the Bash 4.3 braces specification.") +* [braces](https://www.npmjs.com/package/braces): Fast, comprehensive, bash-like brace expansion implemented in JavaScript. Complete support for the Bash 4.3 braces… [more](https://github.com/jonschlinkert/braces) | [homepage](https://github.com/jonschlinkert/braces "Fast, comprehensive, bash-like brace expansion implemented in JavaScript. Complete support for the Bash 4.3 braces specification, without sacrificing speed.") * [expand-brackets](https://www.npmjs.com/package/expand-brackets): Expand POSIX bracket expressions (character classes) in glob patterns. | [homepage](https://github.com/jonschlinkert/expand-brackets "Expand POSIX bracket expressions (character classes) in glob patterns.") -* [extglob](https://www.npmjs.com/package/extglob): Convert extended globs to regex-compatible strings. Add (almost) the expressive power of regular expressions to… [more](https://github.com/jonschlinkert/extglob) | [homepage](https://github.com/jonschlinkert/extglob "Convert extended globs to regex-compatible strings. Add (almost) the expressive power of regular expressions to glob patterns.") +* [extglob](https://www.npmjs.com/package/extglob): Extended glob support for JavaScript. Adds (almost) the expressive power of regular expressions to glob… [more](https://github.com/jonschlinkert/extglob) | [homepage](https://github.com/jonschlinkert/extglob "Extended glob support for JavaScript. Adds (almost) the expressive power of regular expressions to glob patterns.") * [fill-range](https://www.npmjs.com/package/fill-range): Fill in a range of numbers or letters, optionally passing an increment or `step` to… [more](https://github.com/jonschlinkert/fill-range) | [homepage](https://github.com/jonschlinkert/fill-range "Fill in a range of numbers or letters, optionally passing an increment or `step` to use, or create a regex-compatible range with `options.toRegex`") * [nanomatch](https://www.npmjs.com/package/nanomatch): Fast, minimal glob matcher for node.js. Similar to micromatch, minimatch and multimatch, but complete Bash… [more](https://github.com/jonschlinkert/nanomatch) | [homepage](https://github.com/jonschlinkert/nanomatch "Fast, minimal glob matcher for node.js. Similar to micromatch, minimatch and multimatch, but complete Bash 4.3 wildcard support only (no support for exglobs, posix brackets or braces)") @@ -652,8 +652,8 @@ Please read the [contributing guide](.github/contributing.md) for avice on openi | 3 | [paulmillr](https://github.com/paulmillr) | | 2 | [TrySound](https://github.com/TrySound) | | 2 | [doowb](https://github.com/doowb) | -| 2 | [MartinKolarik](https://github.com/MartinKolarik) | | 2 | [tunnckoCore](https://github.com/tunnckoCore) | +| 2 | [MartinKolarik](https://github.com/MartinKolarik) | | 1 | [amilajack](https://github.com/amilajack) | | 1 | [UltCombo](https://github.com/UltCombo) | | 1 | [tomByrer](https://github.com/tomByrer) | @@ -690,4 +690,4 @@ Released under the [MIT license](https://github.com/jonschlinkert/micromatch/blo *** -_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on October 21, 2016._ \ No newline at end of file +_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on November 03, 2016._ \ No newline at end of file From 0ec31732d39914ba7b4fd28c0fc91303e941477c Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 3 Nov 2016 15:24:12 -0400 Subject: [PATCH 24/68] rename examples --- examples/{dot.js => options.dot.js} | 0 .../{basename.js => options.matchBase.js} | 0 examples/options.nodupes.js | 27 +++++++++++++++++++ .../{source-map.js => options.sourceMap.js} | 0 4 files changed, 27 insertions(+) rename examples/{dot.js => options.dot.js} (100%) rename examples/{basename.js => options.matchBase.js} (100%) create mode 100644 examples/options.nodupes.js rename examples/{source-map.js => options.sourceMap.js} (100%) diff --git a/examples/dot.js b/examples/options.dot.js similarity index 100% rename from examples/dot.js rename to examples/options.dot.js diff --git a/examples/basename.js b/examples/options.matchBase.js similarity index 100% rename from examples/basename.js rename to examples/options.matchBase.js diff --git a/examples/options.nodupes.js b/examples/options.nodupes.js new file mode 100644 index 00000000..5c003d24 --- /dev/null +++ b/examples/options.nodupes.js @@ -0,0 +1,27 @@ +var mm = require('..'); +var mi = require('minimatch'); + +var files = [ + '.editorconfig', + '.git', + '.gitignore', + '.nyc_output', + '.travis.yml', + '.verb.md', + 'CHANGELOG.md', + 'CONTRIBUTING.md', + 'LICENSE', + 'coverage', + 'example.js', + 'example.md', + 'example.css', + 'index.js', + 'node_modules', + 'package.json', + 'test.js', + 'utils.js' +] + +console.log(mm(files, ['example.*', '*.js'], { + nodupes: true +})) diff --git a/examples/source-map.js b/examples/options.sourceMap.js similarity index 100% rename from examples/source-map.js rename to examples/options.sourceMap.js From 79b4ae337c0c1a436f889ab58320e7e2769aa69e Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 3 Nov 2016 15:24:39 -0400 Subject: [PATCH 25/68] adds tests for `options.nodupes` closes https://github.com/jonschlinkert/micromatch/issues/73 --- test/options.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/options.js b/test/options.js index 88b21325..197d91ba 100644 --- a/test/options.js +++ b/test/options.js @@ -120,10 +120,32 @@ describe('options', function() { }); it('should remove duplicate elements from the result array:', function() { + var fixtures = [ + '.editorconfig', + '.git', + '.gitignore', + '.nyc_output', + '.travis.yml', + '.verb.md', + 'CHANGELOG.md', + 'CONTRIBUTING.md', + 'LICENSE', + 'coverage', + 'example.js', + 'example.md', + 'example.css', + 'index.js', + 'node_modules', + 'package.json', + 'test.js', + 'utils.js' + ]; + mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c'], {}); mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['/a/b/c'], {}); mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c'], {nodupes: true}); mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['/a/b/c'], {nodupes: true}); + mm(fixtures, ['example.*', '*.js'], ['example.js', 'example.md', 'example.css', 'index.js', 'test.js', 'utils.js'], {nodupes: true}); }); it('should not remove duplicates', function() { From 0efa30c9593f9d0af6e99d3f9f7032fb91da3212 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 14 Nov 2016 17:57:17 -0500 Subject: [PATCH 26/68] adds unit tests for https://github.com/jonschlinkert/micromatch/issues/79 --- test/options.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/options.js b/test/options.js index 197d91ba..9f47b56b 100644 --- a/test/options.js +++ b/test/options.js @@ -32,6 +32,10 @@ describe('options', function() { mm(globs, 'a/*', [], {ignore: 'a/**', dot: true}); mm(globs, '**/*/x', ['x/x/x'], {ignore: 'a/**', dot: true}); + // see https://github.com/jonschlinkert/micromatch/issues/79 + mm(['foo.js', 'a/foo.js'], '**/foo.js', ['foo.js', 'a/foo.js']); + mm(['foo.js', 'a/foo.js'], '**/foo.js', ['foo.js', 'a/foo.js'], {dot: true}); + mm(negations, '!b/a', ['b/b', 'b/c'], opts); mm(negations, '!b/(a)', ['b/b', 'b/c'], opts); mm(negations, '!(b/(a))', ['b/b', 'b/c'], opts); From 971ba5c97a4a9a5eeedb9bc7a59eba029d1c3eff Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 24 Nov 2016 16:58:36 -0500 Subject: [PATCH 27/68] braces examples --- examples/braces.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/braces.js b/examples/braces.js index 237eb53e..2cc97df3 100644 --- a/examples/braces.js +++ b/examples/braces.js @@ -1,7 +1,13 @@ var mm = require('../'); console.log(mm.braces('{a,b}')); +//=> [ '(a|b)' ] + +console.log(mm.braces('{a,b}', {expand: true})); //=> [ 'a', 'b' ] console.log(mm.braces('foo/{a,b}/bar')); +//=> [ 'foo/(a|b)/bar' ] + +console.log(mm.braces('foo/{a,b}/bar', {expand: true})); //=> [ 'foo/a/bar', 'foo/b/bar' ] From b50e2a8cf826f04aec94d6561993ec964f35b6e0 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 24 Nov 2016 16:58:47 -0500 Subject: [PATCH 28/68] update docs --- .verb.md | 111 ++++++++++++++++++++++++++++++++++++++++--------------- index.js | 35 ++++++++++-------- 2 files changed, 101 insertions(+), 45 deletions(-) diff --git a/.verb.md b/.verb.md index 08328b2f..05a83b62 100755 --- a/.verb.md +++ b/.verb.md @@ -80,23 +80,25 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); //=> ['foo', 'baz'] ``` -## API -{%= apidocs("index.js") %} - ## Options -### options.dot - -Match dotfiles. Same behavior as [minimatch]. - -Type: `Boolean` - -Default: `false` - +- [options.basename](#options-basename) +- [options.cache](#options-cache) +- [options.dot](#options-dot) +- [options.failglob](#options-failglob) +- [options.ignore](#options-ignore) +- [options.matchBase](#options-matchBase) +- [options.nobrace](#options-nobrace) +- [options.nocase](#options-nocase) +- [options.nodupes](#options-nodupes) +- [options.nonull](#options-nonull) +- [options.nullglob](#options-nullglob) +- [options.snapdragon](#options-snapdragon) +- [options.unescape](#options-unescape) -### options.matchBase +### options.basename -Allow glob patterns without slashes to match a file path based on its basename. . Same behavior as [minimatch]. +Allow glob patterns without slashes to match a file path based on its basename. Same behavior as [minimatch][] option `matchBase`. Type: `Boolean` @@ -112,9 +114,50 @@ mm(['a/b.js', 'a/c.md'], '*.js', {matchBase: true}); //=> ['a/b.js'] ``` +### options.cache + +Disable regex and function memoization. + +Type: `Boolean` + +Default: `undefined` + + +### options.dot + +Match dotfiles. Same behavior as [minimatch][] option `dot`. + +Type: `Boolean` + +Default: `false` + + +### options.failglob + +Similar to the `--failglob` behavior in Bash, throws an error when no matches are found. + +Type: `Boolean` + +Default: `undefined` + + +### options.ignore + +String or array of glob patterns to match files to ignore. + +Type: `String|Array` + +Default: `undefined` + + +### options.matchBase + +Alias for [options.basename](#options-basename). + + ### options.nobrace -Disable expansion of brace patterns. Same behavior as [minimatch][] `nobrace`. +Disable expansion of brace patterns. Same behavior as [minimatch][] option `nobrace`. Type: `Boolean` @@ -123,6 +166,15 @@ Default: `undefined` See [braces][] for more information about extended brace expansion. +### options.nocase + +Use a case-insensitive regex for matching files. Same behavior as [minimatch][]. + +Type: `Boolean` + +Default: `undefined` + + ### options.nodupes Remove duplicate elements from the result array. @@ -143,15 +195,6 @@ mm.match(['a/b/c', 'a/b/c'], 'a/b/c', {nodupes: true}); //=> ['abc'] ``` -### options.nocase - -Use a case-insensitive regex for matching files. Same behavior as [minimatch][]. - -Type: `Boolean` - -Default: `undefined` - - ### options.nonegate Disallow negation (`!`) patterns, and treat leading `!` as a literal character to match. @@ -163,31 +206,39 @@ Default: `undefined` ### options.nonull -If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch][]. +Alias for [options.nullglob](#options-nullglob). + + +### options.nullglob + +If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch][] option `nonull`. Type: `Boolean` Default: `undefined` -### options.unixify +### options.snapdragon -Normalize slashes in file paths and glob patterns to forward slashes. +Pass your own instance of [snapdragon][], to customize parsers or compilers. -Type: `Boolean` +Type: `Object` -Default: `undefined` on non-windows, `true` on windows. +Default: `undefined` -### options.cache +### options.unescape -Disable memoization of matching functions and generated regex. +Remove backslashes from glob patterns. Type: `Boolean` Default: `undefined` +## API +{%= apidocs("index.js") %} + ## Notes **Bash 4.3 parity** diff --git a/index.js b/index.js index 38838100..9b816ebb 100644 --- a/index.js +++ b/index.js @@ -78,15 +78,6 @@ function micromatch(list, patterns, options) { return matches; } -/** - * Cache - */ - -micromatch.cache = cache; -micromatch.clearCache = function() { - micromatch.cache.__data__ = {}; -}; - /** * Similar to the main function, but `pattern` must be a string. * @@ -430,11 +421,11 @@ micromatch.makeRe = function(pattern, options) { * Expand the given brace `pattern`. * * ```js - * var micromatch = require('micromatch'); - * console.log(micromatch.braces('foo/{a,b}/bar')); + * var mm = require('micromatch'); + * console.log(mm.braces('foo/{a,b}/bar')); * //=> ['foo/(a|b)/bar'] * - * console.log(micromatch.braces('foo/{a,b}/bar', {expand: true})); + * console.log(mm.braces('foo/{a,b}/bar', {expand: true})); * //=> ['foo/(a|b)/bar'] * ``` * @param {String} `pattern` String with brace pattern to expand. @@ -576,15 +567,28 @@ micromatch.parse = function(pattern, options) { return memoize('parse', pattern, options, parse); }; +/** + * Clear the regex cache. + * + * ```js + * mm.clearCache(); + * ``` + * @api public + */ + +micromatch.clearCache = function() { + micromatch.cache.__data__ = {}; +}; + /** * Compile the given `ast` or string with the given `options`. * * ```js - * var micromatch = require('micromatch'); + * var mm = require('micromatch'); * mm.compile(ast[, options]); * - * var ast = micromatch.parse('a/{b,c}/d'); - * console.log(micromatch.compile(ast)); + * var ast = mm.parse('a/{b,c}/d'); + * console.log(mm.compile(ast)); * // { options: { source: 'string' }, * // state: {}, * // compilers: @@ -646,6 +650,7 @@ function memoize(type, pattern, options, fn) { micromatch.compilers = compilers; micromatch.parsers = parsers; +micromatch.cache = cache; /** * Expose `micromatch` From 9681e2777c057266d3677c003847f75d6acf9e7a Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 24 Nov 2016 17:00:07 -0500 Subject: [PATCH 29/68] rebuild docs --- README.md | 367 +++++++++++++++++++++++++++------------------- benchmark/last.md | 62 ++++---- 2 files changed, 245 insertions(+), 184 deletions(-) diff --git a/README.md b/README.md index ae093419..afec0a07 100755 --- a/README.md +++ b/README.md @@ -10,17 +10,22 @@ * [Features](#features) - [Switching from minimatch](#switching-from-minimatch) - [Switching from multimatch](#switching-from-multimatch) -- [API](#api) - [Options](#options) + * [options.basename](#optionsbasename) + * [options.cache](#optionscache) * [options.dot](#optionsdot) + * [options.failglob](#optionsfailglob) + * [options.ignore](#optionsignore) * [options.matchBase](#optionsmatchbase) * [options.nobrace](#optionsnobrace) - * [options.nodupes](#optionsnodupes) * [options.nocase](#optionsnocase) + * [options.nodupes](#optionsnodupes) * [options.nonegate](#optionsnonegate) * [options.nonull](#optionsnonull) - * [options.unixify](#optionsunixify) - * [options.cache](#optionscache) + * [options.nullglob](#optionsnullglob) + * [options.snapdragon](#optionssnapdragon) + * [options.unescape](#optionsunescape) +- [API](#api) - [Notes](#notes) - [Benchmarks](#benchmarks) - [About](#about) @@ -124,6 +129,150 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); //=> ['foo', 'baz'] ``` +## Options + +* [options.basename](#options-basename) +* [options.cache](#options-cache) +* [options.dot](#options-dot) +* [options.failglob](#options-failglob) +* [options.ignore](#options-ignore) +* [options.matchBase](#options-matchBase) +* [options.nobrace](#options-nobrace) +* [options.nocase](#options-nocase) +* [options.nodupes](#options-nodupes) +* [options.nonull](#options-nonull) +* [options.nullglob](#options-nullglob) +* [options.snapdragon](#options-snapdragon) +* [options.unescape](#options-unescape) + +### options.basename + +Allow glob patterns without slashes to match a file path based on its basename. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `matchBase`. + +Type: `Boolean` + +Default: `false` + +**Example** + +```js +mm(['a/b.js', 'a/c.md'], '*.js'); +//=> [] + +mm(['a/b.js', 'a/c.md'], '*.js', {matchBase: true}); +//=> ['a/b.js'] +``` + +### options.cache + +Disable regex and function memoization. + +Type: `Boolean` + +Default: `undefined` + +### options.dot + +Match dotfiles. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `dot`. + +Type: `Boolean` + +Default: `false` + +### options.failglob + +Similar to the `--failglob` behavior in Bash, throws an error when no matches are found. + +Type: `Boolean` + +Default: `undefined` + +### options.ignore + +String or array of glob patterns to match files to ignore. + +Type: `String|Array` + +Default: `undefined` + +### options.matchBase + +Alias for [options.basename](#options-basename). + +### options.nobrace + +Disable expansion of brace patterns. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `nobrace`. + +Type: `Boolean` + +Default: `undefined` + +See [braces](https://github.com/jonschlinkert/braces) for more information about extended brace expansion. + +### options.nocase + +Use a case-insensitive regex for matching files. Same behavior as [minimatch](https://github.com/isaacs/minimatch). + +Type: `Boolean` + +Default: `undefined` + +### options.nodupes + +Remove duplicate elements from the result array. + +Type: `Boolean` + +Default: `undefined` + +**Example** + +Example of using the `unescape` and `nodupes` options together: + +```js +mm.match(['a/b/c', 'a/b/c'], 'a/b/c'); +//=> ['a/b/c', 'a/b/c'] + +mm.match(['a/b/c', 'a/b/c'], 'a/b/c', {nodupes: true}); +//=> ['abc'] +``` + +### options.nonegate + +Disallow negation (`!`) patterns, and treat leading `!` as a literal character to match. + +Type: `Boolean` + +Default: `undefined` + +### options.nonull + +Alias for [options.nullglob](#options-nullglob). + +### options.nullglob + +If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `nonull`. + +Type: `Boolean` + +Default: `undefined` + +### options.snapdragon + +Pass your own instance of [snapdragon](https://github.com/jonschlinkert/snapdragon), to customize parsers or compilers. + +Type: `Object` + +Default: `undefined` + +### options.unescape + +Remove backslashes from glob patterns. + +Type: `Boolean` + +Default: `undefined` + ## API ### [micromatch](index.js#L39) @@ -147,7 +296,7 @@ console.log(mm(['a.js', 'a.txt'], ['*.js'])); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Array}**: Returns an array of matches -### [.match](index.js#L107) +### [.match](index.js#L98) Similar to the main function, but `pattern` must be a string. @@ -168,7 +317,7 @@ console.log(mm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Array}**: Returns an array of matches -### [.isMatch](index.js#L171) +### [.isMatch](index.js#L162) Returns true if the specified `string` matches the given glob `pattern`. @@ -191,7 +340,7 @@ console.log(mm.isMatch('a.b', '*.a')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Boolean}**: Returns true if the string matches the glob pattern. -### [.not](index.js#L201) +### [.not](index.js#L192) Returns a list of strings that _DO NOT MATCH_ any of the given `patterns`. @@ -212,7 +361,7 @@ console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Array}**: Returns an array of strings that **do not match** the given patterns. -### [.any](index.js#L238) +### [.any](index.js#L229) Returns true if the given `string` matches any of the given glob `patterns`. @@ -235,7 +384,7 @@ console.log(mm.any('a.a', 'b.*')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Boolean}**: Returns true if any patterns match `str` -### [.contains](index.js#L268) +### [.contains](index.js#L259) Returns true if the given `string` contains the given pattern. Similar to [.isMatch](#isMatch) but the pattern can match any part of the string. @@ -258,7 +407,7 @@ console.log(mm.contains('aa/bb/cc', '*d')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Boolean}**: Returns true if the patter matches any part of `str`. -### [.matchKeys](index.js#L317) +### [.matchKeys](index.js#L308) Filter the keys of the given object with the given `glob` pattern and `options`. Does not attempt to match nested keys. If you need this feature, use [glob-object](https://github.com/jonschlinkert/glob-object) instead. @@ -280,7 +429,7 @@ console.log(mm.matchKeys(obj, '*b')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Object}**: Returns an object with only keys that match the given patterns. -### [.matcher](index.js#L346) +### [.matcher](index.js#L337) Returns a memoized matcher function from the given glob `pattern` and `options`. The returned function takes a string to match as its only argument and returns true if the string is a match. @@ -303,7 +452,7 @@ console.log(isMatch('a.b')); * `options` **{Object}**: Any [options](#options) to change how matches are performed. * `returns` **{Function}**: Returns a matcher function. -### [.makeRe](index.js#L403) +### [.makeRe](index.js#L394) Create a regular expression from the given glob `pattern`. @@ -323,18 +472,18 @@ console.log(mm.makeRe('*.js')); * `options` **{Object}**: Any [options](#options) to change how matches are performed. * `returns` **{RegExp}**: Returns a regex created from the given pattern. -### [.braces](index.js#L446) +### [.braces](index.js#L437) Expand the given brace `pattern`. **Example** ```js -var micromatch = require('micromatch'); -console.log(micromatch.braces('foo/{a,b}/bar')); +var mm = require('micromatch'); +console.log(mm.braces('foo/{a,b}/bar')); //=> ['foo/(a|b)/bar'] -console.log(micromatch.braces('foo/{a,b}/bar', {expand: true})); +console.log(mm.braces('foo/{a,b}/bar', {expand: true})); //=> ['foo/(a|b)/bar'] ``` @@ -344,7 +493,7 @@ console.log(micromatch.braces('foo/{a,b}/bar', {expand: true})); * `options` **{Object}**: Any [options](#options) to change how expansion is performed. See the [braces](https://github.com/jonschlinkert/braces) library for all available options. * `returns` **{Array}** -### [.create](index.js#L499) +### [.create](index.js#L490) Parses the given glob `pattern` and returns an object with the compiled `output` and optional source `map`. @@ -386,7 +535,7 @@ console.log(mm.create('abc/*.js')); * `options` **{Object}**: Any [options](#options) to change how parsing and compiling is performed. * `returns` **{Object}**: Returns an object with the parsed AST, compiled string and optional source map. -### [.parse](index.js#L556) +### [.parse](index.js#L547) Parse the given `str` with the given `options`. @@ -419,18 +568,28 @@ console.log(ast); * `options` **{Object}** * `returns` **{Object}**: Returns an AST -### [.compile](index.js#L609) +### [.clearCache](index.js#L579) + +Clear the regex cache. + +**Example** + +```js +mm.clearCache(); +``` + +### [.compile](index.js#L613) Compile the given `ast` or string with the given `options`. **Example** ```js -var micromatch = require('micromatch'); +var mm = require('micromatch'); mm.compile(ast[, options]); -var ast = micromatch.parse('a/{b,c}/d'); -console.log(micromatch.compile(ast)); +var ast = mm.parse('a/{b,c}/d'); +console.log(mm.compile(ast)); // { options: { source: 'string' }, // state: {}, // compilers: @@ -453,104 +612,6 @@ console.log(micromatch.compile(ast)); * `options` **{Object}** * `returns` **{Object}**: Returns an object that has an `output` property with the compiled string. -## Options - -### options.dot - -Match dotfiles. Same behavior as [minimatch](https://github.com/isaacs/minimatch). - -Type: `Boolean` - -Default: `false` - -### options.matchBase - -Allow glob patterns without slashes to match a file path based on its basename. . Same behavior as [minimatch](https://github.com/isaacs/minimatch). - -Type: `Boolean` - -Default: `false` - -**Example** - -```js -mm(['a/b.js', 'a/c.md'], '*.js'); -//=> [] - -mm(['a/b.js', 'a/c.md'], '*.js', {matchBase: true}); -//=> ['a/b.js'] -``` - -### options.nobrace - -Disable expansion of brace patterns. Same behavior as [minimatch](https://github.com/isaacs/minimatch) `nobrace`. - -Type: `Boolean` - -Default: `undefined` - -See [braces](https://github.com/jonschlinkert/braces) for more information about extended brace expansion. - -### options.nodupes - -Remove duplicate elements from the result array. - -Type: `Boolean` - -Default: `undefined` - -**Example** - -Example of using the `unescape` and `nodupes` options together: - -```js -mm.match(['a/b/c', 'a/b/c'], 'a/b/c'); -//=> ['a/b/c', 'a/b/c'] - -mm.match(['a/b/c', 'a/b/c'], 'a/b/c', {nodupes: true}); -//=> ['abc'] -``` - -### options.nocase - -Use a case-insensitive regex for matching files. Same behavior as [minimatch](https://github.com/isaacs/minimatch). - -Type: `Boolean` - -Default: `undefined` - -### options.nonegate - -Disallow negation (`!`) patterns, and treat leading `!` as a literal character to match. - -Type: `Boolean` - -Default: `undefined` - -### options.nonull - -If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch](https://github.com/isaacs/minimatch). - -Type: `Boolean` - -Default: `undefined` - -### options.unixify - -Normalize slashes in file paths and glob patterns to forward slashes. - -Type: `Boolean` - -Default: `undefined` on non-windows, `true` on windows. - -### options.cache - -Disable memoization of matching functions and generated regex. - -Type: `Boolean` - -Default: `undefined` - ## Notes **Bash 4.3 parity** @@ -573,58 +634,58 @@ Run the [benchmarks](./benchmark): node benchmark ``` -As of November 03, 2016 (longer bars are better): +As of November 24, 2016 (longer bars are better): ```sh # braces-globstar-large-list -micromatch ██████████████████████████████████████████████████████████████████████ (395 ops/sec) -minimatch ██ (13.75 ops/sec) -multimatch ██ (13.90 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (413 ops/sec) +minimatch ██ (13.20 ops/sec) +multimatch ██ (12.47 ops/sec) # braces-multiple -micromatch ██████████████████████████████████████████████████████████████████████ (35,630 ops/sec) -minimatch (1.58 ops/sec) -multimatch (1.47 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (36,121 ops/sec) +minimatch (1.59 ops/sec) +multimatch (1.46 ops/sec) # braces-range -micromatch ██████████████████████████████████████████████████████████████████████ (192,168 ops/sec) -minimatch ██ (8,167 ops/sec) -multimatch ██ (8,227 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (210,437 ops/sec) +minimatch ██ (8,559 ops/sec) +multimatch ██ (8,342 ops/sec) # braces-set -micromatch ██████████████████████████████████████████████████████████████████████ (24,648 ops/sec) -minimatch █████ (1,960 ops/sec) -multimatch █████ (1,841 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (25,350 ops/sec) +minimatch █████ (2,067 ops/sec) +multimatch █████ (1,815 ops/sec) # globstar-large-list -micromatch ██████████████████████████████████████████████████████████████████████ (396 ops/sec) -minimatch ████ (25.49 ops/sec) -multimatch ████ (25.61 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (399 ops/sec) +minimatch ████ (23.99 ops/sec) +multimatch ████ (25.91 ops/sec) # globstar-long-list -micromatch ██████████████████████████████████████████████████████████████████████ (3,337 ops/sec) -minimatch ██████████ (504 ops/sec) -multimatch ██████████ (493 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (3,639 ops/sec) +minimatch █████████ (504 ops/sec) +multimatch ██████████ (539 ops/sec) # globstar-short-list -micromatch ██████████████████████████████████████████████████████████████████████ (465,408 ops/sec) -minimatch ████ (32,763 ops/sec) -multimatch ████ (28,196 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (436,248 ops/sec) +minimatch ████ (30,473 ops/sec) +multimatch ████ (26,826 ops/sec) # no-glob -micromatch ██████████████████████████████████████████████████████████████████████ (642,909 ops/sec) -minimatch ███ (33,682 ops/sec) -multimatch ███ (29,675 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (625,755 ops/sec) +minimatch ████ (39,617 ops/sec) +multimatch ███ (33,846 ops/sec) # star-basename -micromatch ██████████████████████████████████████████████████████████████████████ (11,012 ops/sec) -minimatch ███████████████████ (3,076 ops/sec) -multimatch ███████████████████ (3,001 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (11,281 ops/sec) +minimatch ██████████████████ (3,028 ops/sec) +multimatch █████████████████████ (3,395 ops/sec) # star -micromatch ██████████████████████████████████████████████████████████████████████ (9,786 ops/sec) -minimatch █████████████████████ (2,976 ops/sec) -multimatch ███████████████████ (2,791 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (9,578 ops/sec) +minimatch ████████████████████ (2,865 ops/sec) +multimatch ████████████████████ (2,873 ops/sec) ``` ## About @@ -652,8 +713,8 @@ Please read the [contributing guide](.github/contributing.md) for avice on openi | 3 | [paulmillr](https://github.com/paulmillr) | | 2 | [TrySound](https://github.com/TrySound) | | 2 | [doowb](https://github.com/doowb) | -| 2 | [tunnckoCore](https://github.com/tunnckoCore) | | 2 | [MartinKolarik](https://github.com/MartinKolarik) | +| 2 | [tunnckoCore](https://github.com/tunnckoCore) | | 1 | [amilajack](https://github.com/amilajack) | | 1 | [UltCombo](https://github.com/UltCombo) | | 1 | [tomByrer](https://github.com/tomByrer) | @@ -690,4 +751,4 @@ Released under the [MIT license](https://github.com/jonschlinkert/micromatch/blo *** -_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on November 03, 2016._ \ No newline at end of file +_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on November 24, 2016._ \ No newline at end of file diff --git a/benchmark/last.md b/benchmark/last.md index c363b793..0d5c4b5d 100644 --- a/benchmark/last.md +++ b/benchmark/last.md @@ -1,4 +1,4 @@ -Benchmarking: (10 of 10) +enchmarking: (10 of 10) · braces-globstar-large-list · braces-multiple · braces-range @@ -11,71 +11,71 @@ Benchmarking: (10 of 10) · star # benchmark/fixtures/match/braces-globstar-large-list.js (485691 bytes) - micromatch x 395 ops/sec ±0.54% (84 runs sampled) - minimatch x 13.75 ops/sec ±0.67% (37 runs sampled) - multimatch x 13.90 ops/sec ±0.53% (37 runs sampled) + micromatch x 413 ops/sec ±1.10% (82 runs sampled) + minimatch x 13.20 ops/sec ±2.02% (36 runs sampled) + multimatch x 12.47 ops/sec ±2.24% (36 runs sampled) fastest is micromatch # benchmark/fixtures/match/braces-multiple.js (3143 bytes) - micromatch x 35,630 ops/sec ±1.39% (88 runs sampled) - minimatch x 1.58 ops/sec ±4.05% (7 runs sampled) - multimatch x 1.47 ops/sec ±2.40% (7 runs sampled) + micromatch x 36,121 ops/sec ±1.96% (82 runs sampled) + minimatch x 1.59 ops/sec ±3.57% (7 runs sampled) + multimatch x 1.46 ops/sec ±2.41% (7 runs sampled) fastest is micromatch # benchmark/fixtures/match/braces-range.js (727 bytes) - micromatch x 192,168 ops/sec ±0.33% (90 runs sampled) - minimatch x 8,167 ops/sec ±0.45% (88 runs sampled) - multimatch x 8,227 ops/sec ±1.25% (86 runs sampled) + micromatch x 210,437 ops/sec ±1.31% (81 runs sampled) + minimatch x 8,559 ops/sec ±1.33% (85 runs sampled) + multimatch x 8,342 ops/sec ±2.42% (84 runs sampled) fastest is micromatch # benchmark/fixtures/match/braces-set.js (2858 bytes) - micromatch x 24,648 ops/sec ±1.11% (87 runs sampled) - minimatch x 1,960 ops/sec ±1.37% (88 runs sampled) - multimatch x 1,841 ops/sec ±1.41% (87 runs sampled) + micromatch x 25,350 ops/sec ±1.68% (82 runs sampled) + minimatch x 2,067 ops/sec ±1.54% (84 runs sampled) + multimatch x 1,815 ops/sec ±1.69% (83 runs sampled) fastest is micromatch # benchmark/fixtures/match/globstar-large-list.js (485686 bytes) - micromatch x 396 ops/sec ±0.47% (85 runs sampled) - minimatch x 25.49 ops/sec ±1.39% (44 runs sampled) - multimatch x 25.61 ops/sec ±0.57% (44 runs sampled) + micromatch x 399 ops/sec ±1.36% (82 runs sampled) + minimatch x 23.99 ops/sec ±2.16% (43 runs sampled) + multimatch x 25.91 ops/sec ±1.89% (43 runs sampled) fastest is micromatch # benchmark/fixtures/match/globstar-long-list.js (90647 bytes) - micromatch x 3,337 ops/sec ±0.73% (89 runs sampled) - minimatch x 504 ops/sec ±0.91% (87 runs sampled) - multimatch x 493 ops/sec ±1.23% (86 runs sampled) + micromatch x 3,639 ops/sec ±1.45% (83 runs sampled) + minimatch x 504 ops/sec ±1.78% (83 runs sampled) + multimatch x 539 ops/sec ±1.68% (81 runs sampled) fastest is micromatch # benchmark/fixtures/match/globstar-short-list.js (182 bytes) - micromatch x 465,408 ops/sec ±1.51% (88 runs sampled) - minimatch x 32,763 ops/sec ±1.52% (88 runs sampled) - multimatch x 28,196 ops/sec ±0.92% (88 runs sampled) + micromatch x 436,248 ops/sec ±1.66% (84 runs sampled) + minimatch x 30,473 ops/sec ±1.54% (85 runs sampled) + multimatch x 26,826 ops/sec ±1.88% (85 runs sampled) fastest is micromatch # benchmark/fixtures/match/no-glob.js (701 bytes) - micromatch x 642,909 ops/sec ±1.13% (88 runs sampled) - minimatch x 33,682 ops/sec ±1.29% (85 runs sampled) - multimatch x 29,675 ops/sec ±1.41% (88 runs sampled) + micromatch x 625,755 ops/sec ±1.50% (84 runs sampled) + minimatch x 39,617 ops/sec ±1.64% (84 runs sampled) + multimatch x 33,846 ops/sec ±2.06% (81 runs sampled) fastest is micromatch # benchmark/fixtures/match/star-basename.js (12339 bytes) - micromatch x 11,012 ops/sec ±0.47% (87 runs sampled) - minimatch x 3,076 ops/sec ±1.71% (85 runs sampled) - multimatch x 3,001 ops/sec ±1.59% (89 runs sampled) + micromatch x 11,281 ops/sec ±1.55% (82 runs sampled) + minimatch x 3,028 ops/sec ±1.61% (83 runs sampled) + multimatch x 3,395 ops/sec ±1.74% (81 runs sampled) fastest is micromatch # benchmark/fixtures/match/star.js (12338 bytes) - micromatch x 9,786 ops/sec ±0.58% (87 runs sampled) - minimatch x 2,976 ops/sec ±1.58% (87 runs sampled) - multimatch x 2,791 ops/sec ±1.17% (88 runs sampled) + micromatch x 9,578 ops/sec ±1.31% (83 runs sampled) + minimatch x 2,865 ops/sec ±2.12% (84 runs sampled) + multimatch x 2,873 ops/sec ±2.06% (83 runs sampled) fastest is micromatch From 036c25a7f4b1d837b47e4e2e7181f35a104f30da Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Fri, 25 Nov 2016 02:25:19 -0500 Subject: [PATCH 30/68] support multiple patterns with `.matcher` --- index.js | 20 +++++---- lib/utils.js | 16 +++++++ test/api.matcher.js | 102 ++++++++++++++++++++++++++++++++++++++++++ test/support/match.js | 24 ++++++++++ 4 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 test/api.matcher.js diff --git a/index.js b/index.js index 9b816ebb..13bd64ed 100644 --- a/index.js +++ b/index.js @@ -107,14 +107,14 @@ micromatch.match = function(list, pattern, options) { while (++idx < len) { var ele = list[idx]; - if (ele === pattern) { - matches.push(unixify(ele)); + var unix = unixify(ele); + if (ele === pattern || unix === pattern) { + matches.push(unix); continue; } - var unix = unixify(ele); - if (unix === pattern || isMatch(unix)) { - matches.push(unix); + if (isMatch(ele)) { + matches.push(ele); } } @@ -334,8 +334,12 @@ micromatch.matchKeys = function(obj, patterns, options) { * @api public */ -micromatch.matcher = function(pattern, options) { - function matcher() { +micromatch.matcher = function matcher(pattern, options) { + if (Array.isArray(pattern)) { + return utils.compose(pattern, options, matcher); + } + + function fn() { var unixify = utils.unixify(options); // if pattern is a regex @@ -372,7 +376,7 @@ micromatch.matcher = function(pattern, options) { }; } - return memoize('matcher', pattern, options, matcher); + return memoize('matcher', pattern, options, fn); }; /** diff --git a/lib/utils.js b/lib/utils.js index 36b380a1..4ac78ef1 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -16,6 +16,22 @@ utils.typeOf = require('kind-of'); utils.pick = require('object.pick'); utils.unique = require('array-unique'); +/** + * Compose a matcher function with the given patterns + */ + +utils.compose = function(patterns, options, matcher) { + var fns = patterns.map(function(pattern) { + return matcher(pattern, options); + }); + + return function(file) { + var len = fns.length; + while (len--) if (fns[len](file)) return true; + return false; + }; +}; + /** * Get the `Snapdragon` instance to use */ diff --git a/test/api.matcher.js b/test/api.matcher.js new file mode 100644 index 00000000..3e1ae4a0 --- /dev/null +++ b/test/api.matcher.js @@ -0,0 +1,102 @@ +'use strict'; + +var mm = require('./support/match'); + +describe('.match method', function() { + describe('posix paths', function() { + it('should return an array of matches for a literal string', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + mm.matcher(fixtures, '(a/b)', ['a/b']); + mm.matcher(fixtures, 'a/b', ['a/b']); + }); + + it('should support regex logical or', function() { + var fixtures = ['a/a', 'a/b', 'a/c']; + mm.matcher(fixtures, 'a/(a|c)', ['a/a', 'a/c']); + mm.matcher(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); + }); + + it('should support regex ranges', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'a/x/y', 'a/x']; + mm.matcher(fixtures, 'a/[b-c]', ['a/b', 'a/c']); + mm.matcher(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + }); + + it('should support negation patterns', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + mm.matcher(fixtures, '!*/*', []); + mm.matcher(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); + mm.matcher(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); + mm.matcher(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + }); + }); + + describe('posix paths (array of patterns)', function() { + it('should return an array of matches for a literal string', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + mm.matcher(fixtures, ['(a/b)'], ['a/b']); + mm.matcher(fixtures, ['a/b'], ['a/b']); + }); + + it('should support regex logical or', function() { + var fixtures = ['a/a', 'a/b', 'a/c']; + mm.matcher(fixtures, ['a/(a|c)'], ['a/a', 'a/c']); + mm.matcher(fixtures, ['a/(a|b|c)'], ['a/a', 'a/b', 'a/c']); + }); + + it('should support regex ranges', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'a/x/y', 'a/x']; + mm.matcher(fixtures, ['a/[b-c]'], ['a/b', 'a/c']); + mm.matcher(fixtures, ['a/[a-z]'], ['a/a', 'a/b', 'a/c', 'a/x']); + }); + + it('should support negation patterns', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + mm.matcher(fixtures, ['!*/*'], []); + mm.matcher(fixtures, ['!*/*'], []); + mm.matcher(fixtures, ['!*/b'], ['a/a', 'a/c', 'b/a', 'b/c']); + mm.matcher(fixtures, ['!a/*'], ['b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, ['!a/b'], ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, ['!a/(b)'], ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, ['!a/(*)'], ['b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, ['!(*/b)'], ['a/a', 'a/c', 'b/a', 'b/c']); + mm.matcher(fixtures, ['!(a/b)'], ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + }); + }); + + describe('unix paths', function() { + it('should return an array of matches for a literal string', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + mm.matcher(fixtures, '(a/b)', ['a/b']); + mm.matcher(fixtures, 'a/b', ['a/b']); + }); + + it('should support regex logical or', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c']; + mm.matcher(fixtures, 'a/(a|c)', ['a/a', 'a/c']); + mm.matcher(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); + }); + + it('should support regex ranges', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x\\y', 'a\\x']; + mm.matcher(fixtures, 'a/[b-c]', ['a/b', 'a/c']); + mm.matcher(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + }); + + it('should support negation patterns', function() { + var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + mm.matcher(fixtures, '!*/*', []); + mm.matcher(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); + mm.matcher(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); + mm.matcher(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + }); + }); +}); diff --git a/test/support/match.js b/test/support/match.js index 6c3b742b..e3ec06ec 100644 --- a/test/support/match.js +++ b/test/support/match.js @@ -4,6 +4,7 @@ var assert = require('assert'); var utils = require('../../lib/utils'); var matcher = require('./matcher'); var compare = require('./compare'); +var mm = require('../..'); module.exports = function(fixtures, patterns, expected, options) { if (!Array.isArray(expected)) { @@ -33,6 +34,29 @@ module.exports.match = function(fixtures, pattern, expected, options) { assert.deepEqual(actual, expected, pattern); }; +module.exports.matcher = function(fixtures, patterns, expected, options) { + if (!Array.isArray(expected)) { + var tmp = expected; + expected = options; + options = tmp; + } + + var fn = matcher.matcher(patterns, options); + fixtures = utils.arrayify(fixtures); + + var actual = []; + fixtures.forEach(function(file) { + if (fn(file)) { + actual.push(file); + } + }); + + expected.sort(compare); + actual.sort(compare); + + assert.deepEqual(actual, expected, patterns); +}; + module.exports.isMatch = function() { return matcher.isMatch.apply(null, arguments); }; From 3ef332ee813b601a96c90652336a9d3cef23e927 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:29:54 -0500 Subject: [PATCH 31/68] run update --- .gitignore | 2 ++ .travis.yml | 13 +------------ appveyor.yml | 2 +- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 13bb9bac..ebe74fab 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ test/actual actual coverage +.nyc* # npm node_modules @@ -18,3 +19,4 @@ vendor temp tmp TODO.md +yarn.lock \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 4cb811cd..8acd4608 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,17 +6,6 @@ language: node_js node_js: - node - '6' - - '5' + - '4' - '0.12' - '0.10' -# addons will be installed when running on linux -addons: - apt: - packages: - - bash - -# when running on "osx" upgrade bash -before_install: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall --force bash; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install bash; fi diff --git a/appveyor.yml b/appveyor.yml index ce44317a..71b3df58 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ environment: matrix: # node.js - nodejs_version: "6.0" - - nodejs_version: "5.0" + - nodejs_version: "4.0" - nodejs_version: "0.12" - nodejs_version: "0.10" From ef09f10056b51c94693a6bf6431d709399a165eb Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:30:21 -0500 Subject: [PATCH 32/68] adds `.create` example --- examples/create.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 examples/create.js diff --git a/examples/create.js b/examples/create.js new file mode 100644 index 00000000..e3e1edd2 --- /dev/null +++ b/examples/create.js @@ -0,0 +1,5 @@ +var mm = require('../'); + +console.log(mm.create('{a,b}', {expand: true})); +console.log(mm.create('{a,b}')); + From 5c224ddae977db3a7c4547dbeef7ab45f1fb0869 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:30:37 -0500 Subject: [PATCH 33/68] make file paths consistent --- benchmark/fixtures/match/braces-multiple.js | 218 ++++++++++---------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/benchmark/fixtures/match/braces-multiple.js b/benchmark/fixtures/match/braces-multiple.js index f6672cb7..a35ef5a6 100644 --- a/benchmark/fixtures/match/braces-multiple.js +++ b/benchmark/fixtures/match/braces-multiple.js @@ -1,23 +1,23 @@ module.exports = [ [ - "a/g-1.txt", - "b/g-1.txt", - "c/g-1.txt", - "a/h-1.txt", - "b/h-1.txt", - "c/h-1.txt", - "a/i-1.txt", - "b/i-1.txt", - "c/i-1.txt", - "a/g-200.txt", - "b/g-200.txt", - "c/g-200.txt", - "a/h-200.txt", - "b/h-200.txt", - "c/h-200.txt", - "a/i-200.txt", - "b/i-200.txt", - "c/i-200.txt", + "a/g-0001.txt", + "b/g-0001.txt", + "c/g-0001.txt", + "a/h-0001.txt", + "b/h-0001.txt", + "c/h-0001.txt", + "a/i-0001.txt", + "b/i-0001.txt", + "c/i-0001.txt", + "a/g-0200.txt", + "b/g-0200.txt", + "c/g-0200.txt", + "a/h-0200.txt", + "b/h-0200.txt", + "c/h-0200.txt", + "a/i-0200.txt", + "b/i-0200.txt", + "c/i-0200.txt", "a/g-3000.txt", "b/g-3000.txt", "c/g-3000.txt", @@ -27,24 +27,24 @@ module.exports = [ "a/i-3000.txt", "b/i-3000.txt", "c/i-3000.txt", - "a/g-1.js", - "b/g-1.js", - "c/g-1.js", - "a/h-1.js", - "b/h-1.js", - "c/h-1.js", - "a/i-1.js", - "b/i-1.js", - "c/i-1.js", - "a/g-200.js", - "b/g-200.js", - "c/g-200.js", - "a/h-200.js", - "b/h-200.js", - "c/h-200.js", - "a/i-200.js", - "b/i-200.js", - "c/i-200.js", + "a/g-0001.js", + "b/g-0001.js", + "c/g-0001.js", + "a/h-0001.js", + "b/h-0001.js", + "c/h-0001.js", + "a/i-0001.js", + "b/i-0001.js", + "c/i-0001.js", + "a/g-0200.js", + "b/g-0200.js", + "c/g-0200.js", + "a/h-0200.js", + "b/h-0200.js", + "c/h-0200.js", + "a/i-0200.js", + "b/i-0200.js", + "c/i-0200.js", "a/g-3000.js", "b/g-3000.js", "c/g-3000.js", @@ -54,24 +54,24 @@ module.exports = [ "a/i-3000.js", "b/i-3000.js", "c/i-3000.js", - "a/g-1.md", - "b/g-1.md", - "c/g-1.md", - "a/h-1.md", - "b/h-1.md", - "c/h-1.md", - "a/i-1.md", - "b/i-1.md", - "c/i-1.md", - "a/g-200.md", - "b/g-200.md", - "c/g-200.md", - "a/h-200.md", - "b/h-200.md", - "c/h-200.md", - "a/i-200.md", - "b/i-200.md", - "c/i-200.md", + "a/g-0001.md", + "b/g-0001.md", + "c/g-0001.md", + "a/h-0001.md", + "b/h-0001.md", + "c/h-0001.md", + "a/i-0001.md", + "b/i-0001.md", + "c/i-0001.md", + "a/g-0200.md", + "b/g-0200.md", + "c/g-0200.md", + "a/h-0200.md", + "b/h-0200.md", + "c/h-0200.md", + "a/i-0200.md", + "b/i-0200.md", + "c/i-0200.md", "a/g-3000.md", "b/g-3000.md", "c/g-3000.md", @@ -81,24 +81,24 @@ module.exports = [ "a/i-3000.md", "b/i-3000.md", "c/i-3000.md", - "a/g-1.hbs", - "b/g-1.hbs", - "c/g-1.hbs", - "a/h-1.hbs", - "b/h-1.hbs", - "c/h-1.hbs", - "a/i-1.hbs", - "b/i-1.hbs", - "c/i-1.hbs", - "a/g-200.hbs", - "b/g-200.hbs", - "c/g-200.hbs", - "a/h-200.hbs", - "b/h-200.hbs", - "c/h-200.hbs", - "a/i-200.hbs", - "b/i-200.hbs", - "c/i-200.hbs", + "a/g-0001.hbs", + "b/g-0001.hbs", + "c/g-0001.hbs", + "a/h-0001.hbs", + "b/h-0001.hbs", + "c/h-0001.hbs", + "a/i-0001.hbs", + "b/i-0001.hbs", + "c/i-0001.hbs", + "a/g-0200.hbs", + "b/g-0200.hbs", + "c/g-0200.hbs", + "a/h-0200.hbs", + "b/h-0200.hbs", + "c/h-0200.hbs", + "a/i-0200.hbs", + "b/i-0200.hbs", + "c/i-0200.hbs", "a/g-3000.hbs", "b/g-3000.hbs", "c/g-3000.hbs", @@ -108,24 +108,24 @@ module.exports = [ "a/i-3000.hbs", "b/i-3000.hbs", "c/i-3000.hbs", - "a/g-1.json", - "b/g-1.json", - "c/g-1.json", - "a/h-1.json", - "b/h-1.json", - "c/h-1.json", - "a/i-1.json", - "b/i-1.json", - "c/i-1.json", - "a/g-200.json", - "b/g-200.json", - "c/g-200.json", - "a/h-200.json", - "b/h-200.json", - "c/h-200.json", - "a/i-200.json", - "b/i-200.json", - "c/i-200.json", + "a/g-0001.json", + "b/g-0001.json", + "c/g-0001.json", + "a/h-0001.json", + "b/h-0001.json", + "c/h-0001.json", + "a/i-0001.json", + "b/i-0001.json", + "c/i-0001.json", + "a/g-0200.json", + "b/g-0200.json", + "c/g-0200.json", + "a/h-0200.json", + "b/h-0200.json", + "c/h-0200.json", + "a/i-0200.json", + "b/i-0200.json", + "c/i-0200.json", "a/g-3000.json", "b/g-3000.json", "c/g-3000.json", @@ -135,24 +135,24 @@ module.exports = [ "a/i-3000.json", "b/i-3000.json", "c/i-3000.json", - "a/g-1.coffee", - "b/g-1.coffee", - "c/g-1.coffee", - "a/h-1.coffee", - "b/h-1.coffee", - "c/h-1.coffee", - "a/i-1.coffee", - "b/i-1.coffee", - "c/i-1.coffee", - "a/g-200.coffee", - "b/g-200.coffee", - "c/g-200.coffee", - "a/h-200.coffee", - "b/h-200.coffee", - "c/h-200.coffee", - "a/i-200.coffee", - "b/i-200.coffee", - "c/i-200.coffee", + "a/g-0001.coffee", + "b/g-0001.coffee", + "c/g-0001.coffee", + "a/h-0001.coffee", + "b/h-0001.coffee", + "c/h-0001.coffee", + "a/i-0001.coffee", + "b/i-0001.coffee", + "c/i-0001.coffee", + "a/g-0200.coffee", + "b/g-0200.coffee", + "c/g-0200.coffee", + "a/h-0200.coffee", + "b/h-0200.coffee", + "c/h-0200.coffee", + "a/i-0200.coffee", + "b/i-0200.coffee", + "c/i-0200.coffee", "a/g-3000.coffee", "b/g-3000.coffee", "c/g-3000.coffee", @@ -163,5 +163,5 @@ module.exports = [ "b/i-3000.coffee", "c/i-3000.coffee" ], - "{a..c}/{g..i}-{1..3000}.{md,js}" + "{a..c}/{g..i}-{0001..3000}.{md,js}" ]; \ No newline at end of file From e9c11cafb1565449759b7f3b0636794fe39c25e5 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:40:23 -0500 Subject: [PATCH 34/68] lint benchmarks --- benchmark/code/isMatch/micromatch.js | 2 -- benchmark/code/match/micromatch.js | 2 -- benchmark/package.json | 1 + 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/benchmark/code/isMatch/micromatch.js b/benchmark/code/isMatch/micromatch.js index 34dc7463..34ddb370 100644 --- a/benchmark/code/isMatch/micromatch.js +++ b/benchmark/code/isMatch/micromatch.js @@ -1,5 +1,3 @@ -'use strict'; - var micromatch = require('../../..'); module.exports = function(file, pattern) { diff --git a/benchmark/code/match/micromatch.js b/benchmark/code/match/micromatch.js index 3375d935..84a26f6c 100644 --- a/benchmark/code/match/micromatch.js +++ b/benchmark/code/match/micromatch.js @@ -1,5 +1,3 @@ -'use strict'; - var micromatch = require('../../..'); module.exports = function(files, pattern) { diff --git a/benchmark/package.json b/benchmark/package.json index 735754cc..e8f1cb80 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -14,6 +14,7 @@ "is-primitive": "^2.0.0", "minimatch": "^3.0.3", "multimatch": "^2.1.0", + "repeat-string": "^1.6.1", "write": "^0.3.2", "yargs-parser": "^4.0.2" } From 337b08da9d9c95ce1ff9bc6716861fdc494d7d11 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:44:00 -0500 Subject: [PATCH 35/68] edit nanomatch star pattern with custom pattern --- lib/compilers.js | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/lib/compilers.js b/lib/compilers.js index 8b902fbf..e345e4a1 100644 --- a/lib/compilers.js +++ b/lib/compilers.js @@ -3,23 +3,37 @@ var nanomatch = require('nanomatch'); var extglob = require('extglob'); -module.exports = function(micromatch) { - var compilers = micromatch.compiler.compilers; +module.exports = function(snapdragon) { + var compilers = snapdragon.compiler.compilers; - micromatch.state = micromatch.state || {}; - micromatch.use(nanomatch.compilers); + snapdragon.state = snapdragon.state || {}; - // store nanomatch compilers to override extglob compilers + // register nanomatch compilers + snapdragon.use(nanomatch.compilers); + + // get references to some specific nanomatch compilers before they + // are overridden by the extglob and/or custom compilers var escape = compilers.escape; var qmark = compilers.qmark; var slash = compilers.slash; var star = compilers.star; - var plus = compilers.plus; var text = compilers.text; + var plus = compilers.plus; var dot = compilers.dot; + var eos = compilers.eos; + + // register extglob compilers + snapdragon.use(extglob.compilers); + snapdragon.use(function() { + this.options.star = this.options.star || function() { + return '[^/]*?'; + }; + }); - micromatch.use(extglob.compilers); - micromatch.compiler + // custom micromatch compilers + snapdragon.compiler + + // reset referenced compiler .set('dot', dot) .set('escape', escape) .set('plus', plus) @@ -27,11 +41,18 @@ module.exports = function(micromatch) { .set('qmark', qmark) .set('star', star) .set('text', text) + + // customize end-of-string compiler .set('eos', function(node) { - var suffix = '\\/?'; - var len = suffix.length; - if (micromatch.state.metachar && this.output.slice(-len) !== suffix) { - this.output += suffix; + if (this.ast.input.slice(-1) !== '/' && this.output.slice(-1) !== '/') { + var suffix = /(\w|\/\])$/.test(this.output) ? '\\/?' : '(\\/|$)'; + var len = suffix.length; + if (snapdragon.state.metachar && this.output.slice(-len) !== suffix) { + this.output += suffix; + } + } + if (typeof eos === 'function') { + return eos.apply(this, arguments); } return this.emit(node.val, node); }); From 2fb592576dd5e3e71c98fea7b3222209eeb67d8d Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:44:48 -0500 Subject: [PATCH 36/68] minor code organization --- lib/parsers.js | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/lib/parsers.js b/lib/parsers.js index 64dfbc7c..961a4007 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -1,23 +1,35 @@ 'use strict'; +var define = require('define-property'); var extglob = require('extglob'); var nanomatch = require('nanomatch'); var regexNot = require('regex-not'); var toRegex = require('to-regex'); +var cached; +var not; /** * Characters to use in negation regex (we want to "not" match * characters that are matched by other parsers) */ -var cached; var TEXT = '([!@*?+]?\\(|\\)|\\[:?(?=.*?:?\\])|:?\\]|[*+?!^$.\\\\/])+'; -var not = textRegex(TEXT); +var createNotRegex = function(opts) { + return not || (not = textRegex(TEXT)); +}; -module.exports = function(micromatch) { - var parsers = micromatch.parser.parsers; +/** + * Parsers + */ - micromatch.use(nanomatch.parsers); +module.exports = function(snapdragon) { + var parsers = snapdragon.parser.parsers; + + // register nanomatch parsers + snapdragon.use(nanomatch.parsers); + + // get references to some specific nanomatch parsers before they + // are overridden by the extglob and/or parsers var escape = parsers.escape; var slash = parsers.slash; var qmark = parsers.qmark; @@ -25,12 +37,16 @@ module.exports = function(micromatch) { var star = parsers.star; var dot = parsers.dot; - micromatch.use(extglob.parsers); - micromatch.parser + // register extglob parsers + snapdragon.use(extglob.parsers); + + // custom micromatch parsers + snapdragon.parser .use(function() { - // override "notRegex" used in nanomatch + // override "notRegex" created in nanomatch parser this.notRegex = /^\!+(?!\()/; }) + // reset the referenced parsers .capture('escape', escape) .capture('slash', slash) .capture('qmark', qmark) @@ -38,18 +54,19 @@ module.exports = function(micromatch) { .capture('plus', plus) .capture('dot', dot) - /** + /** * Override `text` parser */ .capture('text', function() { if (this.isInside('bracket')) return; var pos = this.position(); - var m = this.match(not); + var m = this.match(createNotRegex(this.options)); if (!m || !m[0]) return; - // escape brackets and regex boundary characters + // escape regex boundary characters and simple brackets var val = m[0].replace(/([[\]^$])/g, '\\$1'); + return pos({ type: 'text', val: val @@ -63,8 +80,8 @@ module.exports = function(micromatch) { function textRegex(pattern) { if (cached) return cached; - var opts = {contains: true, strictClose: false}; - var not = regexNot.create(pattern, opts); - var re = toRegex('(?:[\\^]|\\\\|' + not + ')', {strictClose: false}); + var notStr = regexNot.create(pattern, {contains: true, strictClose: false}); + var prefix = '(?:[\\^]|\\\\|'; + var re = toRegex(prefix + notStr + ')', {strictClose: false}); return (cached = re); } From a564ca6977d02f1447e276bf11584fd69cff1c95 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:46:12 -0500 Subject: [PATCH 37/68] minor code organization --- lib/utils.js | 71 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index 4ac78ef1..11699112 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -16,6 +16,10 @@ utils.typeOf = require('kind-of'); utils.pick = require('object.pick'); utils.unique = require('array-unique'); +utils.last = function(arr, n) { + return arr[arr.length - (n || 1)]; +}; + /** * Compose a matcher function with the given patterns */ @@ -160,13 +164,13 @@ utils.combineDuplicates = function(str, val) { */ utils.hasSpecialChars = function(str) { - return /(?:(^|\/)[!.]|[*?+()|\[\]{}]|[+@]\()/.test(str); + return /(?:(?:(^|\/)[!.])|[*?+()|\[\]{}]|[+@]\()/.test(str); }; /** * Strip backslashes from a string. * - * @param {String} `filepath` + * @param {String} `str` * @return {String} */ @@ -181,8 +185,28 @@ utils.unescape = function(str) { * @return {String} */ -utils.normalize = function(filepath) { - return filepath.replace(/[\\\/]+(?=[\w._-])(?![*?+\\!])/g, '/'); +utils.normalize = function(str) { + return str.replace(/\\+/g, '/'); +}; + +/** + * Strip the drive letter from a windows filepath + * @param {String} `fp` + * @return {String} + */ + +utils.stripDrive = function(fp) { + return path.sep === '\\' ? fp.replace(/^[a-z]:\/?/i, '/') : fp; +}; + +/** + * Strip the prefix from a filepath + * @param {String} `fp` + * @return {String} + */ + +utils.stripPrefix = function(str) { + return str.replace(/^\.[\\\/]+/, ''); }; /** @@ -197,7 +221,7 @@ utils.isSimpleChar = function(str) { }; utils.isSlash = function(str) { - return str === '/' || str === '\\' || str === '\\\\'; + return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; }; /** @@ -226,6 +250,7 @@ utils.equalsPattern = function(pattern, options) { var unixify = utils.unixify(options); return function(filepath) { + filepath = utils.stripPrefix(filepath); if (options && options.nocase === true) { filepath = filepath.toLowerCase(); } @@ -244,6 +269,7 @@ utils.equalsPattern = function(pattern, options) { utils.containsPattern = function(pattern, options) { var unixify = utils.unixify(options); return function(filepath) { + filepath = utils.stripPrefix(filepath); if (options && options.nocase === true) { return unixify(filepath.toLowerCase()).indexOf(pattern) !== -1; } else { @@ -266,33 +292,16 @@ utils.matchBasename = function(re) { }; }; -/** - * Strip the prefix from a filepath - * @param {String} `filepath` - * @return {String} - */ - -utils.stripPrefix = function(fp) { - if (typeof fp !== 'string') { - return fp; - } - - if (fp.charAt(0) === '.' && (fp.charAt(1) === '/' || fp.charAt(1) === '\\')) { - return fp.slice(2); - } - - return fp; -}; - /** * Normalize all slashes in a file path or glob pattern to * forward slashes. */ utils.unixify = function(options) { - var key = utils.createKey('unixify', options); + var type = path.sep === '\\' ? 'backslash' : 'slash'; + var key = utils.createKey('unixify' + type, options); - if (cache.hasOwnProperty(key) && path.sep === '/') { + if (cache.hasOwnProperty(key)) { return cache[key]; } @@ -300,18 +309,20 @@ utils.unixify = function(options) { return utils.stripPrefix(filepath); }; - if (path.sep !== '/' || (options && (options.unixify === true || options.normalize === true))) { + options = options || {}; + if (type === 'backslash' || options.unixify === true || options.normalize === true) { unixify = function(filepath) { return utils.stripPrefix(utils.normalize(filepath)); }; } - if (options && options.unescape === true) { - unixify = function(filepath) { - return utils.stripPrefix(utils.normalize(utils.unescape(filepath))); + if (options.unescape === true) { + var fn = function(filepath) { + return unixify(utils.unescape(filepath)); }; + cache[key] = fn; + return fn; } - cache[key] = unixify; return unixify; }; From d843c5a631ed2a7a9cabf121ffe8aa776b139eda Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:46:30 -0500 Subject: [PATCH 38/68] add unit tests --- test/_fixtures.js | 83 ++++++++++ test/{support/patterns.js => _patterns.js} | 89 +++++++++++ test/api.any.js | 63 +++++--- test/api.contains.js | 28 +++- test/api.isMatch.js | 2 +- test/api.js | 42 +++++ test/api.match.js | 25 ++- test/api.matcher.js | 39 +++-- test/bash.js | 11 +- test/bash.spec.js | 41 ++--- test/braces.js | 19 +++ test/brackets.js | 13 +- test/comparison.isMatch.js | 178 +++++++-------------- test/comparison.makeRe.js | 155 ++++++++---------- test/dotfiles.js | 8 +- test/extglobs.js | 32 ++-- test/fixtures/patterns.js | 92 ++++++----- test/globstars.js | 151 +++++++++-------- test/issue-related.js | 74 ++++----- test/minimatch.js | 64 +++++++- test/negation.js | 1 + test/options.js | 77 +++++++-- test/qmarks.js | 25 ++- test/regex-ranges.js | 9 +- test/stars.js | 20 ++- test/support/match.js | 6 +- test/support/matcher.js | 58 +++---- test/support/parse.js | 8 +- 28 files changed, 911 insertions(+), 502 deletions(-) create mode 100644 test/_fixtures.js rename test/{support/patterns.js => _patterns.js} (64%) diff --git a/test/_fixtures.js b/test/_fixtures.js new file mode 100644 index 00000000..6133098f --- /dev/null +++ b/test/_fixtures.js @@ -0,0 +1,83 @@ +module.exports = [ + 'a', + 'a.md', + 'a.js', + 'a/', + 'a/b', + 'a/b/.c.md', + 'a/b/c', + 'a/b/c.md', + 'a/b/c/', + 'a/b/c/d', + 'a/b/c/d/', + 'a/b/c/d/e/f/z.js', + 'a/b/c/z.js', + 'a/bb', + 'a/cb', + 'abbbz', + 'abc', + 'abd', + 'z.js', + 'za.js', + + // literal "!" + '!a.js', + '!a/b', + '!a/b/', + '!a/b/c', + '!a/b/c/', + '!a/!b', + '!a/!b/c', + '!a/!b/c/d', + '!a/b/.c.md', + + // root + '/a/', + '/a/b', + '/a/cb', + '/a/bb', + '/a/b/c', + '/a/b/c/', + '/a/b/c/d', + '/a/b/c/d/', + + // cwd + '.', + './', + + // ancestor directories + '..', + '../c', + '../c', + './../c', + './a/../c', + '/..', + '/../c', + '/../.c', + '/../.c/', + '/a/../c', + 'a/../c', + + // dot files + '../.b/.c', + '../b/.c', + './.b/.c', + './b/.c', + '.b', + '.b.c', + '.b.c/', + '.b/', + '.b/.c', + '.b/c', + 'b/.c', + 'b/.c/', + + // wildcards in filepaths + 'a/+b/c', + '+a/+b/c', + 'a (foo)', + 'a (foo)/(bar)', + 'a/b/c (1)', + 'a/b (2)/c (1)', + 'a/b/c [def]', +]; diff --git a/test/support/patterns.js b/test/_patterns.js similarity index 64% rename from test/support/patterns.js rename to test/_patterns.js index fc79aac4..8448f9a0 100644 --- a/test/support/patterns.js +++ b/test/_patterns.js @@ -1,4 +1,93 @@ module.exports = [ + '!**', + '!**/*', + '!**/*.md', + '!*.*', + '!*.js', + '!*/**/*', + '!*/**/*/', + '!*/*/*', + '!/**', + '!/**/', + '!/*/', + '!/*/**/*/', + '!/*/*/', + '!a/!b*', + '!a/!b/*', + '!a/*?b', + '!a/?', + '!a/?*b', + '!a/??b', + '!a/?b', + '!a/b/!*', + '!a/b/*', + '!a/b/c*', + '*', + '**', + '***', + '**********', + '**/', + '**/*', + '**/**', + '**/**/**', + '**/*.md', + '**/*?.md', + '**/.?.md', + '**/?.md', + '**/z*.js', + '*.js', + '*/', + '*/*', + '*/*/*', + '*/*/*/*', + '/*', + '/**', + '/**/', + '/**/*', + '/*/', + '/*/*', + '/*/**/', + '/*/**/*', + '/*/*/', + '/*/*/*', + '/*/*/*/*', + '/*/*/*/*/', + '?', + '?*?******?', + '?*?***?', + '?*?***?***????', + '?*?*?', + '?/', + '?/.?', + '?/.?*', + '?/?', + '?/?/?', + '??', + '??/??', + '???', + '????', + 'a/*', + 'a/*/', + 'a/b/*', + 'a/**/', + 'a/**/b', + 'a/**b', + 'a/*/', + 'a/*?b', + 'a/?', + 'a/?*b', + 'a/??b', + 'a/?b', + 'a/b', + 'a/b*', + 'a/b/*', + 'a/b/c', + 'a/b/c/*', + 'a/b/c/**/*.js', + 'a/b/c/*.js', +]; + +module.exports.other = [ 'code/{for,while,*-{test,exec}}*.js', 'code/{for-*,while*}.js', '**/a/*/b/c/.js', diff --git a/test/api.any.js b/test/api.any.js index 4f637888..204f95e5 100644 --- a/test/api.any.js +++ b/test/api.any.js @@ -7,12 +7,16 @@ var mm = require('..'); describe('.any()', function() { describe('empty patterns', function() { it('should correctly handle empty patterns', function() { - assert(!mm.any('ab', '')); - assert(!mm.any('a', '')); + assert(!mm.any('', '')); + assert(!mm.any('', [''])); assert(!mm.any('.', '')); - assert(!mm.any('ab', [''])); - assert(!mm.any('a', [''])); assert(!mm.any('.', [''])); + assert(!mm.any('./', '')); + assert(!mm.any('./', [''])); + assert(!mm.any('a', '')); + assert(!mm.any('a', [''])); + assert(!mm.any('ab', '')); + assert(!mm.any('ab', [''])); }); }); @@ -20,56 +24,65 @@ describe('.any()', function() { it('should match literal paths', function() { assert(!mm.any('aaa', 'aa')); assert(mm.any('aaa', 'aaa')); + assert(mm.any('aaa', ['aa', 'aaa'])); assert(mm.any('aaa/bbb', 'aaa/bbb')); assert(mm.any('aaa/bbb', 'aaa[/]bbb')); + assert(mm.any('aaa/bbb', ['aaa\\bbb', 'aaa/bbb'])); + assert(mm.any('aaa\\bbb', ['aaa\\bbb', 'aaa/bbb'])); }); }); describe('stars (single pattern)', function() { - it('should return true when full file paths are matched:', function() { - assert(mm.any('a/b/c/xyz.md', 'a/b/c/*.md')); - assert(mm.any('a/bb/c/xyz.md', 'a/*/c/*.md')); - assert(mm.any('a/bbbb/c/xyz.md', 'a/*/c/*.md')); - assert(mm.any('a/bb.bb/c/xyz.md', 'a/*/c/*.md')); - assert(mm.any('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md')); - assert(mm.any('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md')); + it('should return true when one of the given patterns matches the string', function() { + assert(!mm.any('/ab', '*/*')); assert(!mm.any('a/.b', 'a/')); assert(!mm.any('a/b/c/d/e/z/c.md', 'b/c/d/e')); assert(!mm.any('a/b/z/.a', 'b/z')); - assert(mm.any('a/.b', 'a/.*')); - assert(mm.any('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); - assert(mm.any('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); - assert(mm.any('a/b/z/.a', 'a/*/z/.a')); assert(mm.any('.', '.')); - assert(mm.any('/ab', '*/*')); assert(mm.any('/ab', '/*')); assert(mm.any('/ab', '/??')); assert(mm.any('/ab', '/?b')); assert(mm.any('/cd', '/*')); assert(mm.any('a', 'a')); - assert(mm.any('ab', './*')); - assert(mm.any('ab/', './*/')); + assert(mm.any('a/.b', 'a/.*')); assert(mm.any('a/b', '?/?')); + assert(mm.any('a/b/c/d/e/j/n/p/o/z/c.md', 'a/**/j/**/z/*.md')); + assert(mm.any('a/b/c/d/e/z/c.md', 'a/**/z/*.md')); + assert(mm.any('a/b/c/xyz.md', 'a/b/c/*.md')); + assert(mm.any('a/b/c/xyz.md', ['foo', 'a/b/c/*.md'])); + assert(mm.any('a/b/z/.a', 'a/*/z/.a')); + assert(mm.any('a/bb.bb/aa/b.b/aa/c/xyz.md', 'a/**/c/*.md')); + assert(mm.any('a/bb.bb/aa/bb/aa/c/xyz.md', 'a/**/c/*.md')); + assert(mm.any('a/bb.bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.any('a/bb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.any('a/bbbb/c/xyz.md', 'a/*/c/*.md')); + assert(mm.any('aaa', ['foo', '*'])); assert(mm.any('ab', '*')); + assert(mm.any('ab', './*')); assert(mm.any('ab', 'ab')); + assert(mm.any('ab/', './*/')); }); it('should return false when the path does not match the pattern', function() { assert(!mm.any('/ab', '*/')); + assert(!mm.any('/ab', '*/*')); assert(!mm.any('/ab', '*/a')); assert(!mm.any('/ab', '/')); assert(!mm.any('/ab', '/?')); assert(!mm.any('/ab', '/a')); assert(!mm.any('/ab', '?/?')); assert(!mm.any('/ab', 'a/*')); + assert(!mm.any('a/.b', 'a/')); assert(!mm.any('a/b/c', 'a/*')); assert(!mm.any('a/b/c', 'a/b')); + assert(!mm.any('a/b/c/d/e/z/c.md', 'b/c/d/e')); + assert(!mm.any('a/b/z/.a', 'b/z')); assert(!mm.any('ab', '*/*')); - assert(!mm.any('ab/', '*/*')); assert(!mm.any('ab', '/a')); assert(!mm.any('ab', 'a')); assert(!mm.any('ab', 'b')); assert(!mm.any('ab', 'c')); + assert(!mm.any('ab/', '*/*')); assert(!mm.any('abcd', 'ab')); assert(!mm.any('abcd', 'bc')); assert(!mm.any('abcd', 'c')); @@ -102,13 +115,13 @@ describe('.any()', function() { }); it('should return false when full file paths are not matched:', function() { - assert(!mm.any('a/b/z/.a', 'b/a')); assert(!mm.any('a/.b', 'a/**/z/*.md')); - assert(!mm.any('a/b/z/.a', 'a/**/z/*.a')); - assert(!mm.any('a/b/z/.a', 'a/*/z/*.a')); assert(!mm.any('a/b/c/j/e/z/c.txt', 'a/**/j/**/z/*.md')); - assert(!mm.any('a/b/d/xyz.md', 'a/b/**/c{d,e}/**/xyz.md')); assert(!mm.any('a/b/c/xyz.md', 'a/b/**/c{d,e}/**/xyz.md')); + assert(!mm.any('a/b/d/xyz.md', 'a/b/**/c{d,e}/**/xyz.md')); + assert(!mm.any('a/b/z/.a', 'a/**/z/*.a')); + assert(!mm.any('a/b/z/.a', 'a/*/z/*.a')); + assert(!mm.any('a/b/z/.a', 'b/a')); }); }); @@ -116,11 +129,11 @@ describe('.any()', function() { it('should return true when any of the patterns match', function() { assert(mm.any('.', ['.', 'foo'])); assert(mm.any('a', ['a', 'foo'])); - assert(mm.any('ab', ['ab', 'foo'])); - assert(mm.any('ab', ['./*', 'foo', 'bar'])); assert(mm.any('ab', ['*', 'foo', 'bar'])); assert(mm.any('ab', ['*b', 'foo', 'bar'])); + assert(mm.any('ab', ['./*', 'foo', 'bar'])); assert(mm.any('ab', ['a*', 'foo', 'bar'])); + assert(mm.any('ab', ['ab', 'foo'])); }); it('should return false when none of the patterns match', function() { diff --git a/test/api.contains.js b/test/api.contains.js index 7f8b6e41..2b1642c2 100644 --- a/test/api.contains.js +++ b/test/api.contains.js @@ -189,18 +189,34 @@ describe('.contains()', function() { }); it('should match with common glob patterns', function() { - assert(mm.contains('a\\b\\c', 'a/*')); - assert(mm.contains('\\ab', '/a')); - assert(mm.contains('\\ab', '/*')); - assert(mm.contains('\\cd', '/*')); - assert(mm.contains('\\ab', '*/a')); assert(mm.contains('\\ab', '*/')); assert(mm.contains('\\ab', '*/*')); + assert(mm.contains('\\ab', '*/[a-z]*')); + assert(mm.contains('\\ab', '*/*[a-z]')); + assert(mm.contains('\\ab', '*/a')); assert(mm.contains('\\ab', '/')); + assert(mm.contains('\\ab', '/*')); + assert(mm.contains('\\ab', '/?')); assert(mm.contains('\\ab', '/??')); assert(mm.contains('\\ab', '/?b')); - assert(mm.contains('\\ab', '/?')); + assert(mm.contains('\\ab', '/a')); + assert(mm.contains('\\cd', '/*')); assert(mm.contains('a\\b', '?/?')); + assert(mm.contains('a\\b\\c', 'a/*')); + + assert(mm.contains('\\ab', '*/', {unixify: false})); + assert(mm.contains('\\ab', '*/*', {unixify: false})); + assert(mm.contains('\\ab', '*/[a-z]*', {unixify: false})); + assert(mm.contains('\\ab', '*/a', {unixify: false})); + assert(mm.contains('\\ab', '/', {unixify: false})); + assert(mm.contains('\\ab', '/*', {unixify: false})); + assert(mm.contains('\\ab', '/?', {unixify: false})); + assert(mm.contains('\\ab', '/??', {unixify: false})); + assert(mm.contains('\\ab', '/?b', {unixify: false})); + assert(mm.contains('\\ab', '/a', {unixify: false})); + assert(mm.contains('\\cd', '/*', {unixify: false})); + assert(mm.contains('a\\b', '?/?', {unixify: false})); + assert(mm.contains('a\\b\\c', 'a/*', {unixify: false})); }); it('should match files that contain the given extension:', function() { diff --git a/test/api.isMatch.js b/test/api.isMatch.js index fe518cfa..72de33c4 100644 --- a/test/api.isMatch.js +++ b/test/api.isMatch.js @@ -8,7 +8,7 @@ describe('.isMatch():', function() { it('should throw on bad args', function() { assert.throws(function() { mm.isMatch({}); - }, /expected pattern to be a string or regex/); + }, /expected a string: "{}"/); }); }); diff --git a/test/api.js b/test/api.js index 292bef63..b3cfedb1 100644 --- a/test/api.js +++ b/test/api.js @@ -73,6 +73,14 @@ describe('micromatch', function() { mm(fixtures, ['a*.txt'], ['a.txt']); mm(fixtures, ['*.txt'], ['a.txt']); }); + + it('should match literal brackets', function() { + mm(['a [b]'], 'a \\[b\\]', ['a [b]']); + mm(['a [b] c'], 'a [b] c', ['a [b] c']); + mm(['a [b]'], 'a \\[b\\]*', ['a [b]']); + mm(['a [bc]'], 'a \\[bc\\]*', ['a [bc]']); + mm(['a [b]', 'a [b].js'], 'a \\[b\\].*', ['a [b].js']); + }); }); describe('windows paths', function() { @@ -87,24 +95,32 @@ describe('micromatch', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; mm(fixtures, '(a/b)', ['a/b']); mm(fixtures, 'a/b', ['a/b']); + mm(fixtures, '(a/b)', ['a\\b'], {unixify: false}); + mm(fixtures, 'a/b', ['a\\b'], {unixify: false}); }); it('should return an array of matches for an array of literal strings', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; mm(fixtures, ['(a/b)', 'a/c'], ['a/b', 'a/c']); mm(fixtures, ['a/b', 'b/b'], ['a/b', 'b/b']); + mm(fixtures, ['(a/b)', 'a/c'], ['a\\b', 'a\\c'], {unixify: false}); + mm(fixtures, ['a/b', 'b/b'], ['a\\b', 'b\\b'], {unixify: false}); }); it('should support regex logical or', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c']; mm(fixtures, ['a/(a|c)'], ['a/a', 'a/c']); mm(fixtures, ['a/(a|b|c)', 'a/b'], ['a/a', 'a/b', 'a/c']); + mm(fixtures, ['a/(a|c)'], ['a\\a', 'a\\c'], {unixify: false}); + mm(fixtures, ['a/(a|b|c)', 'a/b'], ['a\\a', 'a\\b', 'a\\c'], {unixify: false}); }); it('should support regex ranges', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x\\y', 'a\\x']; mm(fixtures, 'a/[b-c]', ['a/b', 'a/c']); mm(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, 'a/[b-c]', ['a\\b', 'a\\c'], {unixify: false}); + mm(fixtures, 'a/[a-z]', ['a\\a', 'a\\b', 'a\\c', 'a\\x'], {unixify: false}); }); it('should support single globs (*)', function() { @@ -120,6 +136,17 @@ describe('micromatch', function() { mm(fixtures, ['a/*/*/*/*'], ['a/a/a/a/a']); mm(fixtures, ['a/*/a'], ['a/a/a']); mm(fixtures, ['a/*/b'], ['a/a/b']); + + mm(fixtures, ['*/*'], ['a\\a', 'a\\b', 'a\\c', 'a\\x', 'x\\y', 'z\\z'], {unixify: false}); + mm(fixtures, ['*/*/*'], ['a\\a\\a', 'a\\a\\b'], {unixify: false}); + mm(fixtures, ['*/*/*/*'], ['a\\a\\a\\a'], {unixify: false}); + mm(fixtures, ['*/*/*/*/*'], ['a\\a\\a\\a\\a'], {unixify: false}); + mm(fixtures, ['a/*'], ['a\\a', 'a\\b', 'a\\c', 'a\\x'], {unixify: false}); + mm(fixtures, ['a/*/*'], ['a\\a\\a', 'a\\a\\b'], {unixify: false}); + mm(fixtures, ['a/*/*/*'], ['a\\a\\a\\a'], {unixify: false}); + mm(fixtures, ['a/*/*/*/*'], ['a\\a\\a\\a\\a'], {unixify: false}); + mm(fixtures, ['a/*/a'], ['a\\a\\a'], {unixify: false}); + mm(fixtures, ['a/*/b'], ['a\\a\\b'], {unixify: false}); }); it('should support globstars (**)', function() { @@ -128,10 +155,17 @@ describe('micromatch', function() { mm(fixtures, ['a/**'], expected); mm(fixtures, ['a/**/*'], expected); mm(fixtures, ['a/**/**/*'], expected); + + mm(fixtures, ['a/**'], fixtures, {unixify: false}); + mm(fixtures, ['a/**/*'], fixtures, {unixify: false}); + mm(fixtures, ['a/**/**/*'], fixtures, {unixify: false}); }); it('should work with file extensions', function() { var fixtures = ['a.txt', 'a\\b.txt', 'a\\x\\y.txt', 'a\\x\\y\\z']; + mm(fixtures, ['a/**/*.txt'], ['a\\b.txt', 'a\\x\\y.txt'], {unixify: false}); + mm(fixtures, ['a/*/*.txt'], ['a\\x\\y.txt'], {unixify: false}); + mm(fixtures, ['a/*.txt'], ['a\\b.txt'], {unixify: false}); mm(fixtures, ['a/**/*.txt'], ['a/b.txt', 'a/x/y.txt']); mm(fixtures, ['a/*/*.txt'], ['a/x/y.txt']); mm(fixtures, ['a/*.txt'], ['a/b.txt']); @@ -148,6 +182,14 @@ describe('micromatch', function() { mm(fixtures, ['!a/b', '!a/c'], ['a', 'a/a', 'b/a', 'b/b', 'b/c']); mm(fixtures, ['!a/(b)'], ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); mm(fixtures, ['!(a/b)'], ['a', 'a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + + mm(fixtures, ['!a/b'], ['a', 'a\\a', 'a\\c', 'b\\a', 'b\\b', 'b\\c'], {unixify: false}); + mm(fixtures, ['*/*', '!a/b', '!*/c'], ['a\\a', 'b\\a', 'b\\b'], {unixify: false}); + mm(fixtures, ['!*/c'], ['a', 'a\\a', 'a\\b', 'b\\a', 'b\\b'], {unixify: false}); + mm(fixtures, ['!a/b', '!*/c'], ['a', 'a\\a', 'b\\a', 'b\\b'], {unixify: false}); + mm(fixtures, ['!a/b', '!a/c'], ['a', 'a\\a', 'b\\a', 'b\\b', 'b\\c'], {unixify: false}); + mm(fixtures, ['!a/(b)'], ['a', 'a\\a', 'a\\c', 'b\\a', 'b\\b', 'b\\c'], {unixify: false}); + mm(fixtures, ['!(a/b)'], ['a', 'a\\a', 'a\\c', 'b\\a', 'b\\b', 'b\\c'], {unixify: false}); }); }); }); diff --git a/test/api.match.js b/test/api.match.js index ef749b6d..f66f3110 100644 --- a/test/api.match.js +++ b/test/api.match.js @@ -1,5 +1,6 @@ 'use strict'; +var path = require('path'); var mm = require('./support/match'); describe('.match method', function() { @@ -35,34 +36,56 @@ describe('.match method', function() { }); }); - describe('unix paths', function() { + describe('windows paths', function() { + var sep = path.sep; + beforeEach(function() { + path.sep = '\\'; + }); + + afterEach(function() { + path.sep = sep; + }); + it('should return an array of matches for a literal string', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; + mm(fixtures, '(a/b)', ['a\\b'], {unixify: false}); mm(fixtures, '(a/b)', ['a/b']); + mm(fixtures, 'a/b', ['a\\b'], {unixify: false}); mm(fixtures, 'a/b', ['a/b']); }); it('should support regex logical or', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c']; + mm(fixtures, 'a/(a|c)', ['a\\a', 'a\\c'], {unixify: false}); mm(fixtures, 'a/(a|c)', ['a/a', 'a/c']); + mm(fixtures, 'a/(a|b|c)', ['a\\a', 'a\\b', 'a\\c'], {unixify: false}); mm(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); }); it('should support regex ranges', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x\\y', 'a\\x']; + mm(fixtures, 'a/[b-c]', ['a\\b', 'a\\c'], {unixify: false}); mm(fixtures, 'a/[b-c]', ['a/b', 'a/c']); + mm(fixtures, 'a/[a-z]', ['a\\a', 'a\\b', 'a\\c', 'a\\x'], {unixify: false}); mm(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); }); it('should support negation patterns', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; mm(fixtures, '!*/*', []); + mm(fixtures, '!*/b', ['a\\a', 'a\\c', 'b\\a', 'b\\c'], {unixify: false}); mm(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); + mm(fixtures, '!a/*', ['b\\a', 'b\\b', 'b\\c'], {unixify: false}); mm(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); + mm(fixtures, '!a/b', ['a\\a', 'a\\c', 'b\\a', 'b\\b', 'b\\c'], {unixify: false}); mm(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, '!a/(b)', ['a\\a', 'a\\c', 'b\\a', 'b\\b', 'b\\c'], {unixify: false}); mm(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm(fixtures, '!a/(*)', ['b\\a', 'b\\b', 'b\\c'], {unixify: false}); mm(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); + mm(fixtures, '!(*/b)', ['a\\a', 'a\\c', 'b\\a', 'b\\c'], {unixify: false}); mm(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); + mm(fixtures, '!(a/b)', ['a\\a', 'a\\c', 'b\\a', 'b\\b', 'b\\c'], {unixify: false}); mm(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); }); }); diff --git a/test/api.matcher.js b/test/api.matcher.js index 3e1ae4a0..415236b6 100644 --- a/test/api.matcher.js +++ b/test/api.matcher.js @@ -1,5 +1,6 @@ 'use strict'; +var path = require('path'); var mm = require('./support/match'); describe('.match method', function() { @@ -68,35 +69,45 @@ describe('.match method', function() { }); }); - describe('unix paths', function() { + describe('windows paths', function() { + var sep = path.sep; + beforeEach(function() { + path.sep = '\\'; + }); + + afterEach(function() { + path.sep = sep; + }); + it('should return an array of matches for a literal string', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; - mm.matcher(fixtures, '(a/b)', ['a/b']); - mm.matcher(fixtures, 'a/b', ['a/b']); + mm.matcher(fixtures, '(a/b)', ['a\\b']); + mm.matcher(fixtures, 'a/b', ['a\\b']); }); it('should support regex logical or', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c']; - mm.matcher(fixtures, 'a/(a|c)', ['a/a', 'a/c']); - mm.matcher(fixtures, 'a/(a|b|c)', ['a/a', 'a/b', 'a/c']); + mm.matcher(fixtures, 'a/(a|c)', ['a\\a', 'a\\c']); + mm.matcher(fixtures, 'a/(a|b|c)', ['a\\a', 'a\\b', 'a\\c']); }); it('should support regex ranges', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'a\\x\\y', 'a\\x']; - mm.matcher(fixtures, 'a/[b-c]', ['a/b', 'a/c']); - mm.matcher(fixtures, 'a/[a-z]', ['a/a', 'a/b', 'a/c', 'a/x']); + mm.matcher(fixtures, 'a/[b-c]', ['a\\b', 'a\\c']); + mm.matcher(fixtures, 'a/[a-z]', ['a\\a', 'a\\b', 'a\\c', 'a\\x']); }); it('should support negation patterns', function() { var fixtures = ['a\\a', 'a\\b', 'a\\c', 'b\\a', 'b\\b', 'b\\c']; mm.matcher(fixtures, '!*/*', []); - mm.matcher(fixtures, '!*/b', ['a/a', 'a/c', 'b/a', 'b/c']); - mm.matcher(fixtures, '!a/*', ['b/a', 'b/b', 'b/c']); - mm.matcher(fixtures, '!a/b', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); - mm.matcher(fixtures, '!a/(b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); - mm.matcher(fixtures, '!a/(*)', ['b/a', 'b/b', 'b/c']); - mm.matcher(fixtures, '!(*/b)', ['a/a', 'a/c', 'b/a', 'b/c']); - mm.matcher(fixtures, '!(a/b)', ['a/a', 'a/c', 'b/a', 'b/b', 'b/c']); + mm.matcher(fixtures, '!*/b', ['a\\a', 'a\\c', 'b\\a', 'b\\c']); + mm.matcher(fixtures, '!a/*', ['b\\a', 'b\\b', 'b\\c']); + mm.matcher(fixtures, '!a/b', ['a\\a', 'a\\c', 'b\\a', 'b\\b', 'b\\c']); + mm.matcher(fixtures, '!a/(b)', ['a\\a', 'a\\c', 'b\\a', 'b\\b', 'b\\c']); + mm.matcher(fixtures, '!a/(*)', ['b\\a', 'b\\b', 'b\\c']); + mm.matcher(fixtures, '!(*/b)', ['a\\a', 'a\\c', 'b\\a', 'b\\c']); + mm.matcher(fixtures, '!(a/b)', ['a\\a', 'a\\c', 'b\\a', 'b\\b', 'b\\c']); + path.sep = sep; }); }); }); diff --git a/test/bash.js b/test/bash.js index c5bc5697..05081854 100644 --- a/test/bash.js +++ b/test/bash.js @@ -10,7 +10,7 @@ var mm = require('./support/match'); */ // from the Bash 4.3 specification/unit tests -var fixtures = ['a', 'b', 'c', 'd', 'abc', 'abd', 'abe', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'Beware', 'bdir/', '*', '\\*']; +var fixtures = ['*', '\\*', 'a', 'abc', 'abd', 'abe', 'b', 'bb', 'bcd', 'bdir/', 'Beware', 'c', 'ca', 'cb', 'd', 'dd', 'de']; describe('bash options and features:', function() { describe('failglob:', function() { @@ -34,6 +34,9 @@ describe('bash options and features:', function() { it('should use quoted characters as literals:', function() { mm(fixtures, '\\*', {nonull: true}, ['*', '\\*']); + mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*']); + mm(fixtures, '\\*', {nonull: true, unescape: true, unixify: false}, ['*', '\\*']); + mm(fixtures, '\\^', {nonull: true}, ['\\^']); mm(fixtures, '\\^', []); @@ -43,7 +46,9 @@ describe('bash options and features:', function() { mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['a\\*', '*', '\\*']); mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*']); + mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true, unixify: false}, ['a*', '*', '\\*']); mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*']); + mm(fixtures, ['a\\*', '\\*'], {unescape: true, unixify: false}, ['*', '\\*']); mm(fixtures, ['a\\*', '\\*'], ['*', '\\*']); mm(fixtures, ['a\\*'], {nonull: true}, ['a\\*']); @@ -72,15 +77,17 @@ describe('bash options and features:', function() { it('should support character classes', function() { var f = fixtures.slice(); f.push('baz', 'bzz', 'BZZ', 'beware', 'BewAre'); - mm(f, '[a-y]*[^c]', ['abd', 'abe', 'baz', 'beware', 'bzz', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); mm(f, 'a*[^c]', ['abd', 'abe']); mm(['a-b', 'aXb'], 'a[X-]b', ['a-b', 'aXb']); + mm(f, '[a-y]*[^c]', ['*', 'a', 'b', 'd', 'abd', 'abe', 'baz', 'beware', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); + mm(f, '[a-y]*[^c]', {bash: true}, ['abd', 'abe', 'baz', 'beware', 'bzz', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '\\*']); mm(['a*b/ooo'], 'a\\*b/*', ['a*b/ooo']); mm(['a*b/ooo'], 'a\\*?/*', ['a*b/ooo']); mm(f, 'a[b]c', ['abc']); mm(f, 'a["b"]c', ['abc']); mm(f, 'a[\\\\b]c', ['abc']); + mm(f, 'a[\\b]c', []); mm(f, 'a[b-d]c', ['abc']); mm(f, 'a?c', ['abc']); mm(['a-b'], 'a[]-]b', ['a-b']); diff --git a/test/bash.spec.js b/test/bash.spec.js index 6e9a0aaa..9cbbcf35 100644 --- a/test/bash.spec.js +++ b/test/bash.spec.js @@ -4,29 +4,32 @@ var path = require('path'); var assert = require('assert'); var forOwn = require('for-own'); var parse = require('./support/parse'); -var nm = require('./support/matcher'); -var fixtures = parse('*.txt', {cwd: path.join(__dirname, 'fixtures')}); +var mm = require('./support/matcher'); -forOwn(fixtures, function(lines, filename) { - describe(filename + ':', function() { - lines.forEach(function(line) { - if (typeof line === 'string') { - console.log(line); - return; - } +describe('bash.spec', function() { + var fixtures = parse('*.txt', {cwd: path.join(__dirname, 'fixtures')}); - var fixture = line[0]; - var pattern = line[1]; - var expected = line[2]; + forOwn(fixtures, function(lines, filename) { + describe(filename + ':', function() { + lines.forEach(function(line) { + if (typeof line === 'string') { + console.log(line); + return; + } - var title = '"' + fixture - + '" should' + (expected ? '' : ' not') - + ' match "' + pattern + '"'; + var fixture = line[0]; + var pattern = line[1]; + var expected = line[2]; - it(title, function() { - var msg = fixture + (expected ? ' === ' : ' !== ') + pattern; - // assert.equal(nm.isMatch(fixture, pattern), nm.mm.isMatch(fixture, pattern), msg); - assert.equal(nm.isMatch(fixture, pattern), expected, msg); + var title = '"' + fixture + + '" should' + (expected ? '' : ' not') + + ' match "' + pattern + '"'; + + it(title, function() { + var msg = fixture + (expected ? ' === ' : ' !== ') + pattern; + // assert.equal(mm.isMatch(fixture, pattern), mm.mm.isMatch(fixture, pattern), msg); + assert.equal(mm.isMatch(fixture, pattern), expected, msg); + }); }); }); }); diff --git a/test/braces.js b/test/braces.js index c987c02e..032f7d61 100644 --- a/test/braces.js +++ b/test/braces.js @@ -7,6 +7,7 @@ 'use strict'; +var assert = require('assert'); var extend = require('extend-shallow'); var mm = require('..'); @@ -14,6 +15,24 @@ function optimize(pattern, options) { return mm.braces(pattern, extend({optimize: true}, options)); } +describe('expanded', function() { + it('should handle extglobs in braces', function() { + var fixtures = [ + 'a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'bc', 'cb', 'bc,d', + 'c,db', 'c,d', 'd)', '(b|c', '*(b|c', 'b|c', 'b|cc', 'cb|c', + 'x(a|b|c)', 'x(a|c)', '(a|b|c)', '(a|c)' + ]; + + assert.deepEqual(mm(fixtures, ['a', '*(b|c,d)'], {expand: true}), ['a', 'b', 'bc,d', 'c,db', 'c,d']); + assert.deepEqual(mm(fixtures, '{a,*(b|c,d)}', {expand: true}), ['a', 'b', 'bc,d', 'c,db', 'c,d']); + + var expected = ['a', 'b', 'c', 'ab', 'ac', 'bc', 'cb']; + assert.deepEqual(mm(fixtures, '*(a|b|c)'), expected); + assert.deepEqual(mm(fixtures, '*(a|{b|c,c})'), expected); + assert.deepEqual(mm(fixtures, '*(a|{b|c,c})', {expand: true}), expected); + }); +}); + describe('optimized', function() { describe('sets', function() { describe('invalid sets', function() { diff --git a/test/brackets.js b/test/brackets.js index 13c86ac8..c820e4d0 100644 --- a/test/brackets.js +++ b/test/brackets.js @@ -22,7 +22,7 @@ describe('brackets', function() { assert.equal(create('[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]'), '[a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9\\x21-\\x7Ea-z\\x20-\\x7E \\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~ \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]'); assert.equal(create('[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]'), '[^a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9a-z \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]'); assert.equal(create('[a-c[:digit:]x-z]'), '[a-c0-9x-z]'); - assert.equal(create('[_[:alpha:]][_[:alnum:]][_[:alnum:]]*'), '[_a-zA-Z][_a-zA-Z0-9][_a-zA-Z0-9]*?\\/?', []); + assert.equal(create('[_[:alpha:]][_[:alnum:]][_[:alnum:]]*'), '[_a-zA-Z][_a-zA-Z0-9][_a-zA-Z0-9]*?(\\/|$)', []); }); }); @@ -232,9 +232,16 @@ describe('brackets', function() { assert(!mm.isMatch('?*+', '[[:punct:]]')); }); - it('should only match zero or more characters', function() { + it('should only match one or more characters', function() { assert(mm.isMatch('?*+', '[[:punct:]]*')); - assert(mm.isMatch('', '[[:punct:]]*')); + assert(mm.isMatch('*', '[[:punct:]]*')); + assert(mm.isMatch('+', '[[:punct:]]*')); + assert(mm.isMatch('?', '[[:punct:]]*')); + assert(mm.isMatch('?abc', '[[:punct:]]*')); + assert(mm.isMatch('*abc', '[[:punct:]]*')); + assert(mm.isMatch('+abc', '[[:punct:]]*')); + assert(!mm.isMatch('abc+abc', '[[:punct:]]*')); + assert(!mm.isMatch('', '[[:punct:]]*')); }); it('invalid character class expressions are just characters to be matched', function() { diff --git a/test/comparison.isMatch.js b/test/comparison.isMatch.js index 19e073c9..98bd2921 100644 --- a/test/comparison.isMatch.js +++ b/test/comparison.isMatch.js @@ -1,114 +1,12 @@ 'use strict'; var isTravis = process.env.CI || process.env.TRAVIS; -var isWindows = require('is-windows'); var assert = require('assert'); -var bash = require('bash-match'); -var mm = require('minimatch'); -var nm = require('..'); - -var fixtures = [ - // common file patterns - 'abc', - 'abd', - 'abbbz', - 'a', - 'a.md', - 'a/b/c.md', - 'a/b/.c.md', - '!a/b/.c.md', - - '!a.js', - 'z.js', - 'za.js', - 'a/b/c/z.js', - 'a/b/c/d/e/f/z.js', - - // directories - 'a/', - 'a/b', - 'a/cb', - 'a/bb', - 'a/b/c/d', - 'a/b/c/d/', - - // cwd - '.', - './', - - // ancestor directories - '..', - '../c', - '../c', - './../c', - '/..', - '/../c', - - // bad paths - './a/../c', - '/a/../c', - 'a/../c', - - // dot files - './.b/.c', - './b/.c', - '../.b/.c', - '../b/.c', - '.b', - '.b/', - '.b', - '.b.c', - '.b.c/', - '.b/', - '.b/c', - 'b/.c', - - // dot directories - 'b/.c/', - '.b/.c', -]; +var isWindows = require('is-windows'); +var mi = require('./support/matcher'); -var patterns = [ - '!**/*.md', - '!*.*', - '!*.js', - '!a/*?b', - '!a/?', - '!a/?*b', - '!a/??b', - '!a/?b', - '*', - '**', - '**/', - '**/*', - '**/*.md', - '**/?.md', - '**/*?.md', - '**/.?.md', - '**/z*.js', - '*.js', - '*/*', - '/**', - '/**/', - '/**/*', - '?', - '?/', - '?/.?', - '?/.?*', - '?/?', - '??', - '??/??', - 'a/**/', - 'a/**/b', - 'a/**b', - 'a/*?b', - 'a/?', - 'a/?*b', - 'a/??b', - 'a/?b', - 'a/b/c/**/*.js', - 'a/b/c/*.js', -]; +var fixtures = require('./_fixtures'); +var patterns = require('./_patterns'); describe('.isMatch', function() { if (isWindows() || isTravis) { @@ -117,44 +15,76 @@ describe('.isMatch', function() { } patterns.forEach(function(pattern) { + // if (pattern.slice(0, 3) !== '!**') return; + // if (pattern.slice(0, 3) !== '!**') return; + fixtures.forEach(function(fixture) { + // if (fixture !== '!a/b/c') return; + it('should match ' + fixture + ' with ' + pattern, function() { - var mmRes = mm(fixture, pattern); - var nmRes = nm.isMatch(fixture, pattern); - var bRes = bash.isMatch(fixture, pattern); - var actual = nmRes === bRes || nmRes === mmRes; + var miRes = mi.isMatch(fixture, pattern); + var mmRes = mi.mm.isMatch(fixture, pattern); + var actual = miRes === mmRes; // minimatch is wrong on these - if (actual !== nmRes && /^\?/.test(pattern)) { - actual = true; + if (actual === false) { + // tie-breaker + if (miRes === mi.mm.makeRe(pattern).test(fixture)) { + actual = true; + } else if (/^\?/.test(pattern)) { + actual = true; + } else if (!isWindows() && !isTravis) { + actual = miRes === mi.bash.isMatch(fixture, pattern); + } else { + this.skip(); + return; + } } assert(actual, fixture + ' ' + pattern); }); it('should match ' + fixture + ' with ' + pattern + ' and {dot: true}', function() { - var mmRes = mm(fixture, pattern, {dot: true}); - var nmRes = nm.isMatch(fixture, pattern, {dot: true}); - var bRes = bash.isMatch(fixture, pattern, {dot: true}); - var actual = nmRes === bRes || nmRes === mmRes; + var miRes = mi.isMatch(fixture, pattern, {dot: true}); + var mmRes = mi.mm.isMatch(fixture, pattern, {dot: true}); + var actual = miRes === mmRes; // minimatch is wrong on these - if (actual !== nmRes && /^\?/.test(pattern)) { - actual = true; + if (actual === false) { + // tie-breaker (minimatch is inconsistent with regex and methods) + if (miRes === mi.mm.makeRe(pattern, {dot: true}).test(fixture)) { + actual = true; + } else if (/^\?/.test(pattern) || /^\.\//.test(fixture)) { + actual = true; + } else if (!isWindows() && !isTravis) { + actual = miRes === mi.bash.isMatch(fixture, pattern, {dot: true}); + } else { + this.skip(); + return; + } } assert(actual, fixture + ' ' + pattern); }); it('should match ' + fixture + ' with ' + pattern + ' and {nonegate: true}', function() { - var mmRes = mm(fixture, pattern, {nonegate: true}); - var nmRes = nm.isMatch(fixture, pattern, {nonegate: true}); - var bRes = bash.isMatch(fixture, pattern, {nonegate: true}); - var actual = nmRes === bRes || nmRes === mmRes; + var miRes = mi.isMatch(fixture, pattern, {nonegate: true}); + var mmRes = mi.mm.isMatch(fixture, pattern, {nonegate: true}); + var actual = miRes === mmRes; // minimatch is wrong on these - if (actual !== nmRes && /^\?/.test(pattern)) { - actual = true; + if (actual === false) { + // tie-breaker + if (miRes === mi.mm.makeRe(pattern, {nonegate: true}).test(fixture)) { + actual = true; + } else if (/^\?/.test(pattern) || /^\!/.test(fixture)) { + actual = true; + } else if (!isWindows() && !isTravis) { + actual = miRes === mi.bash.isMatch(fixture, pattern); + } else { + this.skip(); + return; + } } assert(actual, fixture + ' ' + pattern); diff --git a/test/comparison.makeRe.js b/test/comparison.makeRe.js index a4717665..4be3004f 100644 --- a/test/comparison.makeRe.js +++ b/test/comparison.makeRe.js @@ -5,87 +5,10 @@ var isWindows = require('is-windows'); var assert = require('assert'); var bash = require('bash-match'); var mm = require('minimatch'); -var nm = require('..'); +var mi = require('./support/matcher'); -var fixtures = [ - // common file patterns - 'abc', - 'abd', - 'abbbz', - 'a', - 'a.md', - 'a/b/c.md', - - 'z.js', - 'za.js', - 'a/b/c/z.js', - 'a/b/c/d/e/f/z.js', - - // directories - 'a/', - 'a/b', - 'a/cb', - 'a/bb', - 'a/b/c/d', - 'a/b/c/d/', - - // cwd - '.', - './', - - // ancestor directories - '..', - '../c', - '../c', - './../c', - '/..', - '/../c', - - // bad paths - './a/../c', - '/a/../c', - 'a/../c', - - // dot files - './.b/.c', - './b/.c', - '../.b/.c', - '../b/.c', - '.b', - '.b/', - '.b', - '.b.c', - '.b.c/', - '.b/', - '.b/c', - 'b/.c', - - // dot directories - 'b/.c/', - '.b/.c', -]; - -var patterns = [ - '!**/*.md', - '!*.*', - '!*.js', - '*', - '**', - '**/', - '**/*', - '**/*.md', - '**/z*.js', - '*.js', - '*/*', - '/**', - '/**/', - '/**/*', - 'a/**/', - 'a/**/b', - 'a/**b', - 'a/b/c/**/*.js', - 'a/b/c/*.js', -]; +var fixtures = require('./_fixtures'); +var patterns = require('./_patterns'); describe('.makeRe', function() { if (isWindows() || isTravis) { @@ -94,20 +17,76 @@ describe('.makeRe', function() { } patterns.forEach(function(pattern) { + // if (pattern !== 'a/b/c/**/*.js') return; + fixtures.forEach(function(fixture) { + // if (fixture !== 'a/b/c/z.js') return; + it('should match ' + fixture + ' with ' + pattern, function() { - var mmRes = mm(fixture, pattern); - var nmRes = nm.makeRe(pattern).test(fixture); - var bRes = bash.isMatch(fixture, pattern); + var mmRes = mm.makeRe(pattern).test(fixture); + var miRes = mi.makeRe(pattern).test(fixture); + var actual = miRes === mmRes; + + // minimatch is wrong on these + if (actual === false) { + // tie-breaker + if (miRes === mm(fixture, pattern) || /^\?/.test(pattern)) { + actual = true; + } else if (!isWindows() && !isTravis) { + actual = miRes === mi.bash.isMatch(fixture, pattern); + } else { + this.skip(); + return; + } + } - assert(nmRes === bRes || nmRes === mmRes, fixture + ' ' + pattern); + assert(actual, fixture + ' ' + pattern); }); it('should match ' + fixture + ' with ' + pattern + ' and {dot: true}', function() { - var mmRes = mm(fixture, pattern, {dot: true}); - var nmRes = nm.makeRe(pattern, {dot: true}).test(fixture); - var bRes = bash.isMatch(fixture, pattern, {dot: true}); - assert(nmRes === bRes || nmRes === mmRes, fixture + ' ' + pattern); + var mmRes = mm.makeRe(pattern, {dot: true}).test(fixture); + var miRes = mi.makeRe(pattern, {dot: true}).test(fixture); + var actual = miRes === mmRes; + + // minimatch is wrong on these + if (actual === false) { + // tie-breaker + if (miRes === mm(fixture, pattern, {dot: true})) { + actual = true; + } else if (/^\?/.test(pattern) || /^\.\//.test(fixture)) { + actual = true; + } else if (!isWindows() && !isTravis) { + actual = miRes === mi.bash.isMatch(fixture, pattern, {dot: true}); + } else { + this.skip(); + return; + } + } + + assert(actual, fixture + ' ' + pattern); + }); + + it('should match ' + fixture + ' with ' + pattern + ' and {nonegate: true}', function() { + var mmRes = mm.makeRe(pattern, {nonegate: true}).test(fixture); + var miRes = mi.makeRe(pattern, {nonegate: true}).test(fixture); + var actual = miRes === mmRes; + + // minimatch is wrong on these + if (actual === false) { + // tie-breaker + if (miRes === mm(fixture, pattern, {nonegate: true})) { + actual = true; + } else if (/^\?/.test(pattern) || /^\!/.test(fixture)) { + actual = true; + } else if (!isWindows() && !isTravis) { + actual = miRes === mi.bash.isMatch(fixture, pattern, {nonegate: true}); + } else { + this.skip(); + return; + } + } + + assert(actual, fixture + ' ' + pattern); }); }); }); diff --git a/test/dotfiles.js b/test/dotfiles.js index 6bcbb45f..690836b8 100644 --- a/test/dotfiles.js +++ b/test/dotfiles.js @@ -41,6 +41,7 @@ describe('dotfiles', function() { mm('.dot', '.d?t', ['.dot']); assert(!mm.isMatch('.bar.baz', '.*.*/')); + assert(!mm.isMatch('/.dot', '*/[.]dot')); assert(mm.isMatch('.bar.baz/', '.*.*')); assert(mm.isMatch('.bar.baz', '.*.*')); assert(mm.isMatch('.bar.baz', '.*.baz')); @@ -52,7 +53,6 @@ describe('dotfiles', function() { assert(mm.isMatch('/.dot', '**/.[d]ot')); assert(mm.isMatch('/.dot', '**/.dot*')); assert(mm.isMatch('/.dot', '**/[.]dot')); - assert(mm.isMatch('/.dot', '*/[.]dot')); assert(mm.isMatch('/.dot', '/[.]dot')); assert(mm.isMatch('a/.dot', '**/.[d]ot')); assert(mm.isMatch('a/.dot', '*/.[d]ot')); @@ -117,6 +117,12 @@ describe('dotfiles', function() { assert(mm.isMatch('a/b/.dot', '?dot', {dot: true, matchBase: true})); }); + it('should work when the path has leading `./`', function() { + assert(!mm.isMatch('./b/.c', '**')); + assert(mm.isMatch('./b/.c', '**', {dot: true})); + assert(mm.isMatch('./b/.c', '**', {dot: true, matchBase: true})); + }); + it('should not match dotfiles when `options.dot` is false', function() { assert(!mm.isMatch('a/b/.dot', '**/*dot', {dot: false})); assert(!mm.isMatch('a/b/.dot', '**/?dot', {dot: false})); diff --git a/test/extglobs.js b/test/extglobs.js index 12aba007..a3db74f6 100644 --- a/test/extglobs.js +++ b/test/extglobs.js @@ -1,21 +1,20 @@ 'use strict'; +var path = require('path'); var assert = require('assert'); var mm = require('./support/match'); +var sep = path.sep; /** * These tests were converted directly from bash 4.3 and 4.4 unit tests. */ describe('extglobs', function() { - it('should throw on imbalanced sets when `options.strictErrors` is true', function() { - assert.throws(function() { - mm.isMatch('a((b', 'a(b', {strictErrors: true}); - }, 'row:1 col:2 missing opening parens: "a(b"'); - - assert.throws(function() { - mm.isMatch('a((b', 'a(*b', {strictErrors: true}); - }, 'row:1 col:2 missing opening parens: "a(*b"'); + beforeEach(function() { + path.sep = '\\'; + }); + afterEach(function() { + path.sep = sep; }); it('should match extglobs ending with statechar', function() { @@ -51,6 +50,8 @@ describe('extglobs', function() { var arr = ['a', 'b', 'aa', 'ab', 'bb', 'ac', 'aaa', 'aab', 'abb', 'ccc']; mm(arr, '!(a)*', ['b', 'bb', 'ccc']); mm(arr, 'a!(b)*', ['a', 'aa', 'aaa', 'aab', 'ac']); + mm(['foo'], '!(foo)', []); + mm(['foo.js'], '!(foo).js', []); }); it('should support qmark matching', function() { @@ -116,7 +117,7 @@ describe('extglobs', function() { mm(['abd', 'acd', 'ac', 'ab'], 'a!(@(b|B))', ['acd', 'abd', 'ac']); mm(['abd', 'acd'], 'a!(@(b|B))d', ['acd']); mm(['abd', 'acd'], 'a[b*(foo|bar)]d', ['abd']); - mm(['abcx', 'abcz', 'bbc', 'aaz', 'aaaz'], '[a*(]*z', ['aaz', 'aaaz', 'abcz']); + mm(['abcx', 'abcz', 'bbc', 'aaz', 'aaaz'], '[a*(]*z', ['aaz', 'aaaz']); }); it('simple kleene star tests', function() { @@ -141,17 +142,20 @@ describe('extglobs', function() { mm(['def', 'ef'], '()ef', ['ef']); }); - it('should match escaped parens', function() { + it('should match parens', function() { var arr = ['a(b', 'a\\(b', 'a((b', 'a((((b', 'ab']; mm(arr, 'a(b', ['a(b']); - mm(arr, 'a\\(b', ['a(b', 'a\\(b']); mm(arr, 'a(*b', ['a(b', 'a((b', 'a((((b']); + mm(['a(b', 'a((b', 'a((((b', 'ab'], 'a\\(b', ['a(b']); + mm(['a(b', 'a((b', 'a((((b', 'ab'], 'a(b', ['a(b']); }); it('should match escaped backslashes', function() { - mm(['a(b', 'a\\(b', 'a((b', 'a((((b', 'ab'], 'a\\\\(b', ['a\\(b']); - mm(['a\\b', 'a/b', 'ab'], 'a/b', ['a/b']); - mm(['a\\z', 'a/z', 'az'], 'a\\z', ['a/z']); + mm(['a\\b', 'a/b', 'ab'], 'a\\b', ['a\\b'], {unixify: false}); + mm(['a\\\\z', 'a\\z', 'a\\z', 'az'], 'a\\\\z', ['a\\\\z'], {unixify: false}); + + mm(['a\\b', 'a/b', 'ab'], 'a\\b', ['a/b']); + mm(['a\\\\z', 'a\\z', 'a\\z', 'az'], 'a\\\\z', ['a/z']); }); }); diff --git a/test/fixtures/patterns.js b/test/fixtures/patterns.js index cd199854..f49f89ed 100644 --- a/test/fixtures/patterns.js +++ b/test/fixtures/patterns.js @@ -8,6 +8,7 @@ var fixtures = ['a', 'b', 'c', 'd', 'abc', 'abd', 'abe', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/', 'bdir/cfile']; +// pattern | expected | options | fixtures module.exports = [ 'http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test', ['a*', ['a', 'abc', 'abd', 'abe']], @@ -40,7 +41,7 @@ module.exports = [ 'character classes', ['[a-c]b*', ['abc', 'abd', 'abe', 'bb', 'cb']], - ['[a-y]*[^c]', ['abd', 'abe', 'bb', 'bcd', 'bdir/', 'ca', 'cb', 'dd', 'de']], + ['[a-y]*[^c]', ['abd', 'abe', 'bb', 'bcd', 'bdir/', 'ca', 'cb', 'dd', 'de'], {bash: true}], ['a*[^c]', ['abd', 'abe']], function() { fixtures.push('a-b', 'aXb'); @@ -133,7 +134,7 @@ module.exports = [ 'braces: onestar/twostar', ['{/*,*}', [], {null: true}, ['/asdf/asdf/asdf']], - // ['{/?,*}', ['/a', 'bb'], {null: true}, ['/a', '/b/b', '/a/b/c', 'bb']], + ['{/?,*}', ['/a', 'bb'], {null: true}, ['/a', '/b/b', '/a/b/c', 'bb']], 'dots should not match unless requested', ['**', ['a/b'], {}, ['a/b', 'a/.d', '.a/.d']], @@ -158,50 +159,57 @@ module.exports = [ [ '.a/.d', 'a/.d', 'a/b'] ], - // // 'paren sets cannot contain slashes', - // // ['*(a/b)', ['*(a/b)'], {nonull: true}, ['a/b']], - - // // brace sets trump all else. - // // - // // invalid glob pattern. fails on bash4 and bsdglob. - // // however, in this implementation, it's easier just - // // to do the intuitive thing, and let brace-expansion - // // actually come before parsing any extglob patterns, - // // like the documentation seems to say. - // // - // // XXX: if anyone complains about this, either fix it - // // or tell them to grow up and stop complaining. - // // - // // bash/bsdglob says this: - // // , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]] - // // but we do this instead: - // // ['*(a|{b),c)}', ['a', 'ab', 'ac'], {}, ['a', 'ab', 'ac', 'ad']], + // '~~paren sets cannot contain slashes~~', + // 'paren sets _can_ contain slashes', + ['*(a/b)', ['a/b'], {}, ['a/b']], + + // brace sets trump all else. + // + // invalid glob pattern. fails on bash4 and bsdglob. + // however, in this implementation, it's easier just + // to do the intuitive thing, and let brace-expansion + // actually come before parsing any extglob patterns, + // like the documentation seems to say. + // + // XXX: if anyone complains about this, either fix it + // or tell them to grow up and stop complaining. + // + // bash/bsdglob says this: + // ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]], + // but we do this instead: + ['*(a|{b),c)}', ['a', 'ab', 'ac'], {expand: true}, ['a', 'ab', 'ac', 'ad']], // test partial parsing in the presence of comment/negation chars ['[!a*', ['[!ab'], {}, ['[!ab', '[ab']], -// // crazy nested {,,} and *(||) tests. -// function() { -// fixtures = [ -// 'a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'bc', 'cb', 'bc,d', -// 'c,db', 'c,d', 'd)', '(b|c', '*(b|c', 'b|c', 'b|cc', 'cb|c', -// 'x(a|b|c)', 'x(a|c)', '(a|b|c)', '(a|c)' -// ]; -// }, -// ['*(a|{b,c})', ['a', 'b', 'c', 'ab', 'ac']], -// ['{a,*(b|c,d)}', ['a', '(b|c', '*(b|c', 'd)']], -// // a -// // *(b|c) -// // *(b|d) -// ['{a,*(b|{c,d})}', ['a', 'b', 'bc', 'cb', 'c', 'd']], -// ['*(a|{b|c,c})', ['a', 'b', 'c', 'ab', 'ac', 'bc', 'cb']], - -// // test various flag settings. -// [ -// '*(a|{b|c,c})', -// ['x(a|b|c)', 'x(a|c)', '(a|b|c)', '(a|c)'], -// { noext: true } -// ], + // like: {a,b|c\\,d\\\|e} except it's unclosed, so it has to be escaped. + // [ + // '+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g', + // ['+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g'], + // {}, + // ['+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g', 'a', 'b\\c'] + // ], + + // crazy nested {,,} and *(||) tests. + function () { + fixtures = [ + 'a', 'b', 'c', 'd', 'ab', 'ac', 'ad', 'bc', 'cb', 'bc,d', + 'c,db', 'c,d', 'd)', '(b|c', '*(b|c', 'b|c', 'b|cc', 'cb|c', + 'x(a|b|c)', 'x(a|c)', '(a|b|c)', '(a|c)' + ] + }, + ['*(a|{b,c})', ['a', 'b', 'c', 'ab', 'ac'], {expand: true}], + // ['{a,*(b|c,d)}', ['a', '(b|c', '*(b|c', 'd)'], {expand: true}], //<= minimatch (wrong) + ['{a,*(b|c,d)}', ['a', 'b', 'bc,d', 'c,db', 'c,d'], {expand: true}], + + // a + // *(b|c) + // *(b|d) + ['{a,*(b|{c,d})}', ['a', 'b', 'bc', 'cb', 'c', 'd'], {expand: true}], + ['*(a|{b|c,c})', ['a', 'b', 'c', 'ab', 'ac', 'bc', 'cb']], + ['*(a|{b|c,c})', ['a', 'b', 'c', 'ab', 'ac', 'bc', 'cb'], {expand: true}], + + // test various flag settings. ['a?b', ['acb', 'acb/'], {}, ['x/y/acb', 'acb', 'acb/', 'acb/d/e']], ['a?b', ['x/y/acb', 'acb/', 'acb'], {matchBase: true}, ['x/y/acb', 'acb', 'acb/', 'acb/d/e']], diff --git a/test/globstars.js b/test/globstars.js index 2f56f54f..c5b36230 100644 --- a/test/globstars.js +++ b/test/globstars.js @@ -1,104 +1,115 @@ 'use strict'; var assert = require('assert'); -var nm = require('./support/match'); +var mm = require('./support/match'); +var mi = require('minimatch'); describe('globstars', function() { it('should support globstars (**)', function() { var fixtures = ['.a/a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/.a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z', 'a/../a', 'ab/../ac', '../a', 'a', '../../b', '../c', '../c/d']; - nm(fixtures, '**', ['a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); - nm(fixtures, '**/**', ['a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); - nm(fixtures, '**/', []); - nm(fixtures, '**/**/*', ['a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); - nm(fixtures, '**/**/x', ['a/x']); - nm(fixtures, '**/x', ['a/x']); - nm(fixtures, '**/x/*', ['a/x/y']); - nm(fixtures, '*/x/**', ['a/x/y', 'a/x/y/z']); - nm(fixtures, '**/x/**', ['a/x/y', 'a/x/y/z']); - nm(fixtures, '**/x/*/*', ['a/x/y/z']); - nm(fixtures, 'a/**', ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); - nm(fixtures, 'a/**/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); - nm(fixtures, 'a/**/**/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); - nm(fixtures, 'b/**', []); + mm(fixtures, '**', ['a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + mm(fixtures, '**/**', ['a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + mm(fixtures, '**/', []); + mm(fixtures, '**/**/*', ['a', 'a/a', 'aa/a', 'aaa/a', 'aab/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + mm(fixtures, '**/**/x', ['a/x']); + mm(fixtures, '**/x', ['a/x']); + mm(fixtures, '**/x/*', ['a/x/y']); + mm(fixtures, '*/x/**', ['a/x/y', 'a/x/y/z']); + mm(fixtures, '**/x/**', ['a/x/y', 'a/x/y/z']); + mm(fixtures, '**/x/*/*', ['a/x/y/z']); + mm(fixtures, 'a/**', ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + mm(fixtures, 'a/**/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + mm(fixtures, 'a/**/**/*', ['a/a', 'a/b', 'a/c', 'a/x', 'a/x/y', 'a/x/y/z']); + mm(fixtures, 'b/**', []); - assert(!nm.isMatch('a/b', 'a/**/')); - assert(!nm.isMatch('a/b/.js/c.txt', '**/*')); - assert(!nm.isMatch('a/b/c/d', 'a/**/')); - assert(!nm.isMatch('a/bb', 'a/**/')); - assert(!nm.isMatch('a/cb', 'a/**/')); - assert(nm.isMatch('a.b', '**/*')); - assert(nm.isMatch('a.js', '**/*')); - assert(nm.isMatch('a.js', '**/*.js')); - assert(nm.isMatch('a.md', '**/*.md')); - assert(nm.isMatch('a/', 'a/**/')); - assert(nm.isMatch('a/a.js', '**/*.js')); - assert(nm.isMatch('a/a/b.js', '**/*.js')); - assert(nm.isMatch('a/b', 'a/**/b')); - assert(nm.isMatch('a/b', 'a/**b')); - assert(nm.isMatch('a/b.md', '**/*.md')); - assert(nm.isMatch('a/b/c.js', '**/*')); - assert(nm.isMatch('a/b/c.txt', '**/*')); - assert(nm.isMatch('a/b/c/d/', 'a/**/')); - assert(nm.isMatch('a/b/c/d/a.js', '**/*')); - assert(nm.isMatch('a/b/c/z.js', 'a/b/**/*.js')); - assert(nm.isMatch('a/b/z.js', 'a/b/**/*.js')); - assert(nm.isMatch('ab', '**/*')); - assert(nm.isMatch('ab/a/d', '**/*')); - assert(nm.isMatch('ab/b', '**/*')); - assert(nm.isMatch('za.js', '**/*')); + assert(!mm.isMatch('a/b', 'a/**/')); + assert(!mm.isMatch('a/b/.js/c.txt', '**/*')); + assert(!mm.isMatch('a/b/c/d', 'a/**/')); + assert(!mm.isMatch('a/bb', 'a/**/')); + assert(!mm.isMatch('a/cb', 'a/**/')); + assert(mm.isMatch('/a/b', '/**')); + assert(mm.isMatch('a.b', '**/*')); + assert(mm.isMatch('a.js', '**/*')); + assert(mm.isMatch('a.js', '**/*.js')); + assert(mm.isMatch('a.md', '**/*.md')); + assert(mm.isMatch('a/', 'a/**/')); + assert(mm.isMatch('a/a.js', '**/*.js')); + assert(mm.isMatch('a/a/b.js', '**/*.js')); + assert(mm.isMatch('a/b', 'a/**/b')); + assert(mm.isMatch('a/b', 'a/**b')); + assert(mm.isMatch('a/b.md', '**/*.md')); + assert(mm.isMatch('a/b/c.js', '**/*')); + assert(mm.isMatch('a/b/c.txt', '**/*')); + assert(mm.isMatch('a/b/c/d/', 'a/**/')); + assert(mm.isMatch('a/b/c/d/a.js', '**/*')); + assert(mm.isMatch('a/b/c/z.js', 'a/b/**/*.js')); + assert(mm.isMatch('a/b/z.js', 'a/b/**/*.js')); + assert(mm.isMatch('ab', '**/*')); + assert(mm.isMatch('ab/a/d', '**/*')); + assert(mm.isMatch('ab/b', '**/*')); + assert(mm.isMatch('za.js', '**/*')); }); it('should support multiple globstars in one pattern', function() { - assert(!nm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/j/**/z/*.md')); - assert(!nm.isMatch('a/b/c/j/e/z/foo.txt', 'a/**/j/**/z/*.md')); - assert(nm.isMatch('a/b/c/d/e/j/n/p/o/z/foo.md', 'a/**/j/**/z/*.md')); - assert(nm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/z/*.md')); - assert(nm.isMatch('a/b/c/j/e/z/foo.md', 'a/**/j/**/z/*.md')); + assert(!mm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/j/**/z/*.md')); + assert(!mm.isMatch('a/b/c/j/e/z/foo.txt', 'a/**/j/**/z/*.md')); + assert(mm.isMatch('a/b/c/d/e/j/n/p/o/z/foo.md', 'a/**/j/**/z/*.md')); + assert(mm.isMatch('a/b/c/d/e/z/foo.md', 'a/**/z/*.md')); + assert(mm.isMatch('a/b/c/j/e/z/foo.md', 'a/**/j/**/z/*.md')); }); it('should match dotfiles', function() { var fixtures = ['.gitignore', 'a/b/z/.dotfile', 'a/b/z/.dotfile.md', 'a/b/z/.dotfile.md', 'a/b/z/.dotfile.md']; - assert(!nm.isMatch('.gitignore', 'a/**/z/*.md')); - assert(!nm.isMatch('a/b/z/.dotfile', 'a/**/z/*.md')); - assert(!nm.isMatch('a/b/z/.dotfile.md', '**/c/.*.md')); - assert(nm.isMatch('a/b/z/.dotfile.md', '**/.*.md')); - assert(nm.isMatch('a/b/z/.dotfile.md', 'a/**/z/.*.md')); - nm(fixtures, 'a/**/z/.*.md', [ 'a/b/z/.dotfile.md' ]); + assert(!mm.isMatch('.gitignore', 'a/**/z/*.md')); + assert(!mm.isMatch('a/b/z/.dotfile', 'a/**/z/*.md')); + assert(!mm.isMatch('a/b/z/.dotfile.md', '**/c/.*.md')); + assert(mm.isMatch('a/b/z/.dotfile.md', '**/.*.md')); + assert(mm.isMatch('a/b/z/.dotfile.md', 'a/**/z/.*.md')); + mm(fixtures, 'a/**/z/.*.md', [ 'a/b/z/.dotfile.md' ]); }); it('should match file extensions:', function() { - nm(['.md', 'a.md', 'a/b/c.md', '.txt'], '**/*.md', ['a.md', 'a/b/c.md']); - nm(['.md', 'a/b/.md'], '**/.md', ['.md', 'a/b/.md']); + mm(['.md', 'a.md', 'a/b/c.md', '.txt'], '**/*.md', ['a.md', 'a/b/c.md']); + mm(['.md', 'a/b/.md'], '**/.md', ['.md', 'a/b/.md']); }); it('should respect trailing slashes on paterns', function() { var fixtures = ['a', 'a/', 'b', 'b/', 'a/a', 'a/a/', 'a/b', 'a/b/', 'a/c', 'a/c/', 'a/x', 'a/x/', 'a/a/a', 'a/a/b', 'a/a/b/', 'a/a/a/', 'a/a/a/a', 'a/a/a/a/', 'a/a/a/a/a', 'a/a/a/a/a/', 'x/y', 'z/z', 'x/y/', 'z/z/', 'a/b/c/.d/e/']; - nm(fixtures, '**/*/a/', ['a/a/', 'a/a/a/', 'a/a/a/a/', 'a/a/a/a/a/']); - nm(fixtures, '**/*/a/*/', ['a/a/a/', 'a/a/a/a/', 'a/a/a/a/a/', 'a/a/b/']); - nm(fixtures, '**/*/x/', ['a/x/']); - nm(fixtures, '**/*/*/*/*/', ['a/a/a/a/', 'a/a/a/a/a/']); - nm(fixtures, '**/*/*/*/*/*/', ['a/a/a/a/a/']); - nm(fixtures, '*a/a/*/', ['a/a/a/', 'a/a/b/']); - nm(fixtures, '**a/a/*/', ['a/a/a/', 'a/a/b/']); - nm(fixtures, '**/a/*/*/', ['a/a/a/', 'a/a/b/', 'a/a/a/a/', 'a/a/a/a/a/']); - nm(fixtures, '**/a/*/*/*/', ['a/a/a/a/', 'a/a/a/a/a/']); - nm(fixtures, '**/a/*/*/*/*/', ['a/a/a/a/a/']); - nm(fixtures, '**/a/*/a/', ['a/a/a/', 'a/a/a/a/', 'a/a/a/a/a/']); - nm(fixtures, '**/a/*/b/', ['a/a/b/']); + + console.log(mi.makeRe('**/*/a/')) + console.log(mm.makeRe('(|**/)*/a/')) + var re = mi.makeRe('{,**/}*/a/'); + var res = fixtures.filter(function(p) { + return re.test(p); + }); + console.log(res) + + mm(fixtures, '**/*/a/', ['a/a/', 'a/a/a/', 'a/a/a/a/', 'a/a/a/a/a/']); + mm(fixtures, '**/*/a/*/', ['a/a/a/', 'a/a/a/a/', 'a/a/a/a/a/', 'a/a/b/']); + mm(fixtures, '**/*/x/', ['a/x/']); + mm(fixtures, '**/*/*/*/*/', ['a/a/a/a/', 'a/a/a/a/a/']); + mm(fixtures, '**/*/*/*/*/*/', ['a/a/a/a/a/']); + mm(fixtures, '*a/a/*/', ['a/a/a/', 'a/a/b/']); + mm(fixtures, '**a/a/*/', ['a/a/a/', 'a/a/b/']); + mm(fixtures, '**/a/*/*/', ['a/a/a/', 'a/a/b/', 'a/a/a/a/', 'a/a/a/a/a/']); + mm(fixtures, '**/a/*/*/*/', ['a/a/a/a/', 'a/a/a/a/a/']); + mm(fixtures, '**/a/*/*/*/*/', ['a/a/a/a/a/']); + mm(fixtures, '**/a/*/a/', ['a/a/a/', 'a/a/a/a/', 'a/a/a/a/a/']); + mm(fixtures, '**/a/*/b/', ['a/a/b/']); }); it('should match literal globstars when escaped', function() { var fixtures = ['.md', '**a.md', '**.md', '.md', '**']; - nm(fixtures, '\\*\\**.md', ['**a.md', '**.md']); - nm(fixtures, '\\*\\*.md', ['**.md']); + mm(fixtures, '\\*\\**.md', ['**a.md', '**.md']); + mm(fixtures, '\\*\\*.md', ['**.md']); }); // related to https://github.com/isaacs/minimatch/issues/67 it('should work consistently with `makeRe` and matcher functions', function() { - var re = nm.makeRe('node_modules/foobar/**/*.bar'); + var re = mm.makeRe('node_modules/foobar/**/*.bar'); assert(re.test('node_modules/foobar/foo.bar')); - assert(nm.isMatch('node_modules/foobar/foo.bar', 'node_modules/foobar/**/*.bar')); - nm(['node_modules/foobar/foo.bar'], 'node_modules/foobar/**/*.bar', ['node_modules/foobar/foo.bar']); + assert(mm.isMatch('node_modules/foobar/foo.bar', 'node_modules/foobar/**/*.bar')); + mm(['node_modules/foobar/foo.bar'], 'node_modules/foobar/**/*.bar', ['node_modules/foobar/foo.bar']); }); }); diff --git a/test/issue-related.js b/test/issue-related.js index 4aa12e9c..a4aa08b0 100644 --- a/test/issue-related.js +++ b/test/issue-related.js @@ -1,62 +1,62 @@ 'use strict'; var assert = require('assert'); -var nm = require('./support/match'); +var mm = require('./support/match'); describe('issue-related tests', function() { // see https://github.com/jonschlinkert/micromatch/issues/15 it('issue #15', function() { - assert(nm.isMatch('a/b-c/d/e/z.js', 'a/b-*/**/z.js')); - assert(nm.isMatch('z.js', 'z*')); - assert(nm.isMatch('z.js', '**/z*')); - assert(nm.isMatch('z.js', '**/z*.js')); - assert(nm.isMatch('z.js', '**/*.js')); - assert(nm.isMatch('foo', '**/foo')); + assert(mm.isMatch('a/b-c/d/e/z.js', 'a/b-*/**/z.js')); + assert(mm.isMatch('z.js', 'z*')); + assert(mm.isMatch('z.js', '**/z*')); + assert(mm.isMatch('z.js', '**/z*.js')); + assert(mm.isMatch('z.js', '**/*.js')); + assert(mm.isMatch('foo', '**/foo')); }); // see https://github.com/jonschlinkert/micromatch/issues/23 it('issue #23', function() { - assert(!nm.isMatch('zzjs', 'z*.js')); - assert(!nm.isMatch('zzjs', '*z.js')); + assert(!mm.isMatch('zzjs', 'z*.js')); + assert(!mm.isMatch('zzjs', '*z.js')); }); // see https://github.com/jonschlinkert/micromatch/issues/24 it('issue #24', function() { - assert(!nm.isMatch('a', 'a/**')); - assert(!nm.isMatch('a/b/c/d/', 'a/b/**/f')); - assert(nm.isMatch('a', '**')); - assert(nm.isMatch('a/', '**')); - assert(nm.isMatch('a/b/c/d', '**')); - assert(nm.isMatch('a/b/c/d/', '**')); - assert(nm.isMatch('a/b/c/d/', '**/**')); - assert(nm.isMatch('a/b/c/d/', '**/b/**')); - assert(nm.isMatch('a/b/c/d/', 'a/b/**')); - assert(nm.isMatch('a/b/c/d/', 'a/b/**/')); - assert(nm.isMatch('a/b/c/d/e.f', 'a/b/**/**/*.*')); - assert(nm.isMatch('a/b/c/d/e.f', 'a/b/**/*.*')); - assert(nm.isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*')); - assert(nm.isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*')); + assert(!mm.isMatch('a', 'a/**')); + assert(!mm.isMatch('a/b/c/d/', 'a/b/**/f')); + assert(mm.isMatch('a', '**')); + assert(mm.isMatch('a/', '**')); + assert(mm.isMatch('a/b/c/d', '**')); + assert(mm.isMatch('a/b/c/d/', '**')); + assert(mm.isMatch('a/b/c/d/', '**/**')); + assert(mm.isMatch('a/b/c/d/', '**/b/**')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**')); + assert(mm.isMatch('a/b/c/d/', 'a/b/**/')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/**/*.*')); + assert(mm.isMatch('a/b/c/d/e.f', 'a/b/**/*.*')); + assert(mm.isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*')); + assert(mm.isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*')); }); // see https://github.com/jonschlinkert/micromatch/issues/59 it('should only match nested directories when `**` is the only thing in a segment', function() { - assert(!nm.isMatch('a/b/c', 'a/b**')); - assert(!nm.isMatch('a/c/b', 'a/**b')); + assert(!mm.isMatch('a/b/c', 'a/b**')); + assert(!mm.isMatch('a/c/b', 'a/**b')); }); // see https://github.com/jonschlinkert/micromatch/issues/63 it('issue #63', function() { - assert(nm.isMatch('/aaa/bbb/foo', '/aaa/bbb/**')); - assert(nm.isMatch('/aaa/bbb/', '/aaa/bbb/**')); - assert(nm.isMatch('/aaa/bbb/foo.git', '/aaa/bbb/**')); - assert(!nm.isMatch('/aaa/bbb/.git', '/aaa/bbb/**')); - assert(!nm.isMatch('aaa/bbb/.git', 'aaa/bbb/**')); - assert(!nm.isMatch('/aaa/bbb/ccc/.git', '/aaa/bbb/**')); - assert(!nm.isMatch('/aaa/.git/foo', '/aaa/**/*')); - assert(nm.isMatch('/aaa/.git/foo', '/aaa/**/*', {dot: true})); - assert(nm.isMatch('/aaa/bbb/.git', '/aaa/bbb/*', {dot: true})); - assert(nm.isMatch('aaa/bbb/.git', 'aaa/bbb/**', {dot: true})); - assert(nm.isMatch('/aaa/bbb/.git', '/aaa/bbb/**', {dot: true})); - assert(nm.isMatch('/aaa/bbb/ccc/.git', '/aaa/bbb/**', {dot: true})); + assert(mm.isMatch('/aaa/bbb/foo', '/aaa/bbb/**')); + assert(mm.isMatch('/aaa/bbb/', '/aaa/bbb/**')); + assert(mm.isMatch('/aaa/bbb/foo.git', '/aaa/bbb/**')); + assert(!mm.isMatch('/aaa/bbb/.git', '/aaa/bbb/**')); + assert(!mm.isMatch('aaa/bbb/.git', 'aaa/bbb/**')); + assert(!mm.isMatch('/aaa/bbb/ccc/.git', '/aaa/bbb/**')); + assert(!mm.isMatch('/aaa/.git/foo', '/aaa/**/*')); + assert(mm.isMatch('/aaa/.git/foo', '/aaa/**/*', {dot: true})); + assert(mm.isMatch('/aaa/bbb/.git', '/aaa/bbb/*', {dot: true})); + assert(mm.isMatch('aaa/bbb/.git', 'aaa/bbb/**', {dot: true})); + assert(mm.isMatch('/aaa/bbb/.git', '/aaa/bbb/**', {dot: true})); + assert(mm.isMatch('/aaa/bbb/ccc/.git', '/aaa/bbb/**', {dot: true})); }); }); diff --git a/test/minimatch.js b/test/minimatch.js index fc57abf9..b39da9f3 100644 --- a/test/minimatch.js +++ b/test/minimatch.js @@ -1,7 +1,10 @@ 'use strict'; -var match = require('./support/match'); +var path = require('path'); +var assert = require('assert'); +var extend = require('extend-shallow'); var patterns = require('./fixtures/patterns'); +var mm = require('./support/match'); describe('basic tests', function() { patterns.forEach(function(unit, i) { @@ -19,13 +22,68 @@ describe('basic tests', function() { var pattern = unit[0]; var expected = (unit[1] || []).sort(compare); - var options = unit[2] || {}; + var options = extend({}, unit[2]); var fixtures = unit[3] || patterns.fixtures; - match(fixtures, pattern, expected, options); + mm.match(fixtures, pattern, expected, options); }); }); }); +describe('minimatch issues (as of 12/7/2016)', function() { + it('https://github.com/isaacs/minimatch/issues/29', function() { + assert(mm.isMatch('foo/bar.txt', 'foo/**/*.txt')); + assert(mm.makeRe('foo/**/*.txt' ).test( 'foo/bar.txt')); + assert(!mm.isMatch('n/!(axios)/**', 'n/axios/a.js')); + assert(!mm.makeRe('n/!(axios)/**').test('n/axios/a.js')); + }); + + it('https://github.com/isaacs/minimatch/issues/30', function() { + assert(mm.isMatch('foo/bar.js', '**/foo/**')); + assert(mm.isMatch('./foo/bar.js', './**/foo/**')); + assert(mm.isMatch('./foo/bar.js', '**/foo/**')); + assert(mm.isMatch('./foo/bar.txt', 'foo/**/*.txt')); + assert(mm.makeRe('./foo/**/*.txt' ).test( 'foo/bar.txt')); + assert(!mm.isMatch('./n/!(axios)/**', 'n/axios/a.js')); + assert(!mm.makeRe('./n/!(axios)/**').test('n/axios/a.js')); + }); + + it('https://github.com/isaacs/minimatch/issues/50', function() { + assert(mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[ABC\\].txt')); + assert(!mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[abc\\].txt')); + assert(mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[abc\\].txt', {nocase: true})); + }); + + it('https://github.com/isaacs/minimatch/issues/75', function() { + assert(!mm.isMatch('foo/baz.qux.js', 'foo/!(baz.qux).js')); + assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/*/!(baz.qux).js')); + assert(!mm.isMatch('foo/bar/bazqux.js', '**/!(bazqux).js')); + assert(!mm.isMatch('foo/bar/bazqux.js', 'foo/**/!(bazqux).js')); + assert(!mm.isMatch('foo/bar/bazqux.js', 'foo/**/!(bazqux)*.js')); + assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/**/!(baz.qux)*.js')); + assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/**/!(baz.qux).js')); + assert(!mm.isMatch('foo.js', '!(foo)*.js')); + assert(!mm.isMatch('foo.js', '!(foo)*.js')); + assert(!mm.isMatch('foobar.js', '!(foo)*.js')); + }); + + it('https://github.com/isaacs/minimatch/issues/78', function() { + var sep = path.sep; + path.sep = '\\'; + assert(mm.isMatch('a\\b\\c.txt', 'a/**/*.txt')); + path.sep = sep; + }); + + it('https://github.com/isaacs/minimatch/issues/82', function() { + assert(mm.isMatch('./src/test/a.js', '**/test/**')); + assert(mm.isMatch('src/test/a.js', '**/test/**')); + }); + + it('https://github.com/isaacs/minimatch/issues/83', function() { + assert(!mm.makeRe('n/!(axios)/**').test('n/axios/a.js')); + assert(!mm.isMatch('n/!(axios)/**', 'n/axios/a.js')); + }); +}); + function compare(a, b) { return a === b ? 0 : a > b ? 1 : -1; } diff --git a/test/negation.js b/test/negation.js index 24c56f34..68c7066f 100644 --- a/test/negation.js +++ b/test/negation.js @@ -1,5 +1,6 @@ 'use strict'; +var mi = require('minimatch'); var mm = require('./support/match'); describe('negation', function() { diff --git a/test/options.js b/test/options.js index 9f47b56b..7fc8d293 100644 --- a/test/options.js +++ b/test/options.js @@ -6,6 +6,13 @@ var sep = path.sep; var mm = require('./support/match'); describe('options', function() { + beforeEach(function() { + path.sep = '\\'; + }); + afterEach(function() { + path.sep = sep; + }); + describe('options.ignore', function() { var negations = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c', 'a/d', 'a/e']; var globs = ['a', 'a/a', 'a/a/a', 'a/a/a/a', '.a', 'a/.a', '.a/a', '.a/a/a', 'a/a/.a', '.a/a/a/a', 'a/a/a/a/a', 'a/a/b', 'a/b', 'a/b/c', 'a/c', 'a/x', 'b', 'b/b/b', 'b/b/c', 'c/c/c', 'e/f/g', 'h/i/a', 'x/x/x', 'x/y', 'z/z', 'z/z/z']; @@ -145,16 +152,17 @@ describe('options', function() { 'utils.js' ]; - mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c'], {}); - mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['/a/b/c'], {}); - mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c'], {nodupes: true}); - mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['/a/b/c'], {nodupes: true}); - mm(fixtures, ['example.*', '*.js'], ['example.js', 'example.md', 'example.css', 'index.js', 'test.js', 'utils.js'], {nodupes: true}); + mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c', '\\a\\b\\c'], {unixify: false}); + mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['\\a\\b\\c'], {unixify: false}); + mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c', '\\a\\b\\c'], {unixify: false, nodupes: true}); + mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['\\a\\b\\c'], {unixify: false, nodupes: true}); + mm(fixtures, ['example.*', '*.js'], ['example.js', 'example.md', 'example.css', 'index.js', 'test.js', 'utils.js'], {unixify: false, nodupes: true}); }); it('should not remove duplicates', function() { mm(['abc', '/a/b/c', '\\a\\b\\c'], '/a/b/c', ['/a/b/c', '/a/b/c'], {nodupes: false}); mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['/a/b/c'], {nodupes: false}); + mm(['abc', '/a/b/c', '\\a\\b\\c'], '\\a\\b\\c', ['\\a\\b\\c'], {unixify: false, nodupes: false}); }); }); @@ -162,8 +170,9 @@ describe('options', function() { it('should remove backslashes in glob patterns:', function() { var fixtures = ['abc', '/a/b/c', '\\a\\b\\c']; mm(fixtures, '\\a\\b\\c', ['/a/b/c']); - mm(fixtures, '\\a\\b\\c', {unescape: true}, ['/a/b/c']); - mm(fixtures, '\\a\\b\\c', {unescape: true, nodupes: false}, ['/a/b/c']); + mm(fixtures, '\\a\\b\\c', {nodupes: false}, ['/a/b/c']); + mm(fixtures, '\\a\\b\\c', {nodupes: false, unescape: false}, ['/a/b/c']); + mm(fixtures, '\\a\\b\\c', {unescape: true, nodupes: false, unixify: false}, ['\\a\\b\\c']); }); }); @@ -185,11 +194,46 @@ describe('options', function() { describe('options.unixify', function() { it('should unixify file paths', function() { - mm(['a\\b\\c.md'], '**/*.md', ['a/b/c.md'], {unixify: true}); + mm(['a\\b\\c.md'], '**/*.md', ['a/b/c.md']); + mm(['a\\b\\c.md'], '**/*.md', ['a\\b\\c.md'], {unixify: false}); }); it('should unixify absolute paths', function() { - mm(['E:\\a\\b\\c.md'], 'E:/**/*.md', ['E:/a/b/c.md'], {unixify: true}); + mm(['E:\\a\\b\\c.md'], 'E:/**/*.md', ['E:/a/b/c.md']); + mm(['E:\\a\\b\\c.md'], 'E:/**/*.md', ['E:\\a\\b\\c.md'], {unixify: false}); + }); + + it('should strip leading `./`', function() { + var fixtures = ['a', './a', 'b', 'a/a', './a/b', 'a/c', './a/x', './a/a/a', 'a/a/b', './a/a/a/a', './a/a/a/a/a', 'x/y', './z/z']; + mm(fixtures, '*', ['a', 'b']); + mm(fixtures, '**/a/**', ['a/a', 'a/c', 'a/b', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm(fixtures, '*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); + mm(fixtures, '*/*/*', ['a/a/a', 'a/a/b']); + mm(fixtures, '*/*/*/*', ['a/a/a/a']); + mm(fixtures, '*/*/*/*/*', ['a/a/a/a/a']); + mm(fixtures, './*', ['a', 'b']); + mm(fixtures, './**/a/**', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm(fixtures, './a/*/a', ['a/a/a']); + mm(fixtures, 'a/*', ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, 'a/*/*', ['a/a/a', 'a/a/b']); + mm(fixtures, 'a/*/*/*', ['a/a/a/a']); + mm(fixtures, 'a/*/*/*/*', ['a/a/a/a/a']); + mm(fixtures, 'a/*/a', ['a/a/a']); + + mm(fixtures, '*', {unixify: false}, ['a', './a', 'b']); + mm(fixtures, '**/a/**', {unixify: false}, ['a/a', 'a/c', './a/b', './a/x', './a/a/a', 'a/a/b', './a/a/a/a', './a/a/a/a/a']); + mm(fixtures, '*/*', {unixify: false}, ['a/a', './a/b', 'a/c', './a/x', 'x/y', './z/z']); + mm(fixtures, '*/*/*', {unixify: false}, ['./a/a/a', 'a/a/b']); + mm(fixtures, '*/*/*/*', {unixify: false}, ['./a/a/a/a']); + mm(fixtures, '*/*/*/*/*', {unixify: false}, ['./a/a/a/a/a']); + mm(fixtures, './*', {unixify: false}, ['a', './a', 'b']); + mm(fixtures, './**/a/**', {unixify: false}, ['a/a', './a/b', 'a/c', './a/x', './a/a/a', 'a/a/b', './a/a/a/a', './a/a/a/a/a']); + mm(fixtures, './a/*/a', {unixify: false}, ['./a/a/a']); + mm(fixtures, 'a/*', {unixify: false}, ['a/a', './a/b', 'a/c', './a/x']); + mm(fixtures, 'a/*/*', {unixify: false}, ['./a/a/a', 'a/a/b']); + mm(fixtures, 'a/*/*/*', {unixify: false}, ['./a/a/a/a']); + mm(fixtures, 'a/*/*/*/*', {unixify: false}, ['./a/a/a/a/a']); + mm(fixtures, 'a/*/a', {unixify: false}, ['./a/a/a']); }); }); @@ -205,7 +249,9 @@ describe('options', function() { // https://github.com/isaacs/minimatch/issues/30 mm(['foo/bar.js'], '**/foo/**', ['foo/bar.js']); mm(['./foo/bar.js'], './**/foo/**', ['foo/bar.js']); + mm(['./foo/bar.js'], './**/foo/**', ['./foo/bar.js'], {unixify: false}); mm(['./foo/bar.js'], '**/foo/**', ['foo/bar.js']); + mm(['./foo/bar.js'], '**/foo/**', ['./foo/bar.js'], {unixify: false}); }); it('should match dotfiles when a leading dot is defined in the path:', function() { @@ -249,7 +295,7 @@ describe('options', function() { mm(['.a', '.b', 'c', 'c.md'], '!.*', ['c', 'c.md']); mm(['.a', '.b', 'c', 'c.md'], '!(.*)', ['c', 'c.md']); mm(['.a', '.b', 'c', 'c.md'], '!(.*)*', ['c', 'c.md']); - mm(['.a', '.b', 'c', 'c.md'], '!*.*', ['c']); + mm(['.a', '.b', 'c', 'c.md'], '!*.*', ['.a', '.b', 'c']); }); it('should match dotfiles when `options.dot` is true:', function() { @@ -277,10 +323,12 @@ describe('options', function() { describe('windows', function() { it('should unixify file paths', function() { mm(['a\\b\\c.md'], '**/*.md', ['a/b/c.md']); + mm(['a\\b\\c.md'], '**/*.md', {unixify: false}, ['a\\b\\c.md']); }); it('should unixify absolute paths', function() { mm(['E:\\a\\b\\c.md'], 'E:/**/*.md', ['E:/a/b/c.md']); + mm(['E:\\a\\b\\c.md'], 'E:/**/*.md', ['E:\\a\\b\\c.md'], {unixify: false}); }); }); @@ -288,16 +336,25 @@ describe('options', function() { it('should normalize leading `./`', function() { var fixtures = ['a.md', 'a/b/c.md', 'a/b/d.md', './a/b/c.md', './b/c.md', '.\\a\\b\\c.md']; mm(fixtures, '**/*.md', ['a.md', 'a/b/c.md', 'a/b/d.md', 'b/c.md']); + mm(fixtures, '**/*.md', ['a.md', 'a/b/c.md', './a/b/c.md', '.\\a\\b\\c.md', 'a/b/d.md', './b/c.md'], {unixify: false}); }); it('should match leading `./`', function() { var fixtures = ['a.md', 'a/b.md', './a.md', './a/b.md', 'a/b/c.md', './a/b/c.md', '.\\a\\b\\c.md', 'a\\b\\c.md']; mm(fixtures, '**/*.md', ['a.md', 'a/b.md', 'a/b/c.md']); + mm(fixtures, '**/*.md', ['a.md', './a.md', 'a/b.md', './a/b.md', 'a/b/c.md', 'a\\b\\c.md', './a/b/c.md', '.\\a\\b\\c.md'], {unixify: false}); + mm(fixtures, '*.md', ['a.md']); + mm(fixtures, '*.md', ['a.md', './a.md'], {unixify: false}, {unixify: false}); mm(fixtures, '*.md', ['a.md']); + mm(fixtures, '*/*.md', ['a/b.md', './a/b.md'], {unixify: false}); mm(fixtures, '*/*.md', ['a/b.md']); + mm(fixtures, './**/*.md', ['a.md', 'a/b.md', 'a/b/c.md', 'a\\b\\c.md', './a.md', './a/b.md', './a/b/c.md', '.\\a\\b\\c.md'], {unixify: false}); mm(fixtures, './**/*.md', ['a.md', 'a/b.md', 'a/b/c.md']); + mm(fixtures, './*.md', ['a.md', './a.md'], {unixify: false}); mm(fixtures, './*.md', ['a.md']); + mm(fixtures, './*/*.md', ['a/b.md', './a/b.md'], {unixify: false}); mm(fixtures, './*/*.md', ['a/b.md']); + mm(['./a'], 'a', ['./a'], {unixify: false}); mm(['./a'], 'a', ['a']); }); }); diff --git a/test/qmarks.js b/test/qmarks.js index 6c9e5cc5..71af9b28 100644 --- a/test/qmarks.js +++ b/test/qmarks.js @@ -5,14 +5,20 @@ var mm = require('./support/match'); describe('qmarks and stars', function() { it('should correctly handle question marks in globs', function() { - mm(['?'], '?', ['?']); + mm(['?', '??', '???'], '?', ['?']); + mm(['?', '??', '???'], '??', ['??']); + mm(['?', '??', '???'], '???', ['???']); + mm(['/a/', '/a/b/', '/a/b/c/', '/a/b/c/d/'], '??', []); + mm(['/a/', '/a/b/', '/a/b/c/', '/a/b/c/d/'], '??', {dot: true}, []); + mm(['x/y/acb', 'acb', 'acb/', 'acb/d/e'], 'a?b', ['acb', 'acb/']); mm(['aaa', 'aac', 'abc'], 'a?c', ['abc', 'aac']); mm(['aaa', 'aac', 'abc'], 'a*?c', ['aac', 'abc']); mm(['a', 'aa', 'ab', 'ab?', 'ac', 'ac?', 'abcd', 'abbb'], 'ab?', ['ab?']); mm(['abc', 'abb', 'acc'], 'a**?c', ['abc', 'acc']); mm(['abc'], 'a*****?c', ['abc']); - mm(['abc', 'zzz', 'bbb'], '?*****??', ['abc', 'zzz', 'bbb']); - mm(['abc', 'zzz', 'bbb'], '*****??', ['abc', 'zzz', 'bbb']); + mm(['a', 'aa', 'abc', 'zzz', 'bbb', 'aaaa'], '*****?', ['a', 'aa', 'abc', 'zzz', 'bbb', 'aaaa']); + mm(['a', 'aa', 'abc', 'zzz', 'bbb', 'aaaa'], '*****??', ['aa', 'abc', 'zzz', 'bbb', 'aaaa']); + mm(['a', 'aa', 'abc', 'zzz', 'bbb', 'aaaa'], '?*****??', ['abc', 'zzz', 'bbb', 'aaaa']); mm(['abc', 'abb', 'zzz'], '?*****?c', ['abc']); mm(['abc', 'bbb', 'zzz'], '?***?****c', ['abc']); mm(['abc', 'bbb', 'zzz'], '?***?****?', ['abc', 'bbb', 'zzz']); @@ -63,11 +69,20 @@ describe('qmarks and stars', function() { assert(!mm.isMatch('aaa\\\\bbb', 'aaa?bbb')); }); - it('question marks should not match dots', function() { - assert(!mm.isMatch('aaa.bbb', 'aaa?bbb')); + it('question marks should match arbitrary dots', function() { + assert(mm.isMatch('aaa.bbb', 'aaa?bbb')); + }); + + it('question marks should not match leading dots', function() { + assert(!mm.isMatch('.aaa/bbb', '?aaa/bbb')); assert(!mm.isMatch('aaa/.bbb', 'aaa/?bbb')); }); + it('question marks should match leading dots when options.dot is true', function() { + assert(mm.isMatch('aaa/.bbb', 'aaa/?bbb', {dot: true})); + assert(mm.isMatch('.aaa/bbb', '?aaa/bbb', {dot: true})); + }); + it('question marks should match characters preceding a dot', function() { assert(mm.isMatch('a/bbb/abcd.md', 'a/*/ab??.md')); assert(mm.isMatch('a/bbb/abcd.md', 'a/bbb/ab??.md')); diff --git a/test/regex-ranges.js b/test/regex-ranges.js index bdc970a4..56b63cce 100644 --- a/test/regex-ranges.js +++ b/test/regex-ranges.js @@ -1,5 +1,6 @@ 'use strict'; +var mi = require('minimatch'); var mm = require('./support/match'); describe('ranges', function() { @@ -10,12 +11,16 @@ describe('ranges', function() { mm(fixtures, '[a-d]*.[a-b]', ['a.a', 'a.b', 'c.a']); }); - it('should support valid regex ranges with negation patterns', function() { + it('should support valid regex ranges with glob negation patterns', function() { var fixtures = ['a.a', 'a.b', 'a.a.a', 'c.a', 'd.a.d', 'a.bb', 'a.ccc']; mm(fixtures, '!*.[a-b]', ['a.bb', 'a.ccc', 'd.a.d']); + mm(fixtures, '!*.[a-b]*', ['a.ccc', 'd.a.d']); mm(fixtures, '![a-b].[a-b]', ['a.a.a', 'a.bb', 'a.ccc', 'c.a', 'd.a.d']); mm(fixtures, '![a-b]+.[a-b]+', ['a.a.a', 'a.ccc', 'c.a', 'd.a.d']); - mm(fixtures, '!*.[a-b]*', ['a.ccc', 'd.a.d']); + }); + + it('should support valid regex ranges with negation patterns', function() { + var fixtures = ['a.a', 'a.b', 'a.a.a', 'c.a', 'd.a.d', 'a.bb', 'a.ccc']; mm(fixtures, '*.[^a-b]', ['d.a.d']); mm(fixtures, 'a.[^a-b]*', ['a.ccc']); }); diff --git a/test/stars.js b/test/stars.js index 4e4add01..640de2d9 100644 --- a/test/stars.js +++ b/test/stars.js @@ -4,7 +4,7 @@ var mm = require('./support/match'); describe('stars', function() { it('should match one directory level with a single star (*)', function() { - var fixtures = ['a', 'b', 'a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a', 'x/y', 'z/z']; + var fixtures = ['/a', '/b', 'a', 'b', 'a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a', 'x/y', 'z/z']; mm(fixtures, '*', ['a', 'b']); mm(fixtures, '*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); mm(fixtures, '*/*/*', ['a/a/a', 'a/a/b']); @@ -59,18 +59,32 @@ describe('stars', function() { it('should match leading `./`', function() { var fixtures = ['a', './a', 'b', 'a/a', './a/b', 'a/c', './a/x', './a/a/a', 'a/a/b', './a/a/a/a', './a/a/a/a/a', 'x/y', './z/z']; mm(fixtures, '*', ['a', 'b']); + mm(fixtures, '*', ['a', './a', 'b'], {unixify: false}); mm(fixtures, '**/a/**', ['a/a', 'a/c', 'a/b', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm(fixtures, '**/a/**', ['a/a', 'a/c', './a/b', './a/x', './a/a/a', 'a/a/b', './a/a/a/a', './a/a/a/a/a'], {unixify: false}); mm(fixtures, '*/*', ['a/a', 'a/b', 'a/c', 'a/x', 'x/y', 'z/z']); + mm(fixtures, '*/*', ['a/a', './a/b', 'a/c', './a/x', 'x/y', './z/z'], {unixify: false}); mm(fixtures, '*/*/*', ['a/a/a', 'a/a/b']); + mm(fixtures, '*/*/*', ['./a/a/a', 'a/a/b'], {unixify: false}); + mm(fixtures, './a/*/a', ['a/a/a']); + mm(fixtures, './a/*/a', ['./a/a/a'], {unixify: false}); mm(fixtures, '*/*/*/*', ['a/a/a/a']); + mm(fixtures, '*/*/*/*', ['./a/a/a/a'], {unixify: false}); mm(fixtures, '*/*/*/*/*', ['a/a/a/a/a']); + mm(fixtures, '*/*/*/*/*', ['./a/a/a/a/a'], {unixify: false}); mm(fixtures, './*', ['a', 'b']); - mm(fixtures, './**/a/**', ['a/a', 'a/b', 'a/c', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); - mm(fixtures, './a/*/a', ['a/a/a']); + mm(fixtures, './*', ['a', './a', 'b'], {unixify: false}); + mm(fixtures, './**/a/**', ['a/a', 'a/c', 'a/b', 'a/x', 'a/a/a', 'a/a/b', 'a/a/a/a', 'a/a/a/a/a']); + mm(fixtures, './**/a/**', ['a/a', 'a/c', './a/b', './a/x', './a/a/a', 'a/a/b', './a/a/a/a', './a/a/a/a/a'], {unixify: false}); mm(fixtures, 'a/*', ['a/a', 'a/b', 'a/c', 'a/x']); + mm(fixtures, 'a/*', ['a/a', './a/b', 'a/c', './a/x'], {unixify: false}); mm(fixtures, 'a/*/*', ['a/a/a', 'a/a/b']); + mm(fixtures, 'a/*/*', ['./a/a/a', 'a/a/b'], {unixify: false}); mm(fixtures, 'a/*/*/*', ['a/a/a/a']); + mm(fixtures, 'a/*/*/*', ['./a/a/a/a'], {unixify: false}); mm(fixtures, 'a/*/*/*/*', ['a/a/a/a/a']); + mm(fixtures, 'a/*/*/*/*', ['./a/a/a/a/a'], {unixify: false}); mm(fixtures, 'a/*/a', ['a/a/a']); + mm(fixtures, 'a/*/a', ['./a/a/a'], {unixify: false}); }); }); diff --git a/test/support/match.js b/test/support/match.js index e3ec06ec..ec4bcdff 100644 --- a/test/support/match.js +++ b/test/support/match.js @@ -1,10 +1,10 @@ 'use strict'; var assert = require('assert'); +var extend = require('extend-shallow'); var utils = require('../../lib/utils'); var matcher = require('./matcher'); var compare = require('./compare'); -var mm = require('../..'); module.exports = function(fixtures, patterns, expected, options) { if (!Array.isArray(expected)) { @@ -19,8 +19,9 @@ module.exports = function(fixtures, patterns, expected, options) { assert.deepEqual(actual, expected, patterns); }; +extend(module.exports, matcher); -module.exports.match = function(fixtures, pattern, expected, options) { +module.exports.match = function fn(fixtures, pattern, expected, options) { if (!Array.isArray(expected)) { var tmp = expected; expected = options; @@ -43,7 +44,6 @@ module.exports.matcher = function(fixtures, patterns, expected, options) { var fn = matcher.matcher(patterns, options); fixtures = utils.arrayify(fixtures); - var actual = []; fixtures.forEach(function(file) { if (fn(file)) { diff --git a/test/support/matcher.js b/test/support/matcher.js index 8ab920fb..ad3b54e8 100644 --- a/test/support/matcher.js +++ b/test/support/matcher.js @@ -1,76 +1,80 @@ 'use strict'; +var utils = require('../../lib/utils'); var argv = require('yargs-parser')(process.argv.slice(2)); -var mm = require('multimatch'); var bash = require('bash-match'); var minimatch = require('minimatch'); -var utils = require('../../lib/utils'); -var nm = require('../..'); +var mu = require('multimatch'); +var mi = require('../..'); // use multimatch for the array/array scenario -function mi() { - return mm.apply(null, arguments); +function mm() { + return mu.apply(null, arguments); } // label for debugging -mm.multimatch = true; -mi.minimatch = true; -nm.nanomatch = true; +mi.micromatch = true; +mu.multimatch = true; +mm.minimatch = true; bash.bash = true; /** - * Decorate methods onto bash for parity with nanomatch + * Decorate methods onto bash for parity with micromatch */ bash.makeRe = function() {}; /** - * Decorate methods onto multimatch for parity with nanomatch + * Decorate methods onto multimatch for parity with micromatch */ -mm.isMatch = function(files, patterns, options) { - return mm(utils.arrayify(files), patterns, options).length > 0; +mu.isMatch = function(files, patterns, options) { + return mu(utils.arrayify(files), patterns, options).length > 0; }; -mm.match = function(files, patterns, options) { - return mm(utils.arrayify(files), patterns, options); +mu.match = function(files, patterns, options) { + return mu(utils.arrayify(files), patterns, options); }; -mm.makeRe = function(pattern, options) { - return mi.makeRe(pattern, options); +mu.makeRe = function(pattern, options) { + return mm.makeRe(pattern, options); }; -mm.braces = function(pattern, options) { - return mi.braceExpand(pattern, options); +mu.braces = function(pattern, options) { + return mm.braceExpand(pattern, options); }; /** - * Decorate methods onto minimatch for parity with nanomatch + * Decorate methods onto minimatch for parity with micromatch */ -mi.isMatch = function(file, pattern, options) { +mm.isMatch = function(file, pattern, options) { return minimatch(file, pattern, options); }; -mi.match = function(files, pattern, options) { +mm.match = function(files, pattern, options) { return minimatch.match(utils.arrayify(files), pattern, options); }; -mi.makeRe = function(pattern, options) { +mm.makeRe = function(pattern, options) { return minimatch.makeRe(pattern, options); }; -mi.braces = function(pattern, options) { +mm.braces = function(pattern, options) { return minimatch.braceExpand(pattern, options); }; /** - * Detect matcher based on argv, with nanomatch as default + * Detect matcher based on argv, with micromatch as default */ -var matcher = argv.mm ? mm : (argv.mi ? mi : nm); +var matcher = mi; if (argv.bash) { matcher = bash; +} else if (argv.mu) { + matcher = mu; +} else if (argv.mm) { + matcher = mm; } /** @@ -79,6 +83,6 @@ if (argv.bash) { module.exports = matcher; module.exports.bash = bash; -module.exports.nm = nm; -module.exports.mm = mm; module.exports.mi = mi; +module.exports.mu = mu; +module.exports.mm = mm; diff --git a/test/support/parse.js b/test/support/parse.js index 08070ddb..8018b7f2 100644 --- a/test/support/parse.js +++ b/test/support/parse.js @@ -3,13 +3,17 @@ var fs = require('fs'); var path = require('path'); var extend = require('extend-shallow'); -var nm = require('../..'); +var mm = require('../..'); + +/** + * Parse bash test files + */ function parseFiles(pattern, options) { var opts = extend({cwd: process.cwd()}, options); var cwd = opts.cwd; - var files = nm(fs.readdirSync(cwd), pattern); + var files = mm(fs.readdirSync(cwd), pattern); var tests = {}; for (var i = 0; i < files.length; i++) { From 366e829dee5f3b804a18fafaadd68acd76eaf6b0 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:48:00 -0500 Subject: [PATCH 39/68] improve unixification take an array on `.any` --- index.js | 132 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 55 deletions(-) diff --git a/index.js b/index.js index 13bd64ed..d096121c 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ * Module dependencies */ +var util = require('util'); var braces = require('braces'); var toRegex = require('to-regex'); var extend = require('extend-shallow'); @@ -67,7 +68,11 @@ function micromatch(list, patterns, options) { // minimatch.match parity if (negated && keep.length === 0) { - keep = list.map(utils.unixify(options)); + if (options && options.unixify === false) { + keep = list.slice(); + } else { + keep = list.map(utils.unixify(options)); + } } var matches = utils.diff(keep, omit); @@ -96,8 +101,12 @@ function micromatch(list, patterns, options) { */ micromatch.match = function(list, pattern, options) { + if (Array.isArray(pattern)) { + throw new TypeError('expected pattern to be a string'); + } + var unixify = utils.unixify(options); - var isMatch = memoize('isMatch', pattern, options, micromatch.matcher); + var isMatch = memoize('match', pattern, options, micromatch.matcher); list = utils.arrayify(list); var len = list.length; @@ -106,15 +115,10 @@ micromatch.match = function(list, pattern, options) { while (++idx < len) { var ele = list[idx]; - var unix = unixify(ele); - if (ele === pattern || unix === pattern) { - matches.push(unix); - continue; - } - if (isMatch(ele)) { - matches.push(ele); + if (ele === pattern || unix === pattern || isMatch(unix)) { + matches.push((options && options.unixify === false) ? ele : unix); } } @@ -160,6 +164,10 @@ micromatch.match = function(list, pattern, options) { */ micromatch.isMatch = function(str, pattern, options) { + if (typeof str !== 'string') { + throw new TypeError('expected a string: "' + util.inspect(str) + '"'); + } + if (pattern === str) { return true; } @@ -195,7 +203,7 @@ micromatch.not = function(list, patterns, options) { delete opts.ignore; var unixify = utils.unixify(opts); - var unixified = list.map(function(fp) { + var unixified = utils.arrayify(list).map(function(fp) { return unixify(fp, opts); }); @@ -219,17 +227,30 @@ micromatch.not = function(list, patterns, options) { * console.log(mm.any('a.a', 'b.*')); * //=> false * ``` - * @param {String} `str` The string to test. + * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found. * @param {String|Array} `patterns` One or more glob patterns to use for matching. * @param {Object} `options` Any [options](#options) to change how matches are performed * @return {Boolean} Returns true if any patterns match `str` * @api public */ -micromatch.any = function(str, patterns, options) { - patterns = utils.arrayify(patterns); - for (var i = 0; i < patterns.length; i++) { - if (micromatch.isMatch(str, patterns[i], options)) { +micromatch.any = function(list, patterns, options) { + var unixify = utils.unixify(options); + var isMatch = memoize('any', patterns, options, micromatch.matcher); + + list = utils.arrayify(list); + var len = list.length; + var idx = -1; + + while (++idx < len) { + var ele = list[idx]; + if (ele === './' || ele === '') continue; + var unix = unixify(ele); + + if (isMatch(unix)) { + if (options && options.ignore && micromatch.not(ele, options.ignored)) { + continue; + } return true; } } @@ -339,44 +360,45 @@ micromatch.matcher = function matcher(pattern, options) { return utils.compose(pattern, options, matcher); } - function fn() { - var unixify = utils.unixify(options); + // if pattern is a regex + if (pattern instanceof RegExp) { + return test(pattern); + } - // if pattern is a regex - if (pattern instanceof RegExp) { - return function(str) { - return pattern.test(str) || pattern.test(unixify(str)); - }; - } + // if pattern is invalid + if (!utils.isString(pattern)) { + throw new TypeError('expected pattern to be a string or regex'); + } - // if pattern is invalid - if (!utils.isString(pattern)) { - throw new TypeError('expected pattern to be a string or regex'); + // if pattern is a non-glob string + if (!utils.hasSpecialChars(pattern)) { + if (options && options.nocase === true) { + pattern = pattern.toLowerCase(); } + return utils.matchPath(pattern, options); + } - // if pattern is a non-glob string - if (!utils.hasSpecialChars(pattern)) { - if (options && options.nocase === true) { - pattern = pattern.toLowerCase(); - } - return utils.matchPath(pattern, options); - } + // if pattern is a glob string + var re = micromatch.makeRe(pattern, options); - // if pattern is a glob string - var re = micromatch.makeRe(pattern, options); + // if `options.matchBase` or `options.basename` is defined + if (micromatch.matchBase(pattern, options)) { + return utils.matchBasename(re, options); + } - // if `options.matchBase` or `options.basename` is defined - if (micromatch.matchBase(pattern, options)) { - return utils.matchBasename(re, options); - } + function test(regex) { + var unixify = utils.unixify(options); - // everything else... return function(str) { - return re.test(str) || re.test(unixify(str)); + var ele = unixify(str); + if (str === pattern || ele === pattern || regex.test(ele)) { + return true; + } + return false; }; } - return memoize('matcher', pattern, options, fn); + return test(re); }; /** @@ -571,19 +593,6 @@ micromatch.parse = function(pattern, options) { return memoize('parse', pattern, options, parse); }; -/** - * Clear the regex cache. - * - * ```js - * mm.clearCache(); - * ``` - * @api public - */ - -micromatch.clearCache = function() { - micromatch.cache.__data__ = {}; -}; - /** * Compile the given `ast` or string with the given `options`. * @@ -628,6 +637,19 @@ micromatch.compile = function(ast, options) { return memoize('compile', ast.input, options, compile); }; +/** + * Clear the regex cache. + * + * ```js + * mm.clearCache(); + * ``` + * @api public + */ + +micromatch.clearCache = function() { + micromatch.cache.__data__ = {}; +}; + /** * Memoize a generated regex or function. A unique key is generated * from the `type` (usually method name), the `pattern`, and From 479ca23a9470241739baf4f4f98d92f6297bd6a0 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:55:30 -0500 Subject: [PATCH 40/68] update deps --- package.json | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index cecb2356..16f35261 100644 --- a/package.json +++ b/package.json @@ -35,14 +35,14 @@ "dependencies": { "arr-diff": "^3.0.0", "array-unique": "^0.3.2", - "braces": "^2.0.2", + "braces": "^2.0.3", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", - "extglob": "^1.0.0", + "extglob": "^1.1.0", "for-own": "^0.1.4", "fragment-cache": "^0.2.0", - "kind-of": "^3.0.4", - "nanomatch": "^0.3.4", + "kind-of": "^3.1.0", + "nanomatch": "^1.0.0", "object.pick": "^1.2.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", @@ -118,14 +118,13 @@ "reflinks": true }, "reflinks": [ - "braces", - "expand-brackets", "extglob", "glob-object", "minimatch", "multimatch", + "snapdragon", "verb", "verb-generate-readme" ] } -} +} \ No newline at end of file From a055f592005e342859848ca425950f8dd6df5b0e Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:55:43 -0500 Subject: [PATCH 41/68] generate docs --- .verb.md | 129 +++++++++++++-- README.md | 475 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 413 insertions(+), 191 deletions(-) mode change 100755 => 100644 .verb.md mode change 100755 => 100644 README.md diff --git a/.verb.md b/.verb.md old mode 100755 new mode 100644 index 05a83b62..10c96670 --- a/.verb.md +++ b/.verb.md @@ -17,7 +17,7 @@ Use [.isMatch](#ismatch) to get true/false: console.log(mm.isMatch('foo', 'f*')); // true ``` -**Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-minimatch) is easy**: +**Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-multimatch) is easy**: * [mm()](#usage) is the same as [multimatch()][multimatch] * [mm.match()](#match) is the same as [minimatch.match()][minimatch] @@ -33,7 +33,7 @@ Micromatch is [safer][braces]{#braces-is-safe}, [faster](#benchmarks), more accu Moreover, micromatch has: * Better support for the Bash 4.3 specification than minimatch and multimatch -* More than 7,200 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) +* More than 16,000 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) * Better windows support than minimatch and multimatch ### Features @@ -80,6 +80,11 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); //=> ['foo', 'baz'] ``` +## API +{%= apidocs("index.js") %} + + + ## Options - [options.basename](#options-basename) @@ -95,6 +100,7 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); - [options.nullglob](#options-nullglob) - [options.snapdragon](#options-snapdragon) - [options.unescape](#options-unescape) +- [options.unixify](#options-unixify) ### options.basename @@ -229,38 +235,139 @@ Default: `undefined` ### options.unescape -Remove backslashes from glob patterns. +Remove backslashes from returned matches. Type: `Boolean` Default: `undefined` +**Example** -## API -{%= apidocs("index.js") %} +In this example we want to match a literal `*`: + +```js +mm.match(['abc', 'a\\*c'], 'a\\*c'); +//=> ['a\\*c'] + +mm.match(['abc', 'a\\*c'], 'a\\*c', {unescape: true}); +//=> ['a*c'] +``` + +### options.unixify + +Convert path separators on returned files to posix/unix-style forward slashes. + +Type: `Boolean` + +Default: `true` + +**Example** + +```js +mm.match(['a\\b\\c'], 'a/**'); +//=> ['a/b/c'] + +mm.match(['a\\b\\c'], {unixify: false}); +//=> ['a\\b\\c'] +``` + +## Extended globbing + +Micromatch also supports extended globbing features. + +### extglobs + +Extended globbing, as described by the bash man page: + +| **pattern** | **regex equivalent** | **description** | +| --- | --- | --- | +| `?(pattern-list)` | `(... | ...)?` | Matches zero or one occurrence of the given patterns | +| `*(pattern-list)` | `(... | ...)*` | Matches zero or more occurrences of the given patterns | +| `+(pattern-list)` | `(... | ...)+` | Matches one or more occurrences of the given patterns | +| `@(pattern-list)` | `(... | ...)` * | Matches one of the given patterns | +| `!(pattern-list)` | N/A | Matches anything except one of the given patterns | + +* `@` isn't a RegEx character. + +Powered by [extglob](https://github.com/jonschlinkert/extglob). Visit that library for the full range of options or to report extglob related issues. + +See [extglob](https://github.com/jonschlinkert/extglob) for more information about extended globs. + +### braces + +**Expanded braces** + +Braces are expanded when `` + +* range expansion: `a{1..3}b/*.js` expands to: `['a1b/*.js', 'a2b/*.js', 'a3b/*.js']` +* nesting: `a{c,{d,e}}b/*.js` expands to: `['acb/*.js', 'adb/*.js', 'aeb/*.js']` + +**Optimized braces (not expanded)** + +By default, brace patterns work the same way regex logical `OR` operators. For example, `(a|b)` will achieve the same result as `{a,b}`. + +Visit [braces](https://github.com/jonschlinkert/braces) to ask questions and create an issue related to brace-expansion, or to see the full range of features and options related to brace expansion. + +### regex character classes + +Given the list: `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: + +* `[ac].js`: matches both `a` and `c`, returning `['a.js', 'c.js']` +* `[b-d].js`: matches from `b` to `d`, returning `['b.js', 'c.js', 'd.js']` +* `[b-d].js`: matches from `b` to `d`, returning `['b.js', 'c.js', 'd.js']` +* `a/[A-Z].js`: matches and uppercase letter, returning `['a/E.md']` + +Learn about [regex character classes](http://www.regular-expressions.info/charclass.html). + +### regex groups + +Given `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: + +* `(a|c).js`: would match either `a` or `c`, returning `['a.js', 'c.js']` +* `(b|d).js`: would match either `b` or `d`, returning `['b.js', 'd.js']` +* `(b|[A-Z]).js`: would match either `b` or an uppercase letter, returning `['b.js', 'E.js']` + +As with regex, parenthese can be nested, so patterns like `((a|b)|c)/b` will work. But it might be easier to achieve your goal using brace expansion. + +### POSIX bracket expressions + +**Example** + +```js +mm.isMatch('a1', '[[:alpha:][:digit:]]'); +//=> true +``` + +See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more information about bracket expressions. + +*** ## Notes **Bash 4.3 parity** -Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3. Patterns that aren't described by Bash follow wildmatch spec (used by git). +Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3, which is mostly also constistent with minimatch. Patterns that aren't described in enough detail by the Bash spec follow wildmatch spec (used by git). **Escaping** -Backslashes are exclusively and explicitly reserved for escaping characters in a glob pattern, even on windows. This is also the case in minimatch and node-glob, although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212). +Backslashes are exclusively and explicitly reserved for escaping characters in a glob pattern, even on windows. This is the convention in all globbing libs, including minimatch and node-glob, although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212). -To be clear, _a glob pattern is not a filepath_. When you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting for it to work as a glob pattern. The problem is that on windows the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. But since `\\` is an escape character in globs, this means that on windows `path.join('foo', '*')` results in `foo\\*` which tells micromatch that `*` is escaped. +To be clear, _a glob pattern is not a filepath_, it's a [regular language](https://en.wikipedia.org/wiki/Regular_language) that is converted to a JavaScript regular expression. When you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting it to still work as a glob pattern. This causes problems on windows, since the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. Since `\\` is an escape character in globs, on windows `path.join('foo', '*')` would result in `foo\\*`, which tells micromatch to match `*` as a literal character. -Thus you'll need to either do the joining manually or find a lib on npm that does this. +To get around this, you can either do the joining manually or find a lib on npm that does this. ## Benchmarks -Run the [benchmarks](./benchmark): +### Running benchmarks + +Install dev dependencies: ```bash -node benchmark +npm i -d && npm benchmark ``` +### Latest results + As of {%= date() %} (longer bars are better): ```sh diff --git a/README.md b/README.md old mode 100755 new mode 100644 index afec0a07..98fbf8f6 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ * [Features](#features) - [Switching from minimatch](#switching-from-minimatch) - [Switching from multimatch](#switching-from-multimatch) +- [API](#api) - [Options](#options) * [options.basename](#optionsbasename) * [options.cache](#optionscache) @@ -25,9 +26,17 @@ * [options.nullglob](#optionsnullglob) * [options.snapdragon](#optionssnapdragon) * [options.unescape](#optionsunescape) -- [API](#api) + * [options.unixify](#optionsunixify) +- [Extended globbing](#extended-globbing) + * [extglobs](#extglobs) + * [braces](#braces) + * [regex character classes](#regex-character-classes) + * [regex groups](#regex-groups) + * [POSIX bracket expressions](#posix-bracket-expressions) - [Notes](#notes) - [Benchmarks](#benchmarks) + * [Running benchmarks](#running-benchmarks) + * [Latest results](#latest-results) - [About](#about) * [Related projects](#related-projects) * [Contributing](#contributing) @@ -67,7 +76,7 @@ Use [.isMatch](#ismatch) to get true/false: console.log(mm.isMatch('foo', 'f*')); // true ``` -**Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-minimatch) is easy**: +**Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-multimatch) is easy**: * [mm()](#usage) is the same as [multimatch()](https://github.com/sindresorhus/multimatch) * [mm.match()](#match) is the same as [minimatch.match()](https://github.com/isaacs/minimatch) @@ -82,7 +91,7 @@ Micromatch is [safer](https://github.com/jonschlinkert/braces#braces-is-safe), [ Moreover, micromatch has: * Better support for the Bash 4.3 specification than minimatch and multimatch -* More than 7,200 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) +* More than 16,000 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) * Better windows support than minimatch and multimatch ### Features @@ -129,153 +138,9 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); //=> ['foo', 'baz'] ``` -## Options - -* [options.basename](#options-basename) -* [options.cache](#options-cache) -* [options.dot](#options-dot) -* [options.failglob](#options-failglob) -* [options.ignore](#options-ignore) -* [options.matchBase](#options-matchBase) -* [options.nobrace](#options-nobrace) -* [options.nocase](#options-nocase) -* [options.nodupes](#options-nodupes) -* [options.nonull](#options-nonull) -* [options.nullglob](#options-nullglob) -* [options.snapdragon](#options-snapdragon) -* [options.unescape](#options-unescape) - -### options.basename - -Allow glob patterns without slashes to match a file path based on its basename. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `matchBase`. - -Type: `Boolean` - -Default: `false` - -**Example** - -```js -mm(['a/b.js', 'a/c.md'], '*.js'); -//=> [] - -mm(['a/b.js', 'a/c.md'], '*.js', {matchBase: true}); -//=> ['a/b.js'] -``` - -### options.cache - -Disable regex and function memoization. - -Type: `Boolean` - -Default: `undefined` - -### options.dot - -Match dotfiles. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `dot`. - -Type: `Boolean` - -Default: `false` - -### options.failglob - -Similar to the `--failglob` behavior in Bash, throws an error when no matches are found. - -Type: `Boolean` - -Default: `undefined` - -### options.ignore - -String or array of glob patterns to match files to ignore. - -Type: `String|Array` - -Default: `undefined` - -### options.matchBase - -Alias for [options.basename](#options-basename). - -### options.nobrace - -Disable expansion of brace patterns. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `nobrace`. - -Type: `Boolean` - -Default: `undefined` - -See [braces](https://github.com/jonschlinkert/braces) for more information about extended brace expansion. - -### options.nocase - -Use a case-insensitive regex for matching files. Same behavior as [minimatch](https://github.com/isaacs/minimatch). - -Type: `Boolean` - -Default: `undefined` - -### options.nodupes - -Remove duplicate elements from the result array. - -Type: `Boolean` - -Default: `undefined` - -**Example** - -Example of using the `unescape` and `nodupes` options together: - -```js -mm.match(['a/b/c', 'a/b/c'], 'a/b/c'); -//=> ['a/b/c', 'a/b/c'] - -mm.match(['a/b/c', 'a/b/c'], 'a/b/c', {nodupes: true}); -//=> ['abc'] -``` - -### options.nonegate - -Disallow negation (`!`) patterns, and treat leading `!` as a literal character to match. - -Type: `Boolean` - -Default: `undefined` - -### options.nonull - -Alias for [options.nullglob](#options-nullglob). - -### options.nullglob - -If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `nonull`. - -Type: `Boolean` - -Default: `undefined` - -### options.snapdragon - -Pass your own instance of [snapdragon](https://github.com/jonschlinkert/snapdragon), to customize parsers or compilers. - -Type: `Object` - -Default: `undefined` - -### options.unescape - -Remove backslashes from glob patterns. - -Type: `Boolean` - -Default: `undefined` - ## API -### [micromatch](index.js#L39) +### [micromatch](index.js#L40) The main function takes a list of strings and one or more glob patterns to use for matching. @@ -296,7 +161,7 @@ console.log(mm(['a.js', 'a.txt'], ['*.js'])); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Array}**: Returns an array of matches -### [.match](index.js#L98) +### [.match](index.js#L103) Similar to the main function, but `pattern` must be a string. @@ -317,7 +182,7 @@ console.log(mm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Array}**: Returns an array of matches -### [.isMatch](index.js#L162) +### [.isMatch](index.js#L166) Returns true if the specified `string` matches the given glob `pattern`. @@ -340,7 +205,7 @@ console.log(mm.isMatch('a.b', '*.a')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Boolean}**: Returns true if the string matches the glob pattern. -### [.not](index.js#L192) +### [.not](index.js#L200) Returns a list of strings that _DO NOT MATCH_ any of the given `patterns`. @@ -361,7 +226,7 @@ console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Array}**: Returns an array of strings that **do not match** the given patterns. -### [.any](index.js#L229) +### [.any](index.js#L237) Returns true if the given `string` matches any of the given glob `patterns`. @@ -379,12 +244,12 @@ console.log(mm.any('a.a', 'b.*')); **Params** -* `str` **{String}**: The string to test. +* `list` **{String|Array}**: The string or array of strings to test. Returns as soon as the first match is found. * `patterns` **{String|Array}**: One or more glob patterns to use for matching. * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Boolean}**: Returns true if any patterns match `str` -### [.contains](index.js#L259) +### [.contains](index.js#L280) Returns true if the given `string` contains the given pattern. Similar to [.isMatch](#isMatch) but the pattern can match any part of the string. @@ -407,7 +272,7 @@ console.log(mm.contains('aa/bb/cc', '*d')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Boolean}**: Returns true if the patter matches any part of `str`. -### [.matchKeys](index.js#L308) +### [.matchKeys](index.js#L329) Filter the keys of the given object with the given `glob` pattern and `options`. Does not attempt to match nested keys. If you need this feature, use [glob-object](https://github.com/jonschlinkert/glob-object) instead. @@ -429,7 +294,7 @@ console.log(mm.matchKeys(obj, '*b')); * `options` **{Object}**: Any [options](#options) to change how matches are performed * `returns` **{Object}**: Returns an object with only keys that match the given patterns. -### [.matcher](index.js#L337) +### [.matcher](index.js#L358) Returns a memoized matcher function from the given glob `pattern` and `options`. The returned function takes a string to match as its only argument and returns true if the string is a match. @@ -452,7 +317,7 @@ console.log(isMatch('a.b')); * `options` **{Object}**: Any [options](#options) to change how matches are performed. * `returns` **{Function}**: Returns a matcher function. -### [.makeRe](index.js#L394) +### [.makeRe](index.js#L420) Create a regular expression from the given glob `pattern`. @@ -472,7 +337,7 @@ console.log(mm.makeRe('*.js')); * `options` **{Object}**: Any [options](#options) to change how matches are performed. * `returns` **{RegExp}**: Returns a regex created from the given pattern. -### [.braces](index.js#L437) +### [.braces](index.js#L463) Expand the given brace `pattern`. @@ -493,7 +358,7 @@ console.log(mm.braces('foo/{a,b}/bar', {expand: true})); * `options` **{Object}**: Any [options](#options) to change how expansion is performed. See the [braces](https://github.com/jonschlinkert/braces) library for all available options. * `returns` **{Array}** -### [.create](index.js#L490) +### [.create](index.js#L516) Parses the given glob `pattern` and returns an object with the compiled `output` and optional source `map`. @@ -535,7 +400,7 @@ console.log(mm.create('abc/*.js')); * `options` **{Object}**: Any [options](#options) to change how parsing and compiling is performed. * `returns` **{Object}**: Returns an object with the parsed AST, compiled string and optional source map. -### [.parse](index.js#L547) +### [.parse](index.js#L573) Parse the given `str` with the given `options`. @@ -568,17 +433,7 @@ console.log(ast); * `options` **{Object}** * `returns` **{Object}**: Returns an AST -### [.clearCache](index.js#L579) - -Clear the regex cache. - -**Example** - -```js -mm.clearCache(); -``` - -### [.compile](index.js#L613) +### [.compile](index.js#L626) Compile the given `ast` or string with the given `options`. @@ -612,29 +467,289 @@ console.log(mm.compile(ast)); * `options` **{Object}** * `returns` **{Object}**: Returns an object that has an `output` property with the compiled string. +### [.clearCache](index.js#L649) + +Clear the regex cache. + +**Example** + +```js +mm.clearCache(); +``` + +## Options + +* [options.basename](#options-basename) +* [options.cache](#options-cache) +* [options.dot](#options-dot) +* [options.failglob](#options-failglob) +* [options.ignore](#options-ignore) +* [options.matchBase](#options-matchBase) +* [options.nobrace](#options-nobrace) +* [options.nocase](#options-nocase) +* [options.nodupes](#options-nodupes) +* [options.nonull](#options-nonull) +* [options.nullglob](#options-nullglob) +* [options.snapdragon](#options-snapdragon) +* [options.unescape](#options-unescape) +* [options.unixify](#options-unixify) + +### options.basename + +Allow glob patterns without slashes to match a file path based on its basename. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `matchBase`. + +Type: `Boolean` + +Default: `false` + +**Example** + +```js +mm(['a/b.js', 'a/c.md'], '*.js'); +//=> [] + +mm(['a/b.js', 'a/c.md'], '*.js', {matchBase: true}); +//=> ['a/b.js'] +``` + +### options.cache + +Disable regex and function memoization. + +Type: `Boolean` + +Default: `undefined` + +### options.dot + +Match dotfiles. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `dot`. + +Type: `Boolean` + +Default: `false` + +### options.failglob + +Similar to the `--failglob` behavior in Bash, throws an error when no matches are found. + +Type: `Boolean` + +Default: `undefined` + +### options.ignore + +String or array of glob patterns to match files to ignore. + +Type: `String|Array` + +Default: `undefined` + +### options.matchBase + +Alias for [options.basename](#options-basename). + +### options.nobrace + +Disable expansion of brace patterns. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `nobrace`. + +Type: `Boolean` + +Default: `undefined` + +See [braces](https://github.com/jonschlinkert/braces) for more information about extended brace expansion. + +### options.nocase + +Use a case-insensitive regex for matching files. Same behavior as [minimatch](https://github.com/isaacs/minimatch). + +Type: `Boolean` + +Default: `undefined` + +### options.nodupes + +Remove duplicate elements from the result array. + +Type: `Boolean` + +Default: `undefined` + +**Example** + +Example of using the `unescape` and `nodupes` options together: + +```js +mm.match(['a/b/c', 'a/b/c'], 'a/b/c'); +//=> ['a/b/c', 'a/b/c'] + +mm.match(['a/b/c', 'a/b/c'], 'a/b/c', {nodupes: true}); +//=> ['abc'] +``` + +### options.nonegate + +Disallow negation (`!`) patterns, and treat leading `!` as a literal character to match. + +Type: `Boolean` + +Default: `undefined` + +### options.nonull + +Alias for [options.nullglob](#options-nullglob). + +### options.nullglob + +If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `nonull`. + +Type: `Boolean` + +Default: `undefined` + +### options.snapdragon + +Pass your own instance of [snapdragon](https://github.com/jonschlinkert/snapdragon), to customize parsers or compilers. + +Type: `Object` + +Default: `undefined` + +### options.unescape + +Remove backslashes from returned matches. + +Type: `Boolean` + +Default: `undefined` + +**Example** + +In this example we want to match a literal `*`: + +```js +mm.match(['abc', 'a\\*c'], 'a\\*c'); +//=> ['a\\*c'] + +mm.match(['abc', 'a\\*c'], 'a\\*c', {unescape: true}); +//=> ['a*c'] +``` + +### options.unixify + +Convert path separators on returned files to posix/unix-style forward slashes. + +Type: `Boolean` + +Default: `true` + +**Example** + +```js +mm.match(['a\\b\\c'], 'a/**'); +//=> ['a/b/c'] + +mm.match(['a\\b\\c'], {unixify: false}); +//=> ['a\\b\\c'] +``` + +## Extended globbing + +Micromatch also supports extended globbing features. + +### extglobs + +Extended globbing, as described by the bash man page: + +| **pattern** | **regex equivalent** | **description** | +| --- | --- | --- | +| `?(pattern-list)` | `(... | ...)?` | Matches zero or one occurrence of the given patterns | +| `*(pattern-list)` | `(... | ...)*` | Matches zero or more occurrences of the given patterns | +| `+(pattern-list)` | `(... | ...)+` | Matches one or more occurrences of the given patterns | +| `@(pattern-list)` | `(... | ...)` * | Matches one of the given patterns | +| `!(pattern-list)` | N/A | Matches anything except one of the given patterns | + +* `@` isn't a RegEx character. + +Powered by [extglob](https://github.com/jonschlinkert/extglob). Visit that library for the full range of options or to report extglob related issues. + +See [extglob](https://github.com/jonschlinkert/extglob) for more information about extended globs. + +### braces + +**Expanded braces** + +Braces are expanded when `` + +* range expansion: `a{1..3}b/*.js` expands to: `['a1b/*.js', 'a2b/*.js', 'a3b/*.js']` +* nesting: `a{c,{d,e}}b/*.js` expands to: `['acb/*.js', 'adb/*.js', 'aeb/*.js']` + +**Optimized braces (not expanded)** + +By default, brace patterns work the same way regex logical `OR` operators. For example, `(a|b)` will achieve the same result as `{a,b}`. + +Visit [braces](https://github.com/jonschlinkert/braces) to ask questions and create an issue related to brace-expansion, or to see the full range of features and options related to brace expansion. + +### regex character classes + +Given the list: `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: + +* `[ac].js`: matches both `a` and `c`, returning `['a.js', 'c.js']` +* `[b-d].js`: matches from `b` to `d`, returning `['b.js', 'c.js', 'd.js']` +* `[b-d].js`: matches from `b` to `d`, returning `['b.js', 'c.js', 'd.js']` +* `a/[A-Z].js`: matches and uppercase letter, returning `['a/E.md']` + +Learn about [regex character classes](http://www.regular-expressions.info/charclass.html). + +### regex groups + +Given `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: + +* `(a|c).js`: would match either `a` or `c`, returning `['a.js', 'c.js']` +* `(b|d).js`: would match either `b` or `d`, returning `['b.js', 'd.js']` +* `(b|[A-Z]).js`: would match either `b` or an uppercase letter, returning `['b.js', 'E.js']` + +As with regex, parenthese can be nested, so patterns like `((a|b)|c)/b` will work. But it might be easier to achieve your goal using brace expansion. + +### POSIX bracket expressions + +**Example** + +```js +mm.isMatch('a1', '[[:alpha:][:digit:]]'); +//=> true +``` + +See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more information about bracket expressions. + +*** + ## Notes **Bash 4.3 parity** -Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3. Patterns that aren't described by Bash follow wildmatch spec (used by git). +Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3, which is mostly also constistent with minimatch. Patterns that aren't described in enough detail by the Bash spec follow wildmatch spec (used by git). **Escaping** -Backslashes are exclusively and explicitly reserved for escaping characters in a glob pattern, even on windows. This is also the case in minimatch and node-glob, although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212). +Backslashes are exclusively and explicitly reserved for escaping characters in a glob pattern, even on windows. This is the convention in all globbing libs, including minimatch and node-glob, although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212). -To be clear, _a glob pattern is not a filepath_. When you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting for it to work as a glob pattern. The problem is that on windows the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. But since `\\` is an escape character in globs, this means that on windows `path.join('foo', '*')` results in `foo\\*` which tells micromatch that `*` is escaped. +To be clear, _a glob pattern is not a filepath_, it's a [regular language](https://en.wikipedia.org/wiki/Regular_language) that is converted to a JavaScript regular expression. When you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting it to still work as a glob pattern. This causes problems on windows, since the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. Since `\\` is an escape character in globs, on windows `path.join('foo', '*')` would result in `foo\\*`, which tells micromatch to match `*` as a literal character. -Thus you'll need to either do the joining manually or find a lib on npm that does this. +To get around this, you can either do the joining manually or find a lib on npm that does this. ## Benchmarks -Run the [benchmarks](./benchmark): +### Running benchmarks + +Install dev dependencies: ```bash -node benchmark +npm i -d && npm benchmark ``` -As of November 24, 2016 (longer bars are better): +### Latest results + +As of December 12, 2016 (longer bars are better): ```sh # braces-globstar-large-list @@ -707,7 +822,7 @@ Please read the [contributing guide](.github/contributing.md) for avice on openi ### Contributors | **Commits** | **Contributor**
| -| --- | --- | +| --- | --- | --- | --- | --- | | 345 | [jonschlinkert](https://github.com/jonschlinkert) | | 12 | [es128](https://github.com/es128) | | 3 | [paulmillr](https://github.com/paulmillr) | @@ -751,4 +866,4 @@ Released under the [MIT license](https://github.com/jonschlinkert/micromatch/blo *** -_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on November 24, 2016._ \ No newline at end of file +_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on December 12, 2016._ \ No newline at end of file From 09e899a839b6cab8907896a3232332b126f4f417 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 12 Dec 2016 21:59:52 -0500 Subject: [PATCH 42/68] move test --- test/globstars.js | 8 -------- test/minimatch.js | 18 ++++++++++++++---- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/test/globstars.js b/test/globstars.js index c5b36230..2452d414 100644 --- a/test/globstars.js +++ b/test/globstars.js @@ -104,12 +104,4 @@ describe('globstars', function() { mm(fixtures, '\\*\\**.md', ['**a.md', '**.md']); mm(fixtures, '\\*\\*.md', ['**.md']); }); - - // related to https://github.com/isaacs/minimatch/issues/67 - it('should work consistently with `makeRe` and matcher functions', function() { - var re = mm.makeRe('node_modules/foobar/**/*.bar'); - assert(re.test('node_modules/foobar/foo.bar')); - assert(mm.isMatch('node_modules/foobar/foo.bar', 'node_modules/foobar/**/*.bar')); - mm(['node_modules/foobar/foo.bar'], 'node_modules/foobar/**/*.bar', ['node_modules/foobar/foo.bar']); - }); }); diff --git a/test/minimatch.js b/test/minimatch.js index b39da9f3..ea5d0543 100644 --- a/test/minimatch.js +++ b/test/minimatch.js @@ -43,8 +43,8 @@ describe('minimatch issues (as of 12/7/2016)', function() { assert(mm.isMatch('./foo/bar.js', '**/foo/**')); assert(mm.isMatch('./foo/bar.txt', 'foo/**/*.txt')); assert(mm.makeRe('./foo/**/*.txt' ).test( 'foo/bar.txt')); - assert(!mm.isMatch('./n/!(axios)/**', 'n/axios/a.js')); - assert(!mm.makeRe('./n/!(axios)/**').test('n/axios/a.js')); + assert(!mm.isMatch('./foo/!(bar)/**', 'foo/bar/a.js')); + assert(!mm.makeRe('./foo/!(bar)/**').test('foo/bar/a.js')); }); it('https://github.com/isaacs/minimatch/issues/50', function() { @@ -53,7 +53,17 @@ describe('minimatch issues (as of 12/7/2016)', function() { assert(mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[abc\\].txt', {nocase: true})); }); + it('https://github.com/isaacs/minimatch/issues/67 (should work consistently with `makeRe` and matcher functions)', function() { + var re = mm.makeRe('node_modules/foobar/**/*.bar'); + assert(re.test('node_modules/foobar/foo.bar')); + assert(mm.isMatch('node_modules/foobar/foo.bar', 'node_modules/foobar/**/*.bar')); + mm(['node_modules/foobar/foo.bar'], 'node_modules/foobar/**/*.bar', ['node_modules/foobar/foo.bar']); + }); + it('https://github.com/isaacs/minimatch/issues/75', function() { + assert(mm.isMatch('foo/baz.qux.js', 'foo/@(baz.qux).js')); + assert(mm.isMatch('foo/baz.qux.js', 'foo/+(baz.qux).js')); + assert(mm.isMatch('foo/baz.qux.js', 'foo/*(baz.qux).js')); assert(!mm.isMatch('foo/baz.qux.js', 'foo/!(baz.qux).js')); assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/*/!(baz.qux).js')); assert(!mm.isMatch('foo/bar/bazqux.js', '**/!(bazqux).js')); @@ -79,8 +89,8 @@ describe('minimatch issues (as of 12/7/2016)', function() { }); it('https://github.com/isaacs/minimatch/issues/83', function() { - assert(!mm.makeRe('n/!(axios)/**').test('n/axios/a.js')); - assert(!mm.isMatch('n/!(axios)/**', 'n/axios/a.js')); + assert(!mm.makeRe('foo/!(bar)/**').test('foo/bar/a.js')); + assert(!mm.isMatch('foo/!(bar)/**', 'foo/bar/a.js')); }); }); From 93ecce7f8ad72e9c85d28d40f9cb68ad0e79949c Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Tue, 13 Dec 2016 12:14:30 -0500 Subject: [PATCH 43/68] update unit test number --- .verb.md | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.verb.md b/.verb.md index 10c96670..a05eab13 100644 --- a/.verb.md +++ b/.verb.md @@ -33,8 +33,8 @@ Micromatch is [safer][braces]{#braces-is-safe}, [faster](#benchmarks), more accu Moreover, micromatch has: * Better support for the Bash 4.3 specification than minimatch and multimatch -* More than 16,000 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) * Better windows support than minimatch and multimatch +* More than 36,000 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail a great number of the tests) ### Features diff --git a/README.md b/README.md index 98fbf8f6..c6e3ab0c 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,8 @@ Micromatch is [safer](https://github.com/jonschlinkert/braces#braces-is-safe), [ Moreover, micromatch has: * Better support for the Bash 4.3 specification than minimatch and multimatch -* More than 16,000 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail many of the tests) * Better windows support than minimatch and multimatch +* More than 36,000 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail a great number of the tests) ### Features @@ -749,7 +749,7 @@ npm i -d && npm benchmark ### Latest results -As of December 12, 2016 (longer bars are better): +As of December 13, 2016 (longer bars are better): ```sh # braces-globstar-large-list @@ -866,4 +866,4 @@ Released under the [MIT license](https://github.com/jonschlinkert/micromatch/blo *** -_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on December 12, 2016._ \ No newline at end of file +_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on December 13, 2016._ \ No newline at end of file From b8603703c85d68d094922cf9b47ddd903f8aef38 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Tue, 14 Mar 2017 16:16:32 -0400 Subject: [PATCH 44/68] remove unused files --- test/reference/index.js | 1 - test/reference/matcher.js | 11 ---- test/reference/negations.js | 107 ------------------------------------ 3 files changed, 119 deletions(-) delete mode 100644 test/reference/index.js delete mode 100644 test/reference/matcher.js delete mode 100644 test/reference/negations.js diff --git a/test/reference/index.js b/test/reference/index.js deleted file mode 100644 index 23b2930d..00000000 --- a/test/reference/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('export-files')(__dirname); diff --git a/test/reference/matcher.js b/test/reference/matcher.js deleted file mode 100644 index 186202f0..00000000 --- a/test/reference/matcher.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -var argv = require('yargs-parser')(process.argv.slice(2)); -var mm = require('micromatch'); - -if ('mm' in argv) { - mm = require('minimatch'); - mm.minimatch = true; -} - -module.exports = mm; diff --git a/test/reference/negations.js b/test/reference/negations.js deleted file mode 100644 index 0371de1d..00000000 --- a/test/reference/negations.js +++ /dev/null @@ -1,107 +0,0 @@ -'use strict'; - -/** - * minimatch "tricky negations test" - */ - -module.exports = { - options: { nonegate: true }, - cases: { - 'bar.min.js': { - '*.!(js|css)': true, - '!*.+(js|css)': false, - '*.+(js|css)': true - }, - - 'a-integration-test.js': { - '*.!(j)': true, - '!(*-integration-test.js)': false, - '*-!(integration-)test.js': true, - '*-!(integration)-test.js': false, - '*!(-integration)-test.js': true, - '*!(-integration-)test.js': true, - '*!(integration)-test.js': true, - '*!(integration-test).js': true, - '*-!(integration-test).js': true, - '*-!(integration-test.js)': true, - '*-!(integra)tion-test.js': false, - '*-integr!(ation)-test.js': false, - '*-integr!(ation-t)est.js': false, - '*-i!(ntegration-)test.js': false, - '*i!(ntegration-)test.js': true, - '*te!(gration-te)st.js': true, - '*-!(integration)?test.js': false, - '*?!(integration)?test.js': true - }, - - 'foo-integration-test.js': { - 'foo-integration-test.js': true, - '!(*-integration-test.js)': false - }, - - 'foo.jszzz.js': { - '*.!(js).js': true - }, - - 'asd.jss': { - '*.!(js)': true - }, - - 'asd.jss.xyz': { - '*.!(js).!(xy)': true - }, - - 'asd.jss.xy': { - '*.!(js).!(xy)': false - }, - - 'asd.js.xyz': { - '*.!(js).!(xy)': false - }, - - 'asd.js.xy': { - '*.!(js).!(xy)': false - }, - - 'asd.sjs.zxy': { - '*.!(js).!(xy)': true - }, - - 'asd..xyz': { - '*.!(js).!(xy)': true - }, - - 'asd..xy': { - '*.!(js).!(xy)': false, - '*.!(js|x).!(xy)': false - }, - - 'foo.js.js': { - '*.!(js)': false, // Bash 4.3 disagrees! - '*.!(js)*': false, // Bash 4.3 disagrees! - '*.!(js)+': false, - '*.!(js)*.!(js)': false, - }, - - 'testjson.json': { - '*(*.json|!(*.js))': true, - '+(*.json|!(*.js))': true, - '@(*.json|!(*.js))': true, - '?(*.json|!(*.js))': true - }, - - 'foojs.js': { - '*(*.json|!(*.js))': false, - '+(*.json|!(*.js))': false, - '@(*.json|!(*.js))': false, - '?(*.json|!(*.js))': false - }, - - 'other.bar': { - '*(*.json|!(*.js))': true, - '+(*.json|!(*.js))': true, - '@(*.json|!(*.js))': true, - '?(*.json|!(*.js))': true - } - } -}; From de7c6f39a7fd2b970baad3afcba534e174cfa901 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Tue, 14 Mar 2017 16:21:56 -0400 Subject: [PATCH 45/68] run update and lint-deps --- .gitignore | 7 ++++++- .travis.yml | 2 ++ LICENSE | 2 +- package.json | 38 +++++++++++++++++++++++++------------- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index ebe74fab..0a16ee9c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,11 +12,16 @@ coverage node_modules npm-debug.log +# yarn +yarn.lock +yarn-error.log + # misc _gh_pages +_draft +_drafts bower_components vendor temp tmp TODO.md -yarn.lock \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 8acd4608..58dcd48c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,9 @@ os: language: node_js node_js: - node + - '7' - '6' + - '5' - '4' - '0.12' - '0.10' diff --git a/LICENSE b/LICENSE index 842218cf..d734237b 100755 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2016, Jon Schlinkert +Copyright (c) 2014-2017, Jon Schlinkert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/package.json b/package.json index 16f35261..1d12effc 100644 --- a/package.json +++ b/package.json @@ -5,16 +5,16 @@ "homepage": "https://github.com/jonschlinkert/micromatch", "author": "Jon Schlinkert (https://github.com/jonschlinkert)", "contributors": [ - "Amila Welihinda (http://amilawelihinda.com)", + "Amila Welihinda (amilajack.com)", "Bogdan Chadkin (https://github.com/TrySound)", - "Brian Woodward (https://github.com/doowb)", - "Charlike Mike Reagent (http://www.tunnckocore.tk)", + "Brian Woodward (https://twitter.com/doowb)", + "Charlike Mike Reagent (https://i.am.charlike.online)", "Elan Shanker (https://github.com/es128)", "Fabrício Matté (http://ultcombo.js.org)", "Jon Schlinkert (http://twitter.com/jonschlinkert)", "Martin Kolárik (http://kolarik.sk)", "Paul Miller (paulmillr.com)", - "Tom Byrer (https://github.com/tomByrer)" + "Tom Byrer (https://github.com/tomByrer)" ], "repository": "jonschlinkert/micromatch", "bugs": { @@ -39,30 +39,35 @@ "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "extglob": "^1.1.0", - "for-own": "^0.1.4", "fragment-cache": "^0.2.0", "kind-of": "^3.1.0", - "nanomatch": "^1.0.0", + "nanomatch": "^1.0.1", "object.pick": "^1.2.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" }, "devDependencies": { + "ansi-cyan": "^0.1.1", "bash-match": "^0.2.0", - "export-files": "^2.1.1", + "benchmarked": "^0.2.5", + "for-own": "^1.0.0", "fs-exists-sync": "^0.1.0", "gulp": "^3.9.1", "gulp-eslint": "^3.0.1", "gulp-format-md": "^0.1.11", "gulp-istanbul": "^1.1.1", - "gulp-mocha": "^3.0.1", - "gulp-unused": "^0.2.0", - "is-windows": "^0.2.0", + "gulp-mocha": "^4.1.0", + "gulp-unused": "^0.2.1", + "is-object": "^1.0.1", + "is-primitive": "^2.0.0", + "is-windows": "^1.0.0", "minimatch": "^3.0.3", - "mocha": "^3.1.2", + "mocha": "^3.2.0", "multimatch": "^2.1.0", - "yargs-parser": "^4.0.2" + "repeat-string": "^1.6.1", + "write": "^0.3.2", + "yargs-parser": "^5.0.0" }, "keywords": [ "bash", @@ -93,6 +98,13 @@ "shell", "wildcard" ], + "lintDeps": { + "devDependencies": { + "files": [ + "test/{reference,support}/*.js" + ] + } + }, "verb": { "toc": true, "layout": "default", @@ -127,4 +139,4 @@ "verb-generate-readme" ] } -} \ No newline at end of file +} From 8cf11462878b119899231690d210dd62347772f3 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Tue, 14 Mar 2017 16:44:47 -0400 Subject: [PATCH 46/68] remove unnecessary backslashes --- lib/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils.js b/lib/utils.js index 11699112..24c0f890 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -142,7 +142,7 @@ utils.isObject = function(val) { */ utils.escapeRegex = function(str) { - return str.replace(/[\-\[\]{}()^$|\s*+?.\\\/]/g, '\\$&'); + return str.replace(/[-[\]{}()^$|\s*+?.\\\/]/g, '\\$&'); }; /** From 9188fbcaad6732482410612a4145953231c978a2 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Tue, 14 Mar 2017 16:45:42 -0400 Subject: [PATCH 47/68] update deps --- appveyor.yml | 2 ++ gulpfile.js | 7 ------- package.json | 3 +-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 71b3df58..3b8ac52c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,8 +2,10 @@ environment: matrix: # node.js + - nodejs_version: "7.0" - nodejs_version: "6.0" - nodejs_version: "4.0" + - nodejs_version: "5.0" - nodejs_version: "0.12" - nodejs_version: "0.10" diff --git a/gulpfile.js b/gulpfile.js index 857a63e4..10488039 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -4,7 +4,6 @@ var gulp = require('gulp'); var mocha = require('gulp-mocha'); var unused = require('gulp-unused'); var istanbul = require('gulp-istanbul'); -var eslint = require('gulp-eslint'); gulp.task('coverage', function() { return gulp.src(['index.js', 'lib/*.js']) @@ -18,12 +17,6 @@ gulp.task('test', ['coverage'], function() { .pipe(istanbul.writeReports()); }); -gulp.task('lint', function() { - return gulp.src(['*.js', 'lib/*.js', 'test/{*,support/*}.js']) - .pipe(eslint()) - .pipe(eslint.format()); -}); - gulp.task('unused', function() { return gulp.src(['index.js', 'lib/*.js']) .pipe(unused({keys: Object.keys(require('./lib/utils.js'))})); diff --git a/package.json b/package.json index 1d12effc..34db6b19 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "extglob": "^1.1.0", - "fragment-cache": "^0.2.0", + "fragment-cache": "^0.2.1", "kind-of": "^3.1.0", "nanomatch": "^1.0.1", "object.pick": "^1.2.0", @@ -54,7 +54,6 @@ "for-own": "^1.0.0", "fs-exists-sync": "^0.1.0", "gulp": "^3.9.1", - "gulp-eslint": "^3.0.1", "gulp-format-md": "^0.1.11", "gulp-istanbul": "^1.1.1", "gulp-mocha": "^4.1.0", From f565c408e4681a9447534aa448405d339557dd0e Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 3 Apr 2017 17:05:31 -0400 Subject: [PATCH 48/68] update notes about backslashes --- .verb.md | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/.verb.md b/.verb.md index a05eab13..e9a45e06 100644 --- a/.verb.md +++ b/.verb.md @@ -23,6 +23,9 @@ console.log(mm.isMatch('foo', 'f*')); // true * [mm.match()](#match) is the same as [minimatch.match()][minimatch] * use [mm.isMatch()](#ismatch) instead of [minimatch()][minimatch] +**Heads up!** + +There is one notable difference between micromatch and minimatch in regards to how backslashes are handled. See [the notes about backslashes](#backslashes) for more information. ## Why use micromatch? @@ -344,15 +347,37 @@ See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more ## Notes -**Bash 4.3 parity** +### Bash 4.3 parity Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3, which is mostly also constistent with minimatch. Patterns that aren't described in enough detail by the Bash spec follow wildmatch spec (used by git). -**Escaping** +### Backslashes + +There is an important, notable difference between minimatch and micromatch _in regards to how backslashes are handled_ in glob patterns. + +- Micromatch exclusively and explicitly reserves backslashes for escaping characters in a glob pattern, even on windows. This is consistent with bash behavior. +- Minimatch converts all backslashes to forward slashes, which means you can't use backslashes to escape any characters in your glob patterns. + +We made this decision for micromatch for a couple of reasons: + +- consistency with bash conventions. +- glob patterns are not filepaths. They are a type of [regular language](https://en.wikipedia.org/wiki/Regular_language) that is converted to a JavaScript regular expression. Thus, when forward slashes are defined in a glob pattern, the resulting regular expression will match windows or POSIX path separators just fine. + +**A note about joining paths to globs** + +Note that when you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting it to still work as a glob pattern. This causes problems on windows, since the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. + +In other words, since `\\` is reserved as an escape character in globs, on windows `path.join('foo', '*')` would result in `foo\\*`, which tells micromatch to match `*` as a literal character (fwiw this is the same behavior as bash). + + + +This is the convention in all mainstream globbing libs, including bash glob, minimatch and node-glob (although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212) + + + +, and minimatch enforces this convention by converting backslashes to forward slashes). -Backslashes are exclusively and explicitly reserved for escaping characters in a glob pattern, even on windows. This is the convention in all globbing libs, including minimatch and node-glob, although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212). -To be clear, _a glob pattern is not a filepath_, it's a [regular language](https://en.wikipedia.org/wiki/Regular_language) that is converted to a JavaScript regular expression. When you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting it to still work as a glob pattern. This causes problems on windows, since the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. Since `\\` is an escape character in globs, on windows `path.join('foo', '*')` would result in `foo\\*`, which tells micromatch to match `*` as a literal character. To get around this, you can either do the joining manually or find a lib on npm that does this. From edf074aed5e47096ca31015868e2ebe0d70c5dd6 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 3 Apr 2017 17:05:43 -0400 Subject: [PATCH 49/68] wording --- test/api.contains.js | 2 +- test/options.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/api.contains.js b/test/api.contains.js index 2b1642c2..fb96f90c 100644 --- a/test/api.contains.js +++ b/test/api.contains.js @@ -28,7 +28,7 @@ describe('.contains()', function() { assert(mm.contains('abcd', 'ab')); }); - it('should match with common glob patterns', function() { + it('should be true when a glob pattern partially matches the path', function() { assert(mm.contains('a/b/c', 'a/*')); assert(mm.contains('/ab', '/a')); assert(mm.contains('/ab', '/*')); diff --git a/test/options.js b/test/options.js index 7fc8d293..cdea2a0d 100644 --- a/test/options.js +++ b/test/options.js @@ -193,7 +193,7 @@ describe('options', function() { }); describe('options.unixify', function() { - it('should unixify file paths', function() { + it('should unixify file paths by default', function() { mm(['a\\b\\c.md'], '**/*.md', ['a/b/c.md']); mm(['a\\b\\c.md'], '**/*.md', ['a\\b\\c.md'], {unixify: false}); }); From 41eb8a2078d91b547bb526ca9d32431853d48560 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 3 Apr 2017 17:06:57 -0400 Subject: [PATCH 50/68] improve logic for unix vs windows path handling --- index.js | 35 +++++++++------- lib/utils.js | 115 ++++++++++++++++++++++++++++++++++----------------- package.json | 13 ++++-- 3 files changed, 107 insertions(+), 56 deletions(-) diff --git a/index.js b/index.js index d096121c..f5892944 100644 --- a/index.js +++ b/index.js @@ -114,11 +114,11 @@ micromatch.match = function(list, pattern, options) { var matches = []; while (++idx < len) { - var ele = list[idx]; - var unix = unixify(ele); + var origPath = list[idx]; + var unixPath = unixify(origPath); - if (ele === pattern || unix === pattern || isMatch(unix)) { - matches.push((options && options.unixify === false) ? ele : unix); + if (origPath === pattern || unixPath === pattern || isMatch(unixPath)) { + matches.push(utils.value(origPath, unixPath, options)); } } @@ -202,14 +202,19 @@ micromatch.not = function(list, patterns, options) { var ignore = opts.ignore; delete opts.ignore; + list = utils.arrayify(list); var unixify = utils.unixify(opts); - var unixified = utils.arrayify(list).map(function(fp) { - return unixify(fp, opts); - }); + var res = []; - var matches = utils.diff(unixified, micromatch(unixified, patterns, opts)); + for (var i = 0; i < list.length; i++) { + var origPath = list[i]; + var unixPath = unixify(origPath); + res.push(utils.value(origPath, unixPath, opts)); + } + + var matches = utils.diff(res, micromatch(res, patterns, opts)); if (ignore) { - matches = utils.diff(matches, micromatch(unixified, ignore)); + matches = utils.diff(matches, micromatch(res, ignore)); } return opts.nodupes !== false ? utils.unique(matches) : matches; @@ -271,19 +276,19 @@ micromatch.any = function(list, patterns, options) { * //=> false * ``` * @param {String} `str` The string to match. - * @param {String} `pattern` Glob pattern to use for matching. + * @param {String|Array} `patterns` Glob pattern to use for matching. * @param {Object} `options` Any [options](#options) to change how matches are performed * @return {Boolean} Returns true if the patter matches any part of `str`. * @api public */ -micromatch.contains = function(str, pattern, options) { - if (pattern === str) { +micromatch.contains = function(str, patterns, options) { + if (patterns === str) { return true; } - if (utils.isSimpleChar(pattern)) { - return str === pattern; + if (utils.isSimpleChar(patterns)) { + return str === patterns; } var opts = extend({}, options); @@ -291,7 +296,7 @@ micromatch.contains = function(str, pattern, options) { opts.strictOpen = false; opts.contains = true; - return micromatch(str, pattern, opts).length > 0; + return micromatch(str, patterns, opts).length > 0; }; /** diff --git a/lib/utils.js b/lib/utils.js index 24c0f890..19060c63 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -175,7 +175,7 @@ utils.hasSpecialChars = function(str) { */ utils.unescape = function(str) { - return utils.normalize(str.replace(/\\(\W)/g, '$1')); + return utils.toPosixPath(str.replace(/\\(\W)/g, '$1')); }; /** @@ -185,7 +185,7 @@ utils.unescape = function(str) { * @return {String} */ -utils.normalize = function(str) { +utils.toPosixPath = function(str) { return str.replace(/\\+/g, '/'); }; @@ -238,6 +238,24 @@ utils.matchPath = function(pattern, options) { : utils.equalsPattern(pattern, options); }; +/** + * Returns true if the given (original) filepath or unixified path are equal + * to the given pattern. + */ + +utils._equals = function(filepath, unixPath, pattern) { + return pattern === filepath || pattern === unixPath; +}; + +/** + * Returns true if the given (original) filepath or unixified path contain + * the given pattern. + */ + +utils._contains = function(filepath, unixPath, pattern) { + return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; +}; + /** * Returns a function that returns true if the given * pattern is the same as a given `filepath` @@ -248,13 +266,15 @@ utils.matchPath = function(pattern, options) { utils.equalsPattern = function(pattern, options) { var unixify = utils.unixify(options); + options = options || {}; - return function(filepath) { - filepath = utils.stripPrefix(filepath); - if (options && options.nocase === true) { - filepath = filepath.toLowerCase(); + return function fn(filepath) { + var equal = utils._equals(filepath, unixify(filepath), pattern); + if (equal === true || options.nocase !== true) { + return equal; } - return pattern === filepath || pattern === unixify(filepath); + var lower = filepath.toLowerCase(); + return utils._equals(lower, unixify(lower), pattern); }; }; @@ -269,12 +289,12 @@ utils.equalsPattern = function(pattern, options) { utils.containsPattern = function(pattern, options) { var unixify = utils.unixify(options); return function(filepath) { - filepath = utils.stripPrefix(filepath); - if (options && options.nocase === true) { - return unixify(filepath.toLowerCase()).indexOf(pattern) !== -1; - } else { - return unixify(filepath).indexOf(pattern) !== -1; + var contains = utils._contains(filepath, unixify(filepath), pattern); + if (contains === true || options.nocase !== true) { + return contains; } + var lower = filepath.toLowerCase(); + return utils._contains(lower, unixify(lower), pattern); }; }; @@ -293,36 +313,57 @@ utils.matchBasename = function(re) { }; /** - * Normalize all slashes in a file path or glob pattern to - * forward slashes. + * Returns the given value unchanced. + * @return {any} */ -utils.unixify = function(options) { - var type = path.sep === '\\' ? 'backslash' : 'slash'; - var key = utils.createKey('unixify' + type, options); +utils.identity = function(val) { + return val; +}; - if (cache.hasOwnProperty(key)) { - return cache[key]; +/** + * Determines the filepath to return based on the provided options. + * @return {any} + */ + +utils.value = function(origPath, unixPath, options) { + if (typeof options === 'undefined' || options.unixify !== false) { + return unixPath; } + return origPath; +}; - var unixify = function(filepath) { - return utils.stripPrefix(filepath); - }; +/** + * Returns true if the platform is windows, or `path.sep` is `\\`. + * This is defined as a function to allow `path.sep` to be set in unit tests, + * or by the user, if there is a reason to do so. + * @return {Boolean} + */ - options = options || {}; - if (type === 'backslash' || options.unixify === true || options.normalize === true) { - unixify = function(filepath) { - return utils.stripPrefix(utils.normalize(filepath)); - }; - } +utils.isWindows = function() { + return path.sep === '\\' || process.platform === 'win32'; +}; - if (options.unescape === true) { - var fn = function(filepath) { - return unixify(utils.unescape(filepath)); - }; - cache[key] = fn; - return fn; - } - cache[key] = unixify; - return unixify; +/** + * Returns a function that normalizes slashes in a string to forward + * slashes, strips `./` from beginning of paths, and optionally unescapes + * special characters. + * @return {Function} + */ + +utils.unixify = function(options) { + options = options || {}; + return function(filepath) { + if (utils.isWindows() || options.unixify === true) { + filepath = utils.toPosixPath(filepath); + } + if (options.stripPrefix !== false) { + filepath = utils.stripPrefix(filepath); + } + if (options.unescape === true) { + filepath = utils.unescape(filepath); + } + return filepath; + }; }; + diff --git a/package.json b/package.json index 34db6b19..4ae33c37 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "homepage": "https://github.com/jonschlinkert/micromatch", "author": "Jon Schlinkert (https://github.com/jonschlinkert)", "contributors": [ - "Amila Welihinda (amilajack.com)", + "Amila Welihinda (amilajack.com)", "Bogdan Chadkin (https://github.com/TrySound)", "Brian Woodward (https://twitter.com/doowb)", "Charlike Mike Reagent (https://i.am.charlike.online)", @@ -41,7 +41,7 @@ "extglob": "^1.1.0", "fragment-cache": "^0.2.1", "kind-of": "^3.1.0", - "nanomatch": "^1.0.1", + "nanomatch": "^1.0.2", "object.pick": "^1.2.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", @@ -56,7 +56,7 @@ "gulp": "^3.9.1", "gulp-format-md": "^0.1.11", "gulp-istanbul": "^1.1.1", - "gulp-mocha": "^4.1.0", + "gulp-mocha": "^3.0.0", "gulp-unused": "^0.2.1", "is-object": "^1.0.1", "is-primitive": "^2.0.0", @@ -65,7 +65,7 @@ "mocha": "^3.2.0", "multimatch": "^2.1.0", "repeat-string": "^1.6.1", - "write": "^0.3.2", + "write": "^0.3.3", "yargs-parser": "^5.0.0" }, "keywords": [ @@ -98,6 +98,11 @@ "wildcard" ], "lintDeps": { + "dependencies": { + "lock": { + "snapdragon": "^0.8.1" + } + }, "devDependencies": { "files": [ "test/{reference,support}/*.js" From c0f4b6ff08a84c154500decc9c0b5d4764d543f0 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 3 Apr 2017 17:59:13 -0400 Subject: [PATCH 51/68] don't remove duplicate slashes --- index.js | 54 ++++++++++++++++++++++-------------------------- lib/compilers.js | 2 +- lib/utils.js | 2 ++ 3 files changed, 28 insertions(+), 30 deletions(-) diff --git a/index.js b/index.js index f5892944..b91fcef2 100644 --- a/index.js +++ b/index.js @@ -115,10 +115,10 @@ micromatch.match = function(list, pattern, options) { while (++idx < len) { var origPath = list[idx]; - var unixPath = unixify(origPath); - if (origPath === pattern || unixPath === pattern || isMatch(unixPath)) { - matches.push(utils.value(origPath, unixPath, options)); + if (origPath === pattern || isMatch(origPath)) { + var unixPath = unixify(origPath); + matches.push(utils.value(origPath, unixPath, options, pattern)); } } @@ -168,14 +168,11 @@ micromatch.isMatch = function(str, pattern, options) { throw new TypeError('expected a string: "' + util.inspect(str) + '"'); } - if (pattern === str) { + var equals = utils.equalsPattern(options); + if (equals(str)) { return true; } - if (utils.isSimpleChar(pattern) || utils.isSlash(pattern)) { - return str === pattern; - } - var isMatch = memoize('isMatch', pattern, options, micromatch.matcher); return isMatch(str); }; @@ -203,18 +200,10 @@ micromatch.not = function(list, patterns, options) { delete opts.ignore; list = utils.arrayify(list); - var unixify = utils.unixify(opts); - var res = []; - - for (var i = 0; i < list.length; i++) { - var origPath = list[i]; - var unixPath = unixify(origPath); - res.push(utils.value(origPath, unixPath, opts)); - } - var matches = utils.diff(res, micromatch(res, patterns, opts)); + var matches = utils.diff(list, micromatch(list, patterns, opts)); if (ignore) { - matches = utils.diff(matches, micromatch(res, ignore)); + matches = utils.diff(matches, micromatch(list, ignore)); } return opts.nodupes !== false ? utils.unique(matches) : matches; @@ -240,7 +229,6 @@ micromatch.not = function(list, patterns, options) { */ micromatch.any = function(list, patterns, options) { - var unixify = utils.unixify(options); var isMatch = memoize('any', patterns, options, micromatch.matcher); list = utils.arrayify(list); @@ -250,9 +238,8 @@ micromatch.any = function(list, patterns, options) { while (++idx < len) { var ele = list[idx]; if (ele === './' || ele === '') continue; - var unix = unixify(ele); - if (isMatch(unix)) { + if (isMatch(ele)) { if (options && options.ignore && micromatch.not(ele, options.ignored)) { continue; } @@ -283,19 +270,25 @@ micromatch.any = function(list, patterns, options) { */ micromatch.contains = function(str, patterns, options) { - if (patterns === str) { - return true; - } + if (typeof patterns === 'string') { + if (patterns === '') { + return false; + } - if (utils.isSimpleChar(patterns)) { - return str === patterns; + var equals = utils.equalsPattern(patterns, options); + if (equals(str)) { + return true; + } + var contains = utils.containsPattern(patterns, options); + if (contains(str)) { + return true; + } } var opts = extend({}, options); opts.strictClose = false; opts.strictOpen = false; opts.contains = true; - return micromatch(str, patterns, opts).length > 0; }; @@ -393,10 +386,13 @@ micromatch.matcher = function matcher(pattern, options) { function test(regex) { var unixify = utils.unixify(options); + var equals = utils.equalsPattern(options); return function(str) { - var ele = unixify(str); - if (str === pattern || ele === pattern || regex.test(ele)) { + if (equals(str)) { + return true; + } + if (regex.test(unixify(str))) { return true; } return false; diff --git a/lib/compilers.js b/lib/compilers.js index e345e4a1..ed532ca0 100644 --- a/lib/compilers.js +++ b/lib/compilers.js @@ -25,7 +25,7 @@ module.exports = function(snapdragon) { // register extglob compilers snapdragon.use(extglob.compilers); snapdragon.use(function() { - this.options.star = this.options.star || function() { + this.options.star = this.options.star || function(/*node*/) { return '[^/]*?'; }; }); diff --git a/lib/utils.js b/lib/utils.js index 19060c63..1b588c91 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -288,6 +288,8 @@ utils.equalsPattern = function(pattern, options) { utils.containsPattern = function(pattern, options) { var unixify = utils.unixify(options); + options = options || {}; + return function(filepath) { var contains = utils._contains(filepath, unixify(filepath), pattern); if (contains === true || options.nocase !== true) { From c60c3788e96c1fa754d9b80b5432c7f4f9fa8d39 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 3 Apr 2017 17:59:23 -0400 Subject: [PATCH 52/68] update bash tests --- test/bash.js | 98 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/test/bash.js b/test/bash.js index 05081854..0304c24f 100644 --- a/test/bash.js +++ b/test/bash.js @@ -2,6 +2,7 @@ require('mocha'); var assert = require('assert'); +var isWindows = require('is-windows'); var mm = require('./support/match'); /** @@ -33,34 +34,65 @@ describe('bash options and features:', function() { }); it('should use quoted characters as literals:', function() { - mm(fixtures, '\\*', {nonull: true}, ['*', '\\*']); - mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*']); - mm(fixtures, '\\*', {nonull: true, unescape: true, unixify: false}, ['*', '\\*']); + if (isWindows()) { + mm(fixtures, '\\*', {nonull: true}, ['*', '/*']); + mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*']); + mm(fixtures, '\\*', {nonull: true, unescape: true, unixify: false}, ['*', '/*']); - mm(fixtures, '\\^', {nonull: true}, ['\\^']); - mm(fixtures, '\\^', []); + mm(fixtures, '\\^', {nonull: true}, ['/^']); + mm(fixtures, '\\^', []); - mm(fixtures, 'a\\*', {nonull: true}, ['a\\*']); - mm(fixtures, 'a\\*', ['a*'], {nonull: true, unescape: true}); - mm(fixtures, 'a\\*', []); + mm(fixtures, 'a\\*', {nonull: true}, ['a/*']); + mm(fixtures, 'a\\*', ['a*'], {nonull: true, unescape: true}); + mm(fixtures, 'a\\*', []); - mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['a\\*', '*', '\\*']); - mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*']); - mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true, unixify: false}, ['a*', '*', '\\*']); - mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*']); - mm(fixtures, ['a\\*', '\\*'], {unescape: true, unixify: false}, ['*', '\\*']); - mm(fixtures, ['a\\*', '\\*'], ['*', '\\*']); + mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['a/*', '*', '/*']); + mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*']); + mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true, unixify: false}, ['a*', '*', '/*']); + mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*']); + mm(fixtures, ['a\\*', '\\*'], {unescape: true, unixify: false}, ['*', '/*']); + mm(fixtures, ['a\\*', '\\*'], ['*', '/*']); - mm(fixtures, ['a\\*'], {nonull: true}, ['a\\*']); - mm(fixtures, ['a\\*'], []); + mm(fixtures, ['a\\*'], {nonull: true}, ['a/*']); + mm(fixtures, ['a\\*'], []); - mm(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a\\*', '*q*']); - mm(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); + mm(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a/*', '*q*']); + mm(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); - mm(fixtures, '"*"*', {nonull: true}, ['"*"*']); - mm(fixtures, '"*"*', []); + mm(fixtures, '"*"*', {nonull: true}, ['"*"*']); + mm(fixtures, '"*"*', []); - mm(fixtures, '\\**', ['*']); // `*` is in the fixtures array + mm(fixtures, '\\**', ['*']); // `*` is in the fixtures array + } else { + mm(fixtures, '\\*', {nonull: true}, ['*', '\\*']); + mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*']); + mm(fixtures, '\\*', {nonull: true, unescape: true, unixify: false}, ['*', '\\*']); + + mm(fixtures, '\\^', {nonull: true}, ['\\^']); + mm(fixtures, '\\^', []); + + mm(fixtures, 'a\\*', {nonull: true}, ['a\\*']); + mm(fixtures, 'a\\*', ['a*'], {nonull: true, unescape: true}); + mm(fixtures, 'a\\*', []); + + mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['a\\*', '*', '\\*']); + mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*']); + mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true, unixify: false}, ['a*', '*', '\\*']); + mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*']); + mm(fixtures, ['a\\*', '\\*'], {unescape: true, unixify: false}, ['*', '\\*']); + mm(fixtures, ['a\\*', '\\*'], ['*', '\\*']); + + mm(fixtures, ['a\\*'], {nonull: true}, ['a\\*']); + mm(fixtures, ['a\\*'], []); + + mm(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a\\*', '*q*']); + mm(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); + + mm(fixtures, '"*"*', {nonull: true}, ['"*"*']); + mm(fixtures, '"*"*', []); + + mm(fixtures, '\\**', ['*']); // `*` is in the fixtures array + } }); it('should work for escaped paths/dots:', function() { @@ -81,17 +113,26 @@ describe('bash options and features:', function() { mm(['a-b', 'aXb'], 'a[X-]b', ['a-b', 'aXb']); mm(f, '[a-y]*[^c]', ['*', 'a', 'b', 'd', 'abd', 'abe', 'baz', 'beware', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); mm(f, '[a-y]*[^c]', {bash: true}, ['abd', 'abe', 'baz', 'beware', 'bzz', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); - mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '\\*']); mm(['a*b/ooo'], 'a\\*b/*', ['a*b/ooo']); mm(['a*b/ooo'], 'a\\*?/*', ['a*b/ooo']); mm(f, 'a[b]c', ['abc']); mm(f, 'a["b"]c', ['abc']); - mm(f, 'a[\\\\b]c', ['abc']); - mm(f, 'a[\\b]c', []); + mm(f, 'a[\\\\b]c', ['abc']); //<= backslash and a "b" + mm(f, 'a[\\b]c', []); //<= word boundary in a character class mm(f, 'a[b-d]c', ['abc']); mm(f, 'a?c', ['abc']); mm(['a-b'], 'a[]-]b', ['a-b']); mm(['man/man1/bash.1'], '*/man*/bash.*', ['man/man1/bash.1']); + + if (isWindows()) { + // should not match backslashes on windows, since backslashes are path + // separators and negation character classes should not match path separators + // unless it's explicitly defined in the character class + mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*']); + mm(f, '[^\\\\a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '\\*']); + } else { + mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '\\*']); + } }); it('should support basic wildmatch (brackets) features', function() { @@ -125,8 +166,13 @@ describe('bash options and features:', function() { it('should match escaped characters', function() { assert(!mm.isMatch('', '\\')); assert(!mm.isMatch('XXX/\\', '[A-Z]+/\\')); - assert(mm.isMatch('\\', '\\')); - assert(mm.isMatch('XXX/\\', '[A-Z]+/\\\\')); + if (isWindows()) { + assert(!mm.isMatch('\\', '\\')); + assert(!mm.isMatch('XXX/\\', '[A-Z]+/\\\\')); + } else { + assert(mm.isMatch('\\', '\\')); + assert(mm.isMatch('XXX/\\', '[A-Z]+/\\\\')); + } assert(mm.isMatch('[ab]', '\\[ab]')); assert(mm.isMatch('[ab]', '[\\[:]ab]')); }); From 4e28b50dc8c9fcf2d98ddde3fb49b55ee16e6065 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 3 Apr 2017 18:10:57 -0400 Subject: [PATCH 53/68] fix windows tests --- test/bash.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/test/bash.js b/test/bash.js index 0304c24f..3a77cc78 100644 --- a/test/bash.js +++ b/test/bash.js @@ -36,8 +36,7 @@ describe('bash options and features:', function() { it('should use quoted characters as literals:', function() { if (isWindows()) { mm(fixtures, '\\*', {nonull: true}, ['*', '/*']); - mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*']); - mm(fixtures, '\\*', {nonull: true, unescape: true, unixify: false}, ['*', '/*']); + mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*', '/*']); mm(fixtures, '\\^', {nonull: true}, ['/^']); mm(fixtures, '\\^', []); @@ -47,10 +46,8 @@ describe('bash options and features:', function() { mm(fixtures, 'a\\*', []); mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['a/*', '*', '/*']); - mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*']); - mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true, unixify: false}, ['a*', '*', '/*']); - mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*']); - mm(fixtures, ['a\\*', '\\*'], {unescape: true, unixify: false}, ['*', '/*']); + mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*', '/*']); + mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*', '/*']); mm(fixtures, ['a\\*', '\\*'], ['*', '/*']); mm(fixtures, ['a\\*'], {nonull: true}, ['a/*']); @@ -129,7 +126,6 @@ describe('bash options and features:', function() { // separators and negation character classes should not match path separators // unless it's explicitly defined in the character class mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*']); - mm(f, '[^\\\\a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '\\*']); } else { mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '\\*']); } @@ -166,11 +162,10 @@ describe('bash options and features:', function() { it('should match escaped characters', function() { assert(!mm.isMatch('', '\\')); assert(!mm.isMatch('XXX/\\', '[A-Z]+/\\')); + assert(mm.isMatch('\\', '\\')); if (isWindows()) { - assert(!mm.isMatch('\\', '\\')); assert(!mm.isMatch('XXX/\\', '[A-Z]+/\\\\')); } else { - assert(mm.isMatch('\\', '\\')); assert(mm.isMatch('XXX/\\', '[A-Z]+/\\\\')); } assert(mm.isMatch('[ab]', '\\[ab]')); From ca984a8636fbf724697572baebf737b9e1bb5080 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 6 Apr 2017 19:46:25 -0400 Subject: [PATCH 54/68] windows paths --- index.js | 13 ++-- lib/utils.js | 57 +++++++++------- package.json | 72 ++++++++++----------- test/bash.js | 42 ++++++------ test/brackets.js | 6 +- test/extglobs.js | 3 +- test/fixtures/glob.txt | 4 +- test/fixtures/patterns.js | 8 +-- test/minimatch.js | 133 ++++++++++++++++++++++---------------- test/negation.js | 14 +++- test/regex-ranges.js | 7 +- test/special-chars.js | 36 +++++++++-- 12 files changed, 233 insertions(+), 162 deletions(-) diff --git a/index.js b/index.js index b91fcef2..c4f10121 100644 --- a/index.js +++ b/index.js @@ -15,9 +15,9 @@ var extend = require('extend-shallow'); var compilers = require('./lib/compilers'); var parsers = require('./lib/parsers'); +var cache = require('./lib/cache'); var utils = require('./lib/utils'); var MAX_LENGTH = 1024 * 64; -var cache = {}; /** * The main function takes a list of strings and one or more @@ -385,13 +385,14 @@ micromatch.matcher = function matcher(pattern, options) { } function test(regex) { - var unixify = utils.unixify(options); var equals = utils.equalsPattern(options); + var unixify = utils.unixify(options); return function(str) { if (equals(str)) { return true; } + if (regex.test(unixify(str))) { return true; } @@ -664,11 +665,13 @@ function memoize(type, pattern, options, fn) { return fn(pattern, options); } - if (cache.hasOwnProperty(key)) { - return cache[key]; + if (cache.has(type, key)) { + return cache.get(type, key); } - return (cache[key] = fn(pattern, options)); + var val = fn(pattern, options); + cache.set(type, key, val); + return val; } /** diff --git a/lib/utils.js b/lib/utils.js index 1b588c91..a10a6e08 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -2,7 +2,6 @@ var utils = module.exports; var path = require('path'); -var cache = {}; /** * Module dependencies @@ -16,6 +15,21 @@ utils.typeOf = require('kind-of'); utils.pick = require('object.pick'); utils.unique = require('array-unique'); +/** + * Returns true if the platform is windows, or `path.sep` is `\\`. + * This is defined as a function to allow `path.sep` to be set in unit tests, + * or by the user, if there is a reason to do so. + * @return {Boolean} + */ + +utils.isWindows = function() { + return path.sep === '\\' || process.platform === 'win32'; +}; + +/** + * Return the last element from an array + */ + utils.last = function(arr, n) { return arr[arr.length - (n || 1)]; }; @@ -142,7 +156,7 @@ utils.isObject = function(val) { */ utils.escapeRegex = function(str) { - return str.replace(/[-[\]{}()^$|\s*+?.\\\/]/g, '\\$&'); + return str.replace(/[-[\]{}()^$|*+?.\\\/\s]/g, '\\$&'); }; /** @@ -168,25 +182,25 @@ utils.hasSpecialChars = function(str) { }; /** - * Strip backslashes from a string. + * Normalize slashes in the given filepath. * - * @param {String} `str` + * @param {String} `filepath` * @return {String} */ -utils.unescape = function(str) { - return utils.toPosixPath(str.replace(/\\(\W)/g, '$1')); +utils.toPosixPath = function(str) { + return str.replace(/\\+/g, '/'); }; /** - * Normalize slashes in the given filepath. + * Strip backslashes before special characters in a string. * - * @param {String} `filepath` + * @param {String} `str` * @return {String} */ -utils.toPosixPath = function(str) { - return str.replace(/\\+/g, '/'); +utils.unescape = function(str) { + return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); }; /** @@ -196,7 +210,7 @@ utils.toPosixPath = function(str) { */ utils.stripDrive = function(fp) { - return path.sep === '\\' ? fp.replace(/^[a-z]:\/?/i, '/') : fp; + return utils.isWindows() ? fp.replace(/^[a-z]:[\\\/]+?/i, '/') : fp; }; /** @@ -206,7 +220,14 @@ utils.stripDrive = function(fp) { */ utils.stripPrefix = function(str) { - return str.replace(/^\.[\\\/]+/, ''); + if (str.charAt(0) !== '.') { + return str; + } + var ch = str.charAt(1); + if (ch === '\\' || ch === '/') { + return str.slice(2); + } + return str; }; /** @@ -335,17 +356,6 @@ utils.value = function(origPath, unixPath, options) { return origPath; }; -/** - * Returns true if the platform is windows, or `path.sep` is `\\`. - * This is defined as a function to allow `path.sep` to be set in unit tests, - * or by the user, if there is a reason to do so. - * @return {Boolean} - */ - -utils.isWindows = function() { - return path.sep === '\\' || process.platform === 'win32'; -}; - /** * Returns a function that normalizes slashes in a string to forward * slashes, strips `./` from beginning of paths, and optionally unescapes @@ -368,4 +378,3 @@ utils.unixify = function(options) { return filepath; }; }; - diff --git a/package.json b/package.json index 4ae33c37..a7be678f 100644 --- a/package.json +++ b/package.json @@ -32,42 +32,6 @@ "scripts": { "test": "mocha" }, - "dependencies": { - "arr-diff": "^3.0.0", - "array-unique": "^0.3.2", - "braces": "^2.0.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "extglob": "^1.1.0", - "fragment-cache": "^0.2.1", - "kind-of": "^3.1.0", - "nanomatch": "^1.0.2", - "object.pick": "^1.2.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "devDependencies": { - "ansi-cyan": "^0.1.1", - "bash-match": "^0.2.0", - "benchmarked": "^0.2.5", - "for-own": "^1.0.0", - "fs-exists-sync": "^0.1.0", - "gulp": "^3.9.1", - "gulp-format-md": "^0.1.11", - "gulp-istanbul": "^1.1.1", - "gulp-mocha": "^3.0.0", - "gulp-unused": "^0.2.1", - "is-object": "^1.0.1", - "is-primitive": "^2.0.0", - "is-windows": "^1.0.0", - "minimatch": "^3.0.3", - "mocha": "^3.2.0", - "multimatch": "^2.1.0", - "repeat-string": "^1.6.1", - "write": "^0.3.3", - "yargs-parser": "^5.0.0" - }, "keywords": [ "bash", "expand", @@ -142,5 +106,41 @@ "verb", "verb-generate-readme" ] + }, + "dependencies": { + "arr-diff": "^3.0.0", + "array-unique": "^0.3.2", + "braces": "^2.0.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "extglob": "^1.1.0", + "fragment-cache": "^0.2.1", + "kind-of": "^3.1.0", + "nanomatch": "^1.0.3", + "object.pick": "^1.2.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "devDependencies": { + "ansi-cyan": "^0.1.1", + "bash-match": "^0.2.0", + "benchmarked": "^0.2.5", + "for-own": "^1.0.0", + "fs-exists-sync": "^0.1.0", + "gulp": "^3.9.1", + "gulp-format-md": "^0.1.12", + "gulp-istanbul": "^1.1.1", + "gulp-mocha": "^3.0.0", + "gulp-unused": "^0.2.1", + "is-object": "^1.0.1", + "is-primitive": "^2.0.0", + "is-windows": "^1.0.0", + "minimatch": "^3.0.3", + "mocha": "^3.2.0", + "multimatch": "^2.1.0", + "repeat-string": "^1.6.1", + "write": "^0.3.3", + "yargs-parser": "^5.0.0" } } diff --git a/test/bash.js b/test/bash.js index 3a77cc78..fc47bb2c 100644 --- a/test/bash.js +++ b/test/bash.js @@ -11,7 +11,7 @@ var mm = require('./support/match'); */ // from the Bash 4.3 specification/unit tests -var fixtures = ['*', '\\*', 'a', 'abc', 'abd', 'abe', 'b', 'bb', 'bcd', 'bdir/', 'Beware', 'c', 'ca', 'cb', 'd', 'dd', 'de']; +var fixtures = ['*', '**', '\\*', 'a', 'a/*', 'abc', 'abd', 'abe', 'b', 'bb', 'bcd', 'bdir/', 'Beware', 'c', 'ca', 'cb', 'd', 'dd', 'de']; describe('bash options and features:', function() { describe('failglob:', function() { @@ -38,28 +38,23 @@ describe('bash options and features:', function() { mm(fixtures, '\\*', {nonull: true}, ['*', '/*']); mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*', '/*']); - mm(fixtures, '\\^', {nonull: true}, ['/^']); + mm(fixtures, '\\^', {nonull: true}, ['\\^']); mm(fixtures, '\\^', []); - mm(fixtures, 'a\\*', {nonull: true}, ['a/*']); + mm(fixtures, 'a\\*', {nonull: true}, ['a\\*']); mm(fixtures, 'a\\*', ['a*'], {nonull: true, unescape: true}); mm(fixtures, 'a\\*', []); - mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['a/*', '*', '/*']); + mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['*', '/*', 'a\\*']); mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*', '/*']); mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*', '/*']); mm(fixtures, ['a\\*', '\\*'], ['*', '/*']); - mm(fixtures, ['a\\*'], {nonull: true}, ['a/*']); + mm(fixtures, ['a\\*'], {nonull: true}, ['a\\*']); mm(fixtures, ['a\\*'], []); - mm(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a/*', '*q*']); + mm(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a\\*', '*q*']); mm(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); - - mm(fixtures, '"*"*', {nonull: true}, ['"*"*']); - mm(fixtures, '"*"*', []); - - mm(fixtures, '\\**', ['*']); // `*` is in the fixtures array } else { mm(fixtures, '\\*', {nonull: true}, ['*', '\\*']); mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*']); @@ -84,12 +79,17 @@ describe('bash options and features:', function() { mm(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a\\*', '*q*']); mm(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); + } + }); - mm(fixtures, '"*"*', {nonull: true}, ['"*"*']); - mm(fixtures, '"*"*', []); + it('should work for quoted characters', function() { + mm(fixtures, '"***"', []); + mm(fixtures, '"***"', {nonull: true}, ['"***"']); + mm(fixtures, '"*"*', ['*', '**']); + }); - mm(fixtures, '\\**', ['*']); // `*` is in the fixtures array - } + it('should work for escaped characters', function() { + mm(fixtures, '\\**', ['*', '**']); }); it('should work for escaped paths/dots:', function() { @@ -106,10 +106,10 @@ describe('bash options and features:', function() { it('should support character classes', function() { var f = fixtures.slice(); f.push('baz', 'bzz', 'BZZ', 'beware', 'BewAre'); + mm(f, 'a*[^c]', ['abd', 'abe']); mm(['a-b', 'aXb'], 'a[X-]b', ['a-b', 'aXb']); - mm(f, '[a-y]*[^c]', ['*', 'a', 'b', 'd', 'abd', 'abe', 'baz', 'beware', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); - mm(f, '[a-y]*[^c]', {bash: true}, ['abd', 'abe', 'baz', 'beware', 'bzz', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); + mm(f, '[a-y]*[^c]', ['abd', 'abe', 'baz', 'bzz', 'beware', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); mm(['a*b/ooo'], 'a\\*b/*', ['a*b/ooo']); mm(['a*b/ooo'], 'a\\*?/*', ['a*b/ooo']); mm(f, 'a[b]c', ['abc']); @@ -125,9 +125,13 @@ describe('bash options and features:', function() { // should not match backslashes on windows, since backslashes are path // separators and negation character classes should not match path separators // unless it's explicitly defined in the character class - mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*']); + mm(f, '[^a-c]*', ['d', 'dd', 'de', 'Beware', 'BewAre', 'BZZ', '*', '**']); + mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '**'], {bash: false}); + mm(f, '[^a-c]*', ['d', 'dd', 'de', '*', '**'], {nocase: true}); } else { - mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '\\*']); + mm(f, '[^a-c]*', ['d', 'dd', 'de', 'Beware', 'BewAre', 'BZZ', '*', '**', '\\*']); + mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '**', '\\*'], {bash: false}); + mm(f, '[^a-c]*', ['d', 'dd', 'de', '*', '**', '\\*'], {nocase: true}); } }); diff --git a/test/brackets.js b/test/brackets.js index c820e4d0..36b9fc21 100644 --- a/test/brackets.js +++ b/test/brackets.js @@ -22,7 +22,8 @@ describe('brackets', function() { assert.equal(create('[[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]'), '[a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9\\x21-\\x7Ea-z\\x20-\\x7E \\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~ \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]'); assert.equal(create('[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]'), '[^a-zA-Z0-9a-zA-Z \\t\\x00-\\x1F\\x7F0-9a-z \\t\\r\\n\\v\\fA-ZA-Fa-f0-9]'); assert.equal(create('[a-c[:digit:]x-z]'), '[a-c0-9x-z]'); - assert.equal(create('[_[:alpha:]][_[:alnum:]][_[:alnum:]]*'), '[_a-zA-Z][_a-zA-Z0-9][_a-zA-Z0-9]*?(\\/|$)', []); + assert.equal(create('[_[:alpha:]][_[:alnum:]][_[:alnum:]]*', {bash: false}), '[_a-zA-Z][_a-zA-Z0-9][_a-zA-Z0-9]*?(\\/|$)', []); + assert.equal(create('[_[:alpha:]][_[:alnum:]][_[:alnum:]]*'), '[_a-zA-Z][_a-zA-Z0-9][_a-zA-Z0-9][^/]*?(\\/|$)', []); }); }); @@ -91,7 +92,8 @@ describe('brackets', function() { it('should match alpha-numeric characters', function() { mm(['01234', '0123e456', '0123e45g78'], '[\\de]+', ['01234', '0123e456']); - mm(['01234', '0123e456', '0123e45g78'], '[\\de]*', ['01234', '0123e456']); + mm(['01234', '0123e456', '0123e45g78'], '[\\de]*', ['01234', '0123e456'], {bash: false}); + mm(['01234', '0123e456', '0123e45g78'], '[\\de]*', ['01234', '0123e456', '0123e45g78']); mm(['01234', '0123e456', '0123e45g78'], '[e\\d]+', ['01234', '0123e456']); }); diff --git a/test/extglobs.js b/test/extglobs.js index a3db74f6..55a74060 100644 --- a/test/extglobs.js +++ b/test/extglobs.js @@ -117,7 +117,8 @@ describe('extglobs', function() { mm(['abd', 'acd', 'ac', 'ab'], 'a!(@(b|B))', ['acd', 'abd', 'ac']); mm(['abd', 'acd'], 'a!(@(b|B))d', ['acd']); mm(['abd', 'acd'], 'a[b*(foo|bar)]d', ['abd']); - mm(['abcx', 'abcz', 'bbc', 'aaz', 'aaaz'], '[a*(]*z', ['aaz', 'aaaz']); + mm(['abcx', 'abcz', 'bbc', 'aaz', 'aaaz'], '[a*(]*z', ['aaz', 'aaaz'], {bash: false}); + mm(['abcx', 'abcz', 'bbc', 'aaz', 'aaaz'], '[a*(]*z', ['aaz', 'aaaz', 'abcz']); }); it('simple kleene star tests', function() { diff --git a/test/fixtures/glob.txt b/test/fixtures/glob.txt index e00a917a..60e76fb9 100644 --- a/test/fixtures/glob.txt +++ b/test/fixtures/glob.txt @@ -36,7 +36,7 @@ f abc ab?bc t a.a [a-d]*.[a-b] t a.b [a-d]*.[a-b] t c.a [a-d]*.[a-b] -f a.a.a [a-d]*.[a-b] +t a.a.a [a-d]*.[a-b] t a.a.a [a-d]*.[a-b]*.[a-b] t a.a *.[a-b] @@ -52,7 +52,7 @@ t a.a *.[a-b]* t a.b *.[a-b]* t a.a.a *.[a-b]* t c.a *.[a-b]* -f d.a.d *.[a-b]* +t d.a.d *.[a-b]* f d.a.d *.[a-b]*.[a-b]* t d.a.d *.[a-d]*.[a-d]* t a.bb *.[a-b]* diff --git a/test/fixtures/patterns.js b/test/fixtures/patterns.js index f49f89ed..c4f715d6 100644 --- a/test/fixtures/patterns.js +++ b/test/fixtures/patterns.js @@ -97,8 +97,6 @@ module.exports = [ ['a****c**?**??*****', ['abcdecdhjk'], null, ['abcdecdhjk']], ['[-abc]', ['-'], null, ['-']], ['[abc-]', ['-'], null, ['-']], - ['\\', ['\\'], null, ['\\']], - ['[\\\\]', ['\\'], null, ['\\']], ['[[]', ['['], null, ['[']], ['[', ['['], null, ['[']], ['[*', ['[abc'], null, ['[abc']], @@ -217,11 +215,11 @@ module.exports = [ // begin channelling Boole and deMorgan... 'negation tests', function() { - fixtures = ['d', 'e', '!ab', '!abc', 'a!b', '\\!a']; + fixtures = ['d', 'e', '!ab', '!abc', 'a!b']; }, // anything that is NOT a* matches. - ['!a*', ['\\!a', 'd', 'e', '!ab', '!abc']], + ['!a*', ['d', 'e', '!ab', '!abc']], // anything that IS !a* matches. ['!a*', ['!ab', '!abc'], {nonegate: true}], @@ -230,7 +228,7 @@ module.exports = [ ['a*', ['a!b']], // anything that is NOT !a* matches - ['!\\!a*', ['a!b', 'd', 'e', '\\!a']], + ['!\\!a*', ['a!b', 'd', 'e']], // negation nestled within a pattern function() { diff --git a/test/minimatch.js b/test/minimatch.js index ea5d0543..e96b72a7 100644 --- a/test/minimatch.js +++ b/test/minimatch.js @@ -2,10 +2,15 @@ var path = require('path'); var assert = require('assert'); +var isWindows = require('is-windows'); var extend = require('extend-shallow'); var patterns = require('./fixtures/patterns'); var mm = require('./support/match'); +/** + * Minimatch comparison tests + */ + describe('basic tests', function() { patterns.forEach(function(unit, i) { it(i + ': ' + unit[0], function() { @@ -17,7 +22,8 @@ describe('basic tests', function() { // update fixtures list if (typeof unit === 'function') { - return unit(); + unit(); + return; } var pattern = unit[0]; @@ -29,68 +35,85 @@ describe('basic tests', function() { }); }); -describe('minimatch issues (as of 12/7/2016)', function() { - it('https://github.com/isaacs/minimatch/issues/29', function() { - assert(mm.isMatch('foo/bar.txt', 'foo/**/*.txt')); - assert(mm.makeRe('foo/**/*.txt' ).test( 'foo/bar.txt')); - assert(!mm.isMatch('n/!(axios)/**', 'n/axios/a.js')); - assert(!mm.makeRe('n/!(axios)/**').test('n/axios/a.js')); +describe('minimatch parity:', function() { + describe('backslashes', function() { + it('should match literal backslashes', function() { + if (isWindows()) { + mm.match(['\\'], '\\', ['/']); + } else { + mm.match(['\\'], '\\', ['\\']); + } + }); }); - it('https://github.com/isaacs/minimatch/issues/30', function() { - assert(mm.isMatch('foo/bar.js', '**/foo/**')); - assert(mm.isMatch('./foo/bar.js', './**/foo/**')); - assert(mm.isMatch('./foo/bar.js', '**/foo/**')); - assert(mm.isMatch('./foo/bar.txt', 'foo/**/*.txt')); - assert(mm.makeRe('./foo/**/*.txt' ).test( 'foo/bar.txt')); - assert(!mm.isMatch('./foo/!(bar)/**', 'foo/bar/a.js')); - assert(!mm.makeRe('./foo/!(bar)/**').test('foo/bar/a.js')); - }); + /** + * Issues that minimatch fails on but micromatch passes + */ - it('https://github.com/isaacs/minimatch/issues/50', function() { - assert(mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[ABC\\].txt')); - assert(!mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[abc\\].txt')); - assert(mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[abc\\].txt', {nocase: true})); - }); + describe('minimatch issues (as of 12/7/2016)', function() { + it('https://github.com/isaacs/minimatch/issues/29', function() { + assert(mm.isMatch('foo/bar.txt', 'foo/**/*.txt')); + assert(mm.makeRe('foo/**/*.txt' ).test( 'foo/bar.txt')); + assert(!mm.isMatch('n/!(axios)/**', 'n/axios/a.js')); + assert(!mm.makeRe('n/!(axios)/**').test('n/axios/a.js')); + }); - it('https://github.com/isaacs/minimatch/issues/67 (should work consistently with `makeRe` and matcher functions)', function() { - var re = mm.makeRe('node_modules/foobar/**/*.bar'); - assert(re.test('node_modules/foobar/foo.bar')); - assert(mm.isMatch('node_modules/foobar/foo.bar', 'node_modules/foobar/**/*.bar')); - mm(['node_modules/foobar/foo.bar'], 'node_modules/foobar/**/*.bar', ['node_modules/foobar/foo.bar']); - }); + it('https://github.com/isaacs/minimatch/issues/30', function() { + assert(mm.isMatch('foo/bar.js', '**/foo/**')); + assert(mm.isMatch('./foo/bar.js', './**/foo/**')); + assert(mm.isMatch('./foo/bar.js', '**/foo/**')); + assert(mm.isMatch('./foo/bar.txt', 'foo/**/*.txt')); + assert(mm.makeRe('./foo/**/*.txt' ).test( 'foo/bar.txt')); + assert(!mm.isMatch('./foo/!(bar)/**', 'foo/bar/a.js')); + assert(!mm.makeRe('./foo/!(bar)/**').test('foo/bar/a.js')); + }); - it('https://github.com/isaacs/minimatch/issues/75', function() { - assert(mm.isMatch('foo/baz.qux.js', 'foo/@(baz.qux).js')); - assert(mm.isMatch('foo/baz.qux.js', 'foo/+(baz.qux).js')); - assert(mm.isMatch('foo/baz.qux.js', 'foo/*(baz.qux).js')); - assert(!mm.isMatch('foo/baz.qux.js', 'foo/!(baz.qux).js')); - assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/*/!(baz.qux).js')); - assert(!mm.isMatch('foo/bar/bazqux.js', '**/!(bazqux).js')); - assert(!mm.isMatch('foo/bar/bazqux.js', 'foo/**/!(bazqux).js')); - assert(!mm.isMatch('foo/bar/bazqux.js', 'foo/**/!(bazqux)*.js')); - assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/**/!(baz.qux)*.js')); - assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/**/!(baz.qux).js')); - assert(!mm.isMatch('foo.js', '!(foo)*.js')); - assert(!mm.isMatch('foo.js', '!(foo)*.js')); - assert(!mm.isMatch('foobar.js', '!(foo)*.js')); - }); + it('https://github.com/isaacs/minimatch/issues/50', function() { + assert(mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[ABC\\].txt')); + assert(!mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[abc\\].txt')); + assert(mm.isMatch('foo/bar-[ABC].txt', 'foo/**/*-\\[abc\\].txt', {nocase: true})); + }); - it('https://github.com/isaacs/minimatch/issues/78', function() { - var sep = path.sep; - path.sep = '\\'; - assert(mm.isMatch('a\\b\\c.txt', 'a/**/*.txt')); - path.sep = sep; - }); + it('https://github.com/isaacs/minimatch/issues/67 (should work consistently with `makeRe` and matcher functions)', function() { + var re = mm.makeRe('node_modules/foobar/**/*.bar'); + assert(re.test('node_modules/foobar/foo.bar')); + assert(mm.isMatch('node_modules/foobar/foo.bar', 'node_modules/foobar/**/*.bar')); + mm(['node_modules/foobar/foo.bar'], 'node_modules/foobar/**/*.bar', ['node_modules/foobar/foo.bar']); + }); - it('https://github.com/isaacs/minimatch/issues/82', function() { - assert(mm.isMatch('./src/test/a.js', '**/test/**')); - assert(mm.isMatch('src/test/a.js', '**/test/**')); - }); + it('https://github.com/isaacs/minimatch/issues/75', function() { + assert(mm.isMatch('foo/baz.qux.js', 'foo/@(baz.qux).js')); + assert(mm.isMatch('foo/baz.qux.js', 'foo/+(baz.qux).js')); + assert(mm.isMatch('foo/baz.qux.js', 'foo/*(baz.qux).js')); + assert(!mm.isMatch('foo/baz.qux.js', 'foo/!(baz.qux).js')); + assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/*/!(baz.qux).js')); + assert(!mm.isMatch('foo/bar/bazqux.js', '**/!(bazqux).js')); + assert(!mm.isMatch('foo/bar/bazqux.js', 'foo/**/!(bazqux).js')); + assert(!mm.isMatch('foo/bar/bazqux.js', 'foo/**/!(bazqux)*.js')); + assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/**/!(baz.qux)*.js')); + assert(!mm.isMatch('foo/bar/baz.qux.js', 'foo/**/!(baz.qux).js')); + assert(!mm.isMatch('foo.js', '!(foo)*.js')); + assert(!mm.isMatch('foo.js', '!(foo)*.js')); + assert(!mm.isMatch('foobar.js', '!(foo)*.js')); + }); - it('https://github.com/isaacs/minimatch/issues/83', function() { - assert(!mm.makeRe('foo/!(bar)/**').test('foo/bar/a.js')); - assert(!mm.isMatch('foo/!(bar)/**', 'foo/bar/a.js')); + it('https://github.com/isaacs/minimatch/issues/78', function() { + var sep = path.sep; + path.sep = '\\'; + assert(mm.isMatch('a\\b\\c.txt', 'a/**/*.txt')); + assert(mm.isMatch('a/b/c.txt', 'a/**/*.txt')); + path.sep = sep; + }); + + it('https://github.com/isaacs/minimatch/issues/82', function() { + assert(mm.isMatch('./src/test/a.js', '**/test/**')); + assert(mm.isMatch('src/test/a.js', '**/test/**')); + }); + + it('https://github.com/isaacs/minimatch/issues/83', function() { + assert(!mm.makeRe('foo/!(bar)/**').test('foo/bar/a.js')); + assert(!mm.isMatch('foo/!(bar)/**', 'foo/bar/a.js')); + }); }); }); diff --git a/test/negation.js b/test/negation.js index 68c7066f..162316b7 100644 --- a/test/negation.js +++ b/test/negation.js @@ -1,6 +1,7 @@ 'use strict'; var mi = require('minimatch'); +var isWindows = require('is-windows'); var mm = require('./support/match'); describe('negation', function() { @@ -56,6 +57,7 @@ describe('negation', function() { }); it('should negate dotfiles:', function() { + mm(['.dotfile.md'], '!*.md', {dot: true}, []); mm(['.dotfile.md'], '!*.md', ['.dotfile.md']); mm(['.dotfile.txt'], '!*.md', ['.dotfile.txt']); mm(['.dotfile.txt', 'a/b/.dotfile'], '!*.md', ['.dotfile.txt', 'a/b/.dotfile']); @@ -67,12 +69,18 @@ describe('negation', function() { }); it('should support any number of leading exclamations', function() { - mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!a*', ['d', 'e', '!ab', '!abc', '\\!a']); mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!a*', ['a!b']); - mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!a*', ['d', 'e', '!ab', '!abc', '\\!a']); mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!!a*', ['a!b']); - mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!!!a*', ['d', 'e', '!ab', '!abc', '\\!a']); mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!!!!a*', ['a!b']); + if (!isWindows()) { + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!!!a*', ['d', 'e', '!ab', '!abc', '\\!a']); + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!a*', ['d', 'e', '!ab', '!abc', '\\!a']); + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!a*', ['d', 'e', '!ab', '!abc', '\\!a']); + } else { + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!!!a*', ['d', 'e', '!ab', '!abc', '/!a']); + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!a*', ['d', 'e', '!ab', '!abc', '/!a']); + mm(['d', 'e', '!ab', '!abc', 'a!b', '\\!a'], '!!!a*', ['d', 'e', '!ab', '!abc', '/!a']); + } }); it('should not give special meaning to non-leading exclamations', function() { diff --git a/test/regex-ranges.js b/test/regex-ranges.js index 56b63cce..46feeae7 100644 --- a/test/regex-ranges.js +++ b/test/regex-ranges.js @@ -1,6 +1,5 @@ 'use strict'; -var mi = require('minimatch'); var mm = require('./support/match'); describe('ranges', function() { @@ -8,13 +7,15 @@ describe('ranges', function() { var fixtures = ['a.a', 'a.b', 'a.a.a', 'c.a', 'd.a.d', 'a.bb', 'a.ccc']; mm(fixtures, '[a-b].[a-b]', ['a.a', 'a.b']); mm(fixtures, '[a-d].[a-b]', ['a.a', 'a.b', 'c.a']); - mm(fixtures, '[a-d]*.[a-b]', ['a.a', 'a.b', 'c.a']); + mm(fixtures, '[a-d]*.[a-b]', ['a.a', 'a.b', 'a.a.a', 'c.a']); + mm(fixtures, '[a-d]*.[a-b]', ['a.a', 'a.b', 'c.a'], {bash: false}); }); it('should support valid regex ranges with glob negation patterns', function() { var fixtures = ['a.a', 'a.b', 'a.a.a', 'c.a', 'd.a.d', 'a.bb', 'a.ccc']; mm(fixtures, '!*.[a-b]', ['a.bb', 'a.ccc', 'd.a.d']); - mm(fixtures, '!*.[a-b]*', ['a.ccc', 'd.a.d']); + mm(fixtures, '!*.[a-b]*', ['a.ccc']); + mm(fixtures, '!*.[a-b]*', ['a.ccc', 'd.a.d'], {bash: false}); mm(fixtures, '![a-b].[a-b]', ['a.a.a', 'a.bb', 'a.ccc', 'c.a', 'd.a.d']); mm(fixtures, '![a-b]+.[a-b]+', ['a.a.a', 'a.ccc', 'c.a', 'd.a.d']); }); diff --git a/test/special-chars.js b/test/special-chars.js index 8eed06ad..57855f8a 100644 --- a/test/special-chars.js +++ b/test/special-chars.js @@ -1,6 +1,8 @@ 'use strict'; +var path = require('path'); var assert = require('assert'); +var isWindows = require('is-windows'); var mm = require('./support/match'); describe('special characters', function() { @@ -53,12 +55,28 @@ describe('special characters', function() { }); it('should match backslashes', function() { - assert(mm.isMatch('\\', '[\\\\]')); - assert(mm.isMatch('\\', '[\\\\]+')); - assert(mm.isMatch('\\\\', '[\\\\]+')); - assert(mm.isMatch('\\\\\\', '[\\\\]+')); - mm(['\\'], '[\\\\]', ['\\']); - mm(['\\', '\\\\', '\\\\\\'], '[\\\\]+', ['\\', '\\\\', '\\\\\\']); + assert(mm.isMatch('\\', '[\\\\/]')); + assert(mm.isMatch('\\', '[\\\\/]+')); + assert(mm.isMatch('\\\\', '[\\\\/]+')); + assert(mm.isMatch('\\\\\\', '[\\\\/]+')); + + if (isWindows()) { + mm(['\\'], '[\\\\/]', ['/']); + mm(['\\', '\\\\', '\\\\\\'], '[\\\\/]+', ['/']); + } else { + mm(['\\'], '[\\\\/]', ['\\']); + mm(['\\', '\\\\', '\\\\\\'], '[\\\\/]+', ['\\', '\\\\', '\\\\\\']); + } + + var sep = path.sep; + path.sep = '\\'; + assert(mm.isMatch('\\', '[\\\\/]')); + assert(mm.isMatch('\\', '[\\\\/]+')); + assert(mm.isMatch('\\\\', '[\\\\/]+')); + assert(mm.isMatch('\\\\\\', '[\\\\/]+')); + mm(['\\'], '[\\\\/]', ['/']); + mm(['\\', '\\\\', '\\\\\\'], '[\\\\/]+', ['/']); + path.sep = sep; }); }); @@ -68,7 +86,6 @@ describe('special characters', function() { assert(mm.isMatch(':/foo', ':/*')); assert(mm.isMatch('D://foo', 'D://*')); assert(mm.isMatch('D://foo', 'D:\\/\\/*')); - assert(mm.isMatch('D:\\/\\/foo', 'D:\\\\/\\\\/*')); }); }); @@ -80,6 +97,11 @@ describe('special characters', function() { mm(['a/b.md', 'b/b.md', 'c/b.md', 'b/c.md', 'a/d.md'], '[bc]/[bd].md', ['b/b.md', 'c/b.md']); }); + it('should handle brackets', function() { + mm(['ab', 'ac', 'ad', 'a*', '*'], '[a*]*', ['*', 'a*'], {bash: false}); + mm(['ab', 'ac', 'ad', 'a*', '*'], '[a*]*', ['*', 'a*', 'ab', 'ac', 'ad']); + }); + it('should handle unclosed brackets', function() { mm(['[!ab', '[ab'], '[!a*', ['[!ab']); }); From 226797c336dd64d839dd7f5e0043fbed5237dd2f Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Tue, 11 Apr 2017 15:33:26 -0400 Subject: [PATCH 55/68] add tests for matchBase closes https://github.com/jonschlinkert/micromatch/issues/83 --- test/issue-related.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/issue-related.js b/test/issue-related.js index a4aa08b0..77653717 100644 --- a/test/issue-related.js +++ b/test/issue-related.js @@ -1,6 +1,7 @@ 'use strict'; var assert = require('assert'); +var mini = require('minimatch'); var mm = require('./support/match'); describe('issue-related tests', function() { @@ -59,4 +60,10 @@ describe('issue-related tests', function() { assert(mm.isMatch('/aaa/bbb/.git', '/aaa/bbb/**', {dot: true})); assert(mm.isMatch('/aaa/bbb/ccc/.git', '/aaa/bbb/**', {dot: true})); }); + + // see https://github.com/jonschlinkert/micromatch/issues/83 + it('issue #83', function() { + assert(mini('Incl/qqq.log', '**/Incl/**', {matchBase: true})); + assert(mm.isMatch('Incl/qqq.log', '**/Incl/**', {matchBase: true})); + }); }); From e816e5986a2bd44238b2748c0c3441abfef616a7 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Tue, 11 Apr 2017 15:33:45 -0400 Subject: [PATCH 56/68] update sourcemap example --- examples/options.sourceMap.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/options.sourceMap.js b/examples/options.sourceMap.js index 845d61c3..479f4d49 100644 --- a/examples/options.sourceMap.js +++ b/examples/options.sourceMap.js @@ -3,9 +3,9 @@ var mm = require('..'); var pattern = '*(*(of*(a)x)z)'; -var ast = mm.parse(pattern, {sourcemap: true}); -var res = mm.compile(ast); -console.log(res); +var ast = mm.parse(pattern); +var res = mm.compile(ast, {sourcemap: true}); +console.log(res) // { map: // { version: 3, // sources: [ 'string' ], From 75c06289fd8781fff3e6fc95e649532ac4248d0a Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Tue, 11 Apr 2017 15:34:43 -0400 Subject: [PATCH 57/68] adds support for `options.noext` add tests, move some tests around --- lib/compilers.js | 31 ++++++++++++++++++++++++++++++- test/extglobs.js | 9 +-------- test/options.js | 40 ++++++++++++++++++++++++++++++++++------ test/qmarks.js | 7 +++++++ 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/lib/compilers.js b/lib/compilers.js index ed532ca0..2fef6f5f 100644 --- a/lib/compilers.js +++ b/lib/compilers.js @@ -23,7 +23,12 @@ module.exports = function(snapdragon) { var eos = compilers.eos; // register extglob compilers - snapdragon.use(extglob.compilers); + if (snapdragon.options.noext === true) { + snapdragon.compiler.use(escapeExtglobs); + } else { + snapdragon.use(extglob.compilers); + } + snapdragon.use(function() { this.options.star = this.options.star || function(/*node*/) { return '[^/]*?'; @@ -57,3 +62,27 @@ module.exports = function(snapdragon) { return this.emit(node.val, node); }); }; + +function escapeExtglobs(compiler) { + compiler.set('paren', function(node) { + var val = ''; + visit(node, function(tok) { + if (tok.val) val += '\\' + tok.val; + }); + return this.emit(val, node); + }); + + function visit(node, fn) { + if (node.nodes) { + mapVisit(node.nodes, fn); + } else { + fn(node); + } + } + + function mapVisit(nodes, fn) { + for (var i = 0; i < nodes.length; i++) { + visit(nodes[i], fn); + } + } +} diff --git a/test/extglobs.js b/test/extglobs.js index 55a74060..acc89d5a 100644 --- a/test/extglobs.js +++ b/test/extglobs.js @@ -25,7 +25,7 @@ describe('extglobs', function() { it('should match extended globs:', function() { mm(['a.js.js', 'a.md.js'], '*.*(js).js', ['a.js.js']); - mm(['a/z', 'a/b'], 'a/!(z)', ['a/b']); + mm(['a/z', 'a/b', 'a/!(z)'], 'a/!(z)', ['a/!(z)', 'a/b']); mm(['c/z/v'], 'c/z/v', ['c/z/v']); mm(['c/a/v'], 'c/!(z)/v', ['c/a/v']); mm(['c/z/v', 'c/a/v'], 'c/!(z)/v', ['c/a/v']); @@ -54,13 +54,6 @@ describe('extglobs', function() { mm(['foo.js'], '!(foo).js', []); }); - it('should support qmark matching', function() { - var arr = ['a', 'aa', 'ab', 'aaa', 'abcdefg']; - mm(arr, '?', ['a']); - mm(arr, '??', ['aa', 'ab']); - mm(arr, '???', ['aaa']); - }); - it('should match exactly one of the given pattern:', function() { var arr = ['aa.aa', 'a.bb', 'a.aa.a', 'cc.a', 'a.a', 'c.a', 'dd.aa.d', 'b.a']; mm(arr, '(b|a).(a)', ['a.a', 'b.a']); diff --git a/test/options.js b/test/options.js index cdea2a0d..61370091 100644 --- a/test/options.js +++ b/test/options.js @@ -59,12 +59,6 @@ describe('options', function() { }); }); - describe('options.nobrace', function() { - it('should not expand braces', function() { - mm(['1', '2', '3'], '{1..2}', {nobrace: true}, []); - }); - }); - describe('options.expand', function() { it('should expand braces to an array', function() { assert.deepEqual(mm.braces('{a,b}', {expand: true}), ['a', 'b']); @@ -106,6 +100,14 @@ describe('options', function() { }); }); + describe('options.nobrace', function() { + it('should not expand braces when disabled', function() { + mm(['a', 'b', 'c'], '{a,b,c,d}', ['a', 'b', 'c']); + mm(['a', 'b', 'c'], '{a,b,c,d}', [], {nobrace: true}); + mm(['1', '2', '3'], '{1..2}', [], {nobrace: true}); + }); + }); + describe('options.nocase', function() { it('should not be case-sensitive when `options.nocase` is true', function() { mm(['a/b/c/e.md'], 'A/b/*/E.md', ['a/b/c/e.md'], {nocase: true}); @@ -122,6 +124,32 @@ describe('options', function() { }); }); + describe('options.noext', function() { + it('should not match extglobs when noext is true', function() { + assert(!mm.isMatch('ax', '?(a*|b)', {noext: true})); + mm(['a.js.js', 'a.md.js'], '*.*(js).js', [], {noext: true}); + mm(['a/z', 'a/b', 'a/!(z)'], 'a/!(z)', ['a/!(z)'], {noext: true}); + mm(['a/z', 'a/b'], 'a/!(z)', [], {noext: true}); + mm(['c/a/v'], 'c/!(z)/v', [], {noext: true}); + mm(['c/z/v', 'c/a/v'], 'c/!(z)/v', [], {noext: true}); + mm(['c/z/v', 'c/a/v'], 'c/@(z)/v', [], {noext: true}); + mm(['c/z/v', 'c/a/v'], 'c/+(z)/v', [], {noext: true}); + mm(['c/z/v', 'c/a/v'], 'c/*(z)/v', [], {noext: true}); + mm(['c/z/v', 'z', 'zf', 'fz'], '?(z)', [], {noext: true}); + mm(['c/z/v', 'z', 'zf', 'fz'], '+(z)', [], {noext: true}); + mm(['c/z/v', 'z', 'zf', 'fz'], '*(z)', [], {noext: true}); + mm(['cz', 'abz', 'az'], 'a@(z)', [], {noext: true}); + mm(['cz', 'abz', 'az'], 'a*@(z)', [], {noext: true}); + mm(['cz', 'abz', 'az'], 'a!(z)', [], {noext: true}); + mm(['cz', 'abz', 'az'], 'a?(z)', [], {noext: true}); + mm(['cz', 'abz', 'az'], 'a+(z)', [], {noext: true}); + mm(['az', 'bz', 'axz'], 'a+(z)', [], {noext: true}); + mm(['cz', 'abz', 'az'], 'a*(z)', [], {noext: true}); + mm(['cz', 'abz', 'az'], 'a**(z)', [], {noext: true}); + mm(['cz', 'abz', 'az'], 'a*!(z)', [], {noext: true}); + }); + }); + describe('options.nodupes', function() { beforeEach(function() { path.sep = '\\'; diff --git a/test/qmarks.js b/test/qmarks.js index 71af9b28..0d019aa1 100644 --- a/test/qmarks.js +++ b/test/qmarks.js @@ -4,6 +4,13 @@ var assert = require('assert'); var mm = require('./support/match'); describe('qmarks and stars', function() { + it('should support qmark matching', function() { + var arr = ['a', 'aa', 'ab', 'aaa', 'abcdefg']; + mm(arr, '?', ['a']); + mm(arr, '??', ['aa', 'ab']); + mm(arr, '???', ['aaa']); + }); + it('should correctly handle question marks in globs', function() { mm(['?', '??', '???'], '?', ['?']); mm(['?', '??', '???'], '??', ['??']); From e894de182b81d2a2236b4316090edef26ddd7c70 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 20 Apr 2017 20:41:01 -0400 Subject: [PATCH 58/68] remove dead code, minor re-org --- lib/compilers.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/compilers.js b/lib/compilers.js index 2fef6f5f..016a330e 100644 --- a/lib/compilers.js +++ b/lib/compilers.js @@ -5,6 +5,7 @@ var extglob = require('extglob'); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; + var opts = snapdragon.options; snapdragon.state = snapdragon.state || {}; @@ -22,8 +23,8 @@ module.exports = function(snapdragon) { var dot = compilers.dot; var eos = compilers.eos; - // register extglob compilers - if (snapdragon.options.noext === true) { + // register extglob compilers or escape exglobs if disabled + if (opts.extglob === false || opts.noext === true) { snapdragon.compiler.use(escapeExtglobs); } else { snapdragon.use(extglob.compilers); @@ -49,13 +50,6 @@ module.exports = function(snapdragon) { // customize end-of-string compiler .set('eos', function(node) { - if (this.ast.input.slice(-1) !== '/' && this.output.slice(-1) !== '/') { - var suffix = /(\w|\/\])$/.test(this.output) ? '\\/?' : '(\\/|$)'; - var len = suffix.length; - if (snapdragon.state.metachar && this.output.slice(-len) !== suffix) { - this.output += suffix; - } - } if (typeof eos === 'function') { return eos.apply(this, arguments); } @@ -72,17 +66,23 @@ function escapeExtglobs(compiler) { return this.emit(val, node); }); + /** + * Visit `node` with the given `fn` + */ + function visit(node, fn) { - if (node.nodes) { - mapVisit(node.nodes, fn); - } else { - fn(node); - } + return node.nodes ? mapVisit(node.nodes, fn) : fn(node); } + /** + * Map visit over array of `nodes`. + */ + function mapVisit(nodes, fn) { - for (var i = 0; i < nodes.length; i++) { - visit(nodes[i], fn); + var len = nodes.length; + var idx = -1; + while (++idx < len) { + visit(nodes[idx], fn); } } } From f2503bb35c0a1c9df4a132fe7e1347d204821e20 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Thu, 20 Apr 2017 20:41:12 -0400 Subject: [PATCH 59/68] move `compose` to main file --- lib/utils.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index a10a6e08..c1f2c1cb 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -34,22 +34,6 @@ utils.last = function(arr, n) { return arr[arr.length - (n || 1)]; }; -/** - * Compose a matcher function with the given patterns - */ - -utils.compose = function(patterns, options, matcher) { - var fns = patterns.map(function(pattern) { - return matcher(pattern, options); - }); - - return function(file) { - var len = fns.length; - while (len--) if (fns[len](file)) return true; - return false; - }; -}; - /** * Get the `Snapdragon` instance to use */ @@ -220,6 +204,7 @@ utils.stripDrive = function(fp) { */ utils.stripPrefix = function(str) { + if (!str || typeof str !== 'string') return str; if (str.charAt(0) !== '.') { return str; } From c2e1e0ba04c97bc115948221de7d23c9718ee729 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Wed, 26 Apr 2017 15:38:59 -0400 Subject: [PATCH 60/68] minor edits --- .github/contributing.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/contributing.md b/.github/contributing.md index 0bc32a89..3791537b 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -29,7 +29,7 @@ Please try to determine if the issue is caused by an underlying library, and if Try to follow these guidelines -- **Investigate the issue**: There might be an existing issue that covers the bug you experienced. If so, please do not create a new issue, feel free to add comments to the issue that best describes what you're experiencing. +- **Investigate the issue**: There might be an existing issue (open or closed) that covers the bug you experienced. If so, please do not create a new issue. If necessary you may add comments to the existing issue if you can shed additional light on the problem, or you'd like to help with debugging. - **Check the readme** - oftentimes you will find notes about creating issues, and where to go depending on the type of issue. - Create the issue in the appropriate repository: try to find out if the bug you're experiencing is in micromatch or one of its dependencies @@ -52,6 +52,4 @@ Here are some tips for creating idiomatic issues. Taking just a little bit extra - use syntax highlighting by adding the correct language name after the first "code fence" -[node-glob]: https://github.com/isaacs/node-glob [micromatch]: https://github.com/jonschlinkert/micromatch -[so]: http://stackoverflow.com/questions/tagged/micromatch From d44afb5959ee6a29ec6b36c441a73a5b16917b05 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Wed, 26 Apr 2017 23:24:00 -0400 Subject: [PATCH 61/68] adds examples --- examples/all.js | 13 +++++++++++++ examples/any.js | 8 ++++++++ examples/every.js | 13 +++++++++++++ examples/not.js | 16 ++++++++++++++++ examples/some.js | 10 ++++++++++ examples/star.js | 10 ++++++++++ 6 files changed, 70 insertions(+) create mode 100644 examples/all.js create mode 100644 examples/any.js create mode 100644 examples/every.js create mode 100644 examples/not.js create mode 100644 examples/some.js create mode 100644 examples/star.js diff --git a/examples/all.js b/examples/all.js new file mode 100644 index 00000000..4059b917 --- /dev/null +++ b/examples/all.js @@ -0,0 +1,13 @@ +var mm = require('..'); + +console.log(mm.all('foo.js', ['foo.js'])); +// true + +console.log(mm.all('foo.js', ['*.js', '!foo.js'])); +// false + +console.log(mm.all('foo.js', ['*.js', 'foo.js'])); +// true + +console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); +// true diff --git a/examples/any.js b/examples/any.js new file mode 100644 index 00000000..b3fe45fe --- /dev/null +++ b/examples/any.js @@ -0,0 +1,8 @@ +var mm = require('..'); + +console.log(mm.any('foo.js', ['foo.js'])); +// true + +// the following is correct, because one of the patterns matches +console.log(mm.any('foo.js', ['*.js', '!foo.js'])); +// true diff --git a/examples/every.js b/examples/every.js new file mode 100644 index 00000000..ade309c4 --- /dev/null +++ b/examples/every.js @@ -0,0 +1,13 @@ +var mm = require('..'); + +console.log(mm.every('foo.js', ['foo.js'])); +// true + +console.log(mm.every(['foo.js', 'bar.js'], ['*.js'])); +// true + +console.log(mm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); +// false + +console.log(mm.every(['foo.js'], ['*.js', '!foo.js'])); +// false diff --git a/examples/not.js b/examples/not.js new file mode 100644 index 00000000..654b8063 --- /dev/null +++ b/examples/not.js @@ -0,0 +1,16 @@ +var mm = require('..'); + +console.log(mm.not('foo.js', ['foo.js'])); +// [] + +console.log(mm.not(['foo.js', 'bar.js'], ['*.js'])); +// [] + +console.log(mm.not(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); +// ['foo.js'] + +console.log(mm.not(['foo.js', 'bar.js', 'baz.js', 'foo.md'], ['!*.js'], {ignore: 'baz.js'})); +// ['foo.js', 'bar.js'] + +console.log(mm.not(['foo.js'], ['*.js', '!foo.js'])); +// ['foo.js'] diff --git a/examples/some.js b/examples/some.js new file mode 100644 index 00000000..92c4fd66 --- /dev/null +++ b/examples/some.js @@ -0,0 +1,10 @@ +var mm = require('..'); + +console.log(mm.some('foo.js', ['foo.js'])); +// true + +console.log(mm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); +// true + +console.log(mm.some(['foo.js'], ['*.js', '!foo.js'])); +// false diff --git a/examples/star.js b/examples/star.js new file mode 100644 index 00000000..aed7531d --- /dev/null +++ b/examples/star.js @@ -0,0 +1,10 @@ +'use strict'; + +var parsers = require('../lib/parsers'); +var Extglob = require('../lib/extglob'); +var extglob = new Extglob(); +extglob.use(parsers); + +var pattern = '*(*(of*(a)x)z)'; +var res = extglob.parse(pattern); +console.log(res); From bf2cc5af8f9f878112cf7b6587c10698d99741c6 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Sun, 28 May 2017 20:00:31 -0400 Subject: [PATCH 62/68] fix url --- benchmark/fixtures/isMatch/star.js | 1 + benchmark/index.js | 7 +- benchmark/package.json | 25 +- examples/braces.js | 19 +- gulpfile.js | 2 +- index.js | 358 +++++++++++++++++++++-------- lib/parsers.js | 1 - lib/utils.js | 22 +- package.json | 98 ++++---- test/api.isMatch.js | 20 +- test/bash.js | 339 ++++++++++++++------------- test/extglobs.js | 5 +- test/support/matcher.js | 2 +- test/support/utils.js | 6 +- 14 files changed, 556 insertions(+), 349 deletions(-) create mode 100644 benchmark/fixtures/isMatch/star.js diff --git a/benchmark/fixtures/isMatch/star.js b/benchmark/fixtures/isMatch/star.js new file mode 100644 index 00000000..a4a46bee --- /dev/null +++ b/benchmark/fixtures/isMatch/star.js @@ -0,0 +1 @@ +module.exports = ["abc.txt", "*"]; \ No newline at end of file diff --git a/benchmark/index.js b/benchmark/index.js index 39e8d166..a4dcb85e 100755 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -3,7 +3,8 @@ var path = require('path'); var util = require('util'); var cyan = require('ansi-cyan'); -var argv = require('yargs-parser')(process.argv.slice(2)); +var opts = { alias: {pattern: 'p' }}; +var argv = require('minimist')(process.argv.slice(2), opts); var isPrimitive = require('is-primitive'); var isObject = require('is-object'); var Suite = require('benchmarked'); @@ -11,7 +12,7 @@ var Suite = require('benchmarked'); function run(type, pattern) { var suite = new Suite({ cwd: __dirname, - fixtures: path.join('fixtures', type, '*.js'), + fixtures: path.join('fixtures', type, pattern || '*.js'), code: path.join('code', type, '*.js') }); @@ -39,4 +40,4 @@ function run(type, pattern) { } } -run(argv._[0] || 'match', argv._[1] || 'large*'); +run(argv._[0] || 'match', argv._[1] || argv.pattern); diff --git a/benchmark/package.json b/benchmark/package.json index e8f1cb80..6af446ee 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -6,16 +6,31 @@ "scripts": { "test": "mocha" }, + "lintDeps": { + "dependencies": { + "options": { + "ignore": [ + "index.js" + ] + } + }, + "devDependencies": { + "files": [ + "code/**/*.js", + "*.js" + ] + } + }, "devDependencies": { "ansi-cyan": "^0.1.1", - "benchmarked": "^0.2.5", - "braces": "^2.0.2", + "benchmarked": "^1.1.1", + "braces": "^2.2.0", "is-object": "^1.0.1", "is-primitive": "^2.0.0", - "minimatch": "^3.0.3", + "minimatch": "^3.0.4", + "minimist": "^1.2.0", "multimatch": "^2.1.0", "repeat-string": "^1.6.1", - "write": "^0.3.2", - "yargs-parser": "^4.0.2" + "write": "^0.3.3" } } diff --git a/examples/braces.js b/examples/braces.js index 2cc97df3..6f7b5e98 100644 --- a/examples/braces.js +++ b/examples/braces.js @@ -1,13 +1,18 @@ var mm = require('../'); -console.log(mm.braces('{a,b}')); -//=> [ '(a|b)' ] +/** + * Brace optimization + */ -console.log(mm.braces('{a,b}', {expand: true})); -//=> [ 'a', 'b' ] +console.log(mm.braces('{a,b,c}/{001..100}')); +//=> [ '{a,b,c}/{1..100}' ] -console.log(mm.braces('foo/{a,b}/bar')); -//=> [ 'foo/(a|b)/bar' ] +/** + * Brace expansion + */ -console.log(mm.braces('foo/{a,b}/bar', {expand: true})); +console.log(mm.braceExpand('{a,b,c}/{001..100}')); +//=> ['a/a', 'a/b', 'a/c', 'a/d', 'a/e', 'b/a', 'b/b', 'b/c', 'b/d', 'b/e', 'c/a', 'c/b', 'c/c', 'c/d', 'c/e'] + +console.log(mm.braces('{a,b,c}/{001..100}', {expand: true})); //=> [ 'foo/a/bar', 'foo/b/bar' ] diff --git a/gulpfile.js b/gulpfile.js index 10488039..bb23e3d5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -22,4 +22,4 @@ gulp.task('unused', function() { .pipe(unused({keys: Object.keys(require('./lib/utils.js'))})); }); -gulp.task('default', ['test', 'lint']); +gulp.task('default', ['test']); diff --git a/index.js b/index.js index c4f10121..6c9d8a89 100644 --- a/index.js +++ b/index.js @@ -32,16 +32,17 @@ var MAX_LENGTH = 1024 * 64; * ``` * @param {Array} `list` A list of strings to match * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` Any [options](#options) to change how matches are performed + * @param {Object} `options` See available [options](#options) for changing how matches are performed * @return {Array} Returns an array of matches + * @summary false * @api public */ function micromatch(list, patterns, options) { patterns = utils.arrayify(patterns); list = utils.arrayify(list); - var len = patterns.length; + var len = patterns.length; if (list.length === 0 || len === 0) { return []; } @@ -71,7 +72,10 @@ function micromatch(list, patterns, options) { if (options && options.unixify === false) { keep = list.slice(); } else { - keep = list.map(utils.unixify(options)); + var unixify = utils.unixify(options); + for (var i = 0; i < list.length; i++) { + keep.push(unixify(list[i])); + } } } @@ -95,7 +99,7 @@ function micromatch(list, patterns, options) { * ``` * @param {Array} `list` Array of strings to match * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` Any [options](#options) to change how matches are performed + * @param {Object} `options` See available [options](#options) for changing how matches are performed * @return {Array} Returns an array of matches * @api public */ @@ -107,18 +111,16 @@ micromatch.match = function(list, pattern, options) { var unixify = utils.unixify(options); var isMatch = memoize('match', pattern, options, micromatch.matcher); + var matches = []; list = utils.arrayify(list); var len = list.length; var idx = -1; - var matches = []; while (++idx < len) { - var origPath = list[idx]; - - if (origPath === pattern || isMatch(origPath)) { - var unixPath = unixify(origPath); - matches.push(utils.value(origPath, unixPath, options, pattern)); + var ele = list[idx]; + if (ele === pattern || isMatch(ele)) { + matches.push(utils.value(ele, unixify, options)); } } @@ -158,7 +160,7 @@ micromatch.match = function(list, pattern, options) { * ``` * @param {String} `string` String to match * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` Any [options](#options) to change how matches are performed + * @param {Object} `options` See available [options](#options) for changing how matches are performed * @return {Boolean} Returns true if the string matches the glob pattern. * @api public */ @@ -168,6 +170,10 @@ micromatch.isMatch = function(str, pattern, options) { throw new TypeError('expected a string: "' + util.inspect(str) + '"'); } + if (isEmptyString(str) || isEmptyString(pattern)) { + return false; + } + var equals = utils.equalsPattern(options); if (equals(str)) { return true; @@ -178,39 +184,80 @@ micromatch.isMatch = function(str, pattern, options) { }; /** - * Returns a list of strings that _DO NOT MATCH_ any of the given `patterns`. + * Returns true if some of the elements in the given `list` match any of the + * given glob `patterns`. * * ```js * var mm = require('micromatch'); - * mm.not(list, patterns[, options]); + * mm.some(list, patterns[, options]); * - * console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); - * //=> ['b.b', 'c.c'] + * console.log(mm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); + * // true + * console.log(mm.some(['foo.js'], ['*.js', '!foo.js'])); + * // false * ``` - * @param {Array} `list` Array of strings to match. - * @param {String|Array} `patterns` One or more glob pattern to use for matching. - * @param {Object} `options` Any [options](#options) to change how matches are performed - * @return {Array} Returns an array of strings that **do not match** the given patterns. + * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found. + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Boolean} Returns true if any patterns match `str` * @api public */ -micromatch.not = function(list, patterns, options) { - var opts = extend({}, options); - var ignore = opts.ignore; - delete opts.ignore; +micromatch.some = function(list, patterns, options) { + if (typeof list === 'string') { + list = [list]; + } - list = utils.arrayify(list); + for (var i = 0; i < list.length; i++) { + if (micromatch(list[i], patterns, options).length === 1) { + return true; + } + } - var matches = utils.diff(list, micromatch(list, patterns, opts)); - if (ignore) { - matches = utils.diff(matches, micromatch(list, ignore)); + return false; +}; + +/** + * Returns true if every element in the given `list` matches + * at least one of the given glob `patterns`. + * + * ```js + * var mm = require('micromatch'); + * mm.every(list, patterns[, options]); + * + * console.log(mm.every('foo.js', ['foo.js'])); + * // true + * console.log(mm.every(['foo.js', 'bar.js'], ['*.js'])); + * // true + * console.log(mm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); + * // false + * console.log(mm.every(['foo.js'], ['*.js', '!foo.js'])); + * // false + * ``` + * @param {String|Array} `list` The string or array of strings to test. + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Boolean} Returns true if any patterns match `str` + * @api public + */ + +micromatch.every = function(list, patterns, options) { + if (typeof list === 'string') { + list = [list]; } - return opts.nodupes !== false ? utils.unique(matches) : matches; + for (var i = 0; i < list.length; i++) { + if (micromatch(list[i], patterns, options).length !== 1) { + return false; + } + } + + return true; }; /** - * Returns true if the given `string` matches any of the given glob `patterns`. + * Returns true if **any** of the given glob `patterns` + * match the specified `string`. * * ```js * var mm = require('micromatch'); @@ -221,34 +268,110 @@ micromatch.not = function(list, patterns, options) { * console.log(mm.any('a.a', 'b.*')); * //=> false * ``` - * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found. + * @param {String|Array} `str` The string to test. * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` Any [options](#options) to change how matches are performed + * @param {Object} `options` See available [options](#options) for changing how matches are performed * @return {Boolean} Returns true if any patterns match `str` * @api public */ -micromatch.any = function(list, patterns, options) { - var isMatch = memoize('any', patterns, options, micromatch.matcher); +micromatch.any = function(str, patterns, options) { + if (typeof str !== 'string') { + throw new TypeError('expected a string: "' + util.inspect(str) + '"'); + } - list = utils.arrayify(list); - var len = list.length; - var idx = -1; + if (isEmptyString(str) || isEmptyString(patterns)) { + return false; + } - while (++idx < len) { - var ele = list[idx]; - if (ele === './' || ele === '') continue; + if (typeof patterns === 'string') { + patterns = [patterns]; + } - if (isMatch(ele)) { - if (options && options.ignore && micromatch.not(ele, options.ignored)) { - continue; - } + for (var i = 0; i < patterns.length; i++) { + if (micromatch.isMatch(str, patterns[i], options)) { return true; } } return false; }; +/** + * Returns true if **all** of the given `patterns` + * match the specified string. + * + * ```js + * var mm = require('micromatch'); + * mm.all(string, patterns[, options]); + * + * console.log(mm.all('foo.js', ['foo.js'])); + * // true + * + * console.log(mm.all('foo.js', ['*.js', '!foo.js'])); + * // false + * + * console.log(mm.all('foo.js', ['*.js', 'foo.js'])); + * // true + * + * console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); + * // true + * ``` + * @param {String|Array} `str` The string to test. + * @param {String|Array} `patterns` One or more glob patterns to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Boolean} Returns true if any patterns match `str` + * @api public + */ + +micromatch.all = function(str, patterns, options) { + if (typeof str !== 'string') { + throw new TypeError('expected a string: "' + util.inspect(str) + '"'); + } + + if (typeof patterns === 'string') { + patterns = [patterns]; + } + + for (var i = 0; i < patterns.length; i++) { + if (!micromatch.isMatch(str, patterns[i], options)) { + return false; + } + } + return true; +}; + +/** + * Returns a list of strings that _**do not match any**_ of the given `patterns`. + * + * ```js + * var mm = require('micromatch'); + * mm.not(list, patterns[, options]); + * + * console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); + * //=> ['b.b', 'c.c'] + * ``` + * @param {Array} `list` Array of strings to match. + * @param {String|Array} `patterns` One or more glob pattern to use for matching. + * @param {Object} `options` See available [options](#options) for changing how matches are performed + * @return {Array} Returns an array of strings that **do not match** the given patterns. + * @api public + */ + +micromatch.not = function(list, patterns, options) { + var opts = extend({}, options); + var ignore = opts.ignore; + delete opts.ignore; + + list = utils.arrayify(list); + + var matches = utils.diff(list, micromatch(list, patterns, opts)); + if (ignore) { + matches = utils.diff(matches, micromatch(list, ignore)); + } + + return opts.nodupes !== false ? utils.unique(matches) : matches; +}; + /** * Returns true if the given `string` contains the given pattern. Similar * to [.isMatch](#isMatch) but the pattern can match any part of the string. @@ -264,14 +387,18 @@ micromatch.any = function(list, patterns, options) { * ``` * @param {String} `str` The string to match. * @param {String|Array} `patterns` Glob pattern to use for matching. - * @param {Object} `options` Any [options](#options) to change how matches are performed + * @param {Object} `options` See available [options](#options) for changing how matches are performed * @return {Boolean} Returns true if the patter matches any part of `str`. * @api public */ micromatch.contains = function(str, patterns, options) { + if (typeof str !== 'string') { + throw new TypeError('expected a string: "' + util.inspect(str) + '"'); + } + if (typeof patterns === 'string') { - if (patterns === '') { + if (isEmptyString(str) || isEmptyString(patterns)) { return false; } @@ -285,11 +412,8 @@ micromatch.contains = function(str, patterns, options) { } } - var opts = extend({}, options); - opts.strictClose = false; - opts.strictOpen = false; - opts.contains = true; - return micromatch(str, patterns, opts).length > 0; + var opts = extend({}, options, {contains: true}); + return micromatch.any(str, patterns, opts); }; /** @@ -319,7 +443,7 @@ micromatch.matchBase = function(pattern, options) { * ``` * @param {Object} `object` The object with keys to filter. * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` Any [options](#options) to change how matches are performed + * @param {Object} `options` See available [options](#options) for changing how matches are performed * @return {Object} Returns an object with only keys that match the given patterns. * @api public */ @@ -348,14 +472,20 @@ micromatch.matchKeys = function(obj, patterns, options) { * //=> true * ``` * @param {String} `pattern` Glob pattern - * @param {Object} `options` Any [options](#options) to change how matches are performed. + * @param {Object} `options` See available [options](#options) for changing how matches are performed. * @return {Function} Returns a matcher function. * @api public */ micromatch.matcher = function matcher(pattern, options) { + if (isEmptyString(pattern)) { + return function() { + return false; + } + } + if (Array.isArray(pattern)) { - return utils.compose(pattern, options, matcher); + return compose(pattern, options, matcher); } // if pattern is a regex @@ -365,7 +495,7 @@ micromatch.matcher = function matcher(pattern, options) { // if pattern is invalid if (!utils.isString(pattern)) { - throw new TypeError('expected pattern to be a string or regex'); + throw new TypeError('expected pattern to be an array, string or regex'); } // if pattern is a non-glob string @@ -400,7 +530,9 @@ micromatch.matcher = function matcher(pattern, options) { }; } - return test(re); + var fn = test(re); + fn.result = re.result; + return fn; }; /** @@ -414,7 +546,7 @@ micromatch.matcher = function matcher(pattern, options) { * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ * ``` * @param {String} `pattern` A glob pattern to convert to regex. - * @param {Object} `options` Any [options](#options) to change how matches are performed. + * @param {Object} `options` See available [options](#options) for changing how matches are performed. * @return {RegExp} Returns a regex created from the given pattern. * @api public */ @@ -433,13 +565,17 @@ micromatch.makeRe = function(pattern, options) { } function makeRe() { - var patterns = micromatch - .create(pattern, options) - .map(function(obj) { - return obj.output; - }); + var result = micromatch.create(pattern, options); + var asts = []; + var output = result.map(function(obj) { + obj.ast.state = obj.state; + asts.push(obj.ast); + return obj.output; + }); - return toRegex(patterns.join('|'), options); + var regex = toRegex(output.join('|'), options); + regex.result = asts; + return regex; } return memoize('makeRe', pattern, options, makeRe); @@ -477,15 +613,26 @@ micromatch.braces = function(pattern, options) { }; /** - * Parses the given glob `pattern` and returns an object with the compiled `output` - * and optional source `map`. + * Proxy to the [micromatch.braces](#method), for parity with + * minimatch. + */ + +micromatch.braceExpand = function(pattern, options) { + var opts = extend({}, options, {expand: true}); + return micromatch.braces(pattern, opts); +}; + +/** + * Parses the given glob `pattern` and returns an array of abstract syntax + * trees (ASTs), with the compiled `output` and optional source `map` on + * each AST. * * ```js * var mm = require('micromatch'); * mm.create(pattern[, options]); * * console.log(mm.create('abc/*.js')); - * // { options: { source: 'string', sourcemap: true }, + * // [{ options: { source: 'string', sourcemap: true }, * // state: {}, * // compilers: * // { ... }, @@ -507,7 +654,7 @@ micromatch.braces = function(pattern, options) { * // position: { line: 1, column: 28 }, * // content: {}, * // files: {}, - * // idx: 6 } + * // idx: 6 }] * ``` * @param {String} `pattern` Glob pattern to parse and compile. * @param {Object} `options` Any [options](#options) to change how parsing and compiling is performed. @@ -521,25 +668,15 @@ micromatch.create = function(pattern, options) { return micromatch.compile(micromatch.parse(str, opts), opts); } - if (pattern.slice(0, 2) === './') { - pattern = pattern.slice(2); - } - - pattern = utils.combineDuplicates(pattern, '\\*\\*\\/|\\/\\*\\*'); pattern = micromatch.braces(pattern, options); + var len = pattern.length; + var idx = -1; + var res = []; - if (Array.isArray(pattern)) { - var len = pattern.length; - var idx = -1; - var res = []; - - while (++idx < len) { - res.push(create(pattern[idx], options)); - } - return res; + while (++idx < len) { + res.push(create(pattern[idx], options)); } - - return create(pattern, options); + return res; }); }; @@ -626,17 +763,15 @@ micromatch.parse = function(pattern, options) { */ micromatch.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = micromatch.parse(ast, options); - } + return memoize('compile', ast.input, options, function() { + if (typeof ast === 'string') { + ast = micromatch.parse(ast, options); + } - function compile() { var snapdragon = utils.instantiate(ast, options); compilers(snapdragon, options); return snapdragon.compile(ast, options); - } - - return memoize('compile', ast.input, options, compile); + }); }; /** @@ -649,9 +784,48 @@ micromatch.compile = function(ast, options) { */ micromatch.clearCache = function() { - micromatch.cache.__data__ = {}; + micromatch.cache.caches = {}; }; +/** + * Returns true if the given value is effectively an empty string + */ + +function isEmptyString(val) { + return String(val) === '' || String(val) === './'; +} + +/** + * Compose a matcher function with the given patterns. + * This allows matcher functions to be compiled once and + * called multiple times. + */ + +function compose(patterns, options, matcher) { + var matchers; + + return memoize('compose', String(patterns), options, function() { + return function(file) { + // delay composition until it's invoked the first time, + // after that it won't be called again + if (!matchers) { + matchers = []; + for (var i = 0; i < patterns.length; i++) { + matchers.push(matcher(patterns[i], options)); + } + } + + var len = matchers.length; + while (len--) { + if (matchers[len](file) === true) { + return true; + } + } + return false; + }; + }); +} + /** * Memoize a generated regex or function. A unique key is generated * from the `type` (usually method name), the `pattern`, and @@ -675,12 +849,12 @@ function memoize(type, pattern, options, fn) { } /** - * Expose parser, compiler and constructor on `micromatch` + * Expose compiler, parser and cache on `micromatch` */ micromatch.compilers = compilers; micromatch.parsers = parsers; -micromatch.cache = cache; +micromatch.caches = cache.caches; /** * Expose `micromatch` diff --git a/lib/parsers.js b/lib/parsers.js index 961a4007..7edfa65e 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -1,6 +1,5 @@ 'use strict'; -var define = require('define-property'); var extglob = require('extglob'); var nanomatch = require('nanomatch'); var regexNot = require('regex-not'); diff --git a/lib/utils.js b/lib/utils.js index c1f2c1cb..962523be 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -11,8 +11,8 @@ var Snapdragon = require('snapdragon'); utils.define = require('define-property'); utils.diff = require('arr-diff'); utils.extend = require('extend-shallow'); -utils.typeOf = require('kind-of'); utils.pick = require('object.pick'); +utils.typeOf = require('kind-of'); utils.unique = require('array-unique'); /** @@ -89,10 +89,10 @@ utils.instantiate = function(ast, options) { */ utils.createKey = function(pattern, options) { - var key = pattern; if (typeof options === 'undefined') { - return key; + return pattern; } + var key = pattern; for (var prop in options) { if (options.hasOwnProperty(prop)) { key += ';' + prop + '=' + String(options[prop]); @@ -204,12 +204,11 @@ utils.stripDrive = function(fp) { */ utils.stripPrefix = function(str) { - if (!str || typeof str !== 'string') return str; if (str.charAt(0) !== '.') { return str; } var ch = str.charAt(1); - if (ch === '\\' || ch === '/') { + if (utils.isSlash(ch)) { return str.slice(2); } return str; @@ -226,6 +225,11 @@ utils.isSimpleChar = function(str) { return str === '' || str === ' ' || str === '.'; }; +/** + * Returns true if the given str is an escaped or + * unescaped path character + */ + utils.isSlash = function(str) { return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; }; @@ -334,11 +338,11 @@ utils.identity = function(val) { * @return {any} */ -utils.value = function(origPath, unixPath, options) { - if (typeof options === 'undefined' || options.unixify !== false) { - return unixPath; +utils.value = function(str, unixify, options) { + if (options && options.unixify === false) { + return str; } - return origPath; + return unixify(str); }; /** diff --git a/package.json b/package.json index a7be678f..7ea50928 100644 --- a/package.json +++ b/package.json @@ -2,23 +2,24 @@ "name": "micromatch", "description": "Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch.", "version": "2.3.11", - "homepage": "https://github.com/jonschlinkert/micromatch", + "homepage": "https://github.com/micromatch/micromatch", "author": "Jon Schlinkert (https://github.com/jonschlinkert)", "contributors": [ "Amila Welihinda (amilajack.com)", - "Bogdan Chadkin (https://github.com/TrySound)", - "Brian Woodward (https://twitter.com/doowb)", + "Bogdan Chadkin (https://github.com/TrySound)", + "Brian Woodward (https://twitter.com/doowb)", "Charlike Mike Reagent (https://i.am.charlike.online)", "Elan Shanker (https://github.com/es128)", "Fabrício Matté (http://ultcombo.js.org)", - "Jon Schlinkert (http://twitter.com/jonschlinkert)", - "Martin Kolárik (http://kolarik.sk)", - "Paul Miller (paulmillr.com)", - "Tom Byrer (https://github.com/tomByrer)" + "Jon Schlinkert (http://twitter.com/jonschlinkert)", + "Martin Kolárik (https://kolarik.sk)", + "Paul Miller (paulmillr.com)", + "Tom Byrer (https://github.com/tomByrer)", + "(https://github.com/DianeLooney)" ], - "repository": "jonschlinkert/micromatch", + "repository": "micromatch/micromatch", "bugs": { - "url": "https://github.com/jonschlinkert/micromatch/issues" + "url": "https://github.com/micromatch/micromatch/issues" }, "license": "MIT", "files": [ @@ -32,6 +33,35 @@ "scripts": { "test": "mocha" }, + "dependencies": { + "arr-diff": "^3.0.0", + "array-unique": "^0.3.2", + "braces": "^2.0.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "extglob": "^1.1.0", + "fragment-cache": "^0.2.1", + "kind-of": "^3.1.0", + "nanomatch": "^1.1.1", + "object.pick": "^1.2.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "devDependencies": { + "bash-match": "^0.2.0", + "extend-shallow": "^2.0.1", + "for-own": "^1.0.0", + "gulp": "^3.9.1", + "gulp-istanbul": "^1.1.1", + "gulp-mocha": "^3.0.0", + "gulp-unused": "^0.2.1", + "is-windows": "^1.0.1", + "minimatch": "^3.0.3", + "minimist": "^1.2.0", + "mocha": "^3.4.2", + "multimatch": "^2.1.0" + }, "keywords": [ "bash", "expand", @@ -68,8 +98,15 @@ } }, "devDependencies": { + "options": { + "ignore": [ + "benchmark/**" + ] + }, "files": [ - "test/{reference,support}/*.js" + "gulpfile.js", + "examples/*.js", + "test/**/*.js" ] } }, @@ -101,46 +138,7 @@ "extglob", "glob-object", "minimatch", - "multimatch", - "snapdragon", - "verb", - "verb-generate-readme" + "snapdragon" ] - }, - "dependencies": { - "arr-diff": "^3.0.0", - "array-unique": "^0.3.2", - "braces": "^2.0.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "extglob": "^1.1.0", - "fragment-cache": "^0.2.1", - "kind-of": "^3.1.0", - "nanomatch": "^1.0.3", - "object.pick": "^1.2.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "devDependencies": { - "ansi-cyan": "^0.1.1", - "bash-match": "^0.2.0", - "benchmarked": "^0.2.5", - "for-own": "^1.0.0", - "fs-exists-sync": "^0.1.0", - "gulp": "^3.9.1", - "gulp-format-md": "^0.1.12", - "gulp-istanbul": "^1.1.1", - "gulp-mocha": "^3.0.0", - "gulp-unused": "^0.2.1", - "is-object": "^1.0.1", - "is-primitive": "^2.0.0", - "is-windows": "^1.0.0", - "minimatch": "^3.0.3", - "mocha": "^3.2.0", - "multimatch": "^2.1.0", - "repeat-string": "^1.6.1", - "write": "^0.3.3", - "yargs-parser": "^5.0.0" } } diff --git a/test/api.isMatch.js b/test/api.isMatch.js index 72de33c4..e68c5ec1 100644 --- a/test/api.isMatch.js +++ b/test/api.isMatch.js @@ -109,14 +109,16 @@ describe('.isMatch():', function() { }); it('should match with common glob patterns', function() { + assert(!mm.isMatch('/ab', './*/')); + assert(!mm.isMatch('/ef', '*')); + assert(!mm.isMatch('ab', './*/')); + assert(!mm.isMatch('ef', '/*')); assert(mm.isMatch('/ab', '/*')); assert(mm.isMatch('/cd', '/*')); - assert(!mm.isMatch('ef', '/*')); - assert(mm.isMatch('ab', './*')); - assert(mm.isMatch('ab/', './*/')); - assert(!mm.isMatch('ab', './*/')); assert(mm.isMatch('ab', '*')); + assert(mm.isMatch('ab', './*')); assert(mm.isMatch('ab', 'ab')); + assert(mm.isMatch('ab/', './*/')); }); it('should exactly match leading slash', function() { @@ -187,7 +189,7 @@ describe('.isMatch():', function() { assert(mm.isMatch('a/b/c/d/g/e.f', 'a/b/**/d/**/*.*')); assert(mm.isMatch('a/b/c/d/g/g/e.f', 'a/b/**/d/**/*.*')); - // https://github.com/jonschlinkert/micromatch/issues/15 + // https://github.com/micromatch/micromatch/issues/15 assert(mm.isMatch('z.js', 'z*')); assert(mm.isMatch('z.js', '**/z*')); assert(mm.isMatch('z.js', '**/z*.js')); @@ -226,6 +228,14 @@ describe('.isMatch():', function() { assert(mm.isMatch('foo/baz/bar', 'foo/**/bar')); assert(mm.isMatch('foobazbar', 'foo**bar')); assert(mm.isMatch('XXX/foo', '**/foo')); + + // https://github.com/micromatch/micromatch/issues/89 + assert(mm.isMatch('foo//baz.md', 'foo//baz.md')); + assert(mm.isMatch('foo//baz.md', 'foo/+baz.md')); + assert(mm.isMatch('foo//baz.md', 'foo//+baz.md')); + assert(mm.isMatch('foo//baz.md', 'foo//*baz.md')); + assert(!mm.isMatch('foo//baz.md', 'foo/baz.md')); + assert(!mm.isMatch('foo/baz.md', 'foo//baz.md')); }); it('question marks should not match slashes', function() { diff --git a/test/bash.js b/test/bash.js index fc47bb2c..f237a884 100644 --- a/test/bash.js +++ b/test/bash.js @@ -3,12 +3,8 @@ require('mocha'); var assert = require('assert'); var isWindows = require('is-windows'); -var mm = require('./support/match'); - -/** - * Heads up! In these tests, `mm` is a custom function that can - * be either `micromatch` or `minimatch` if the `--mm` flag is passed - */ +var match = require('./support/match'); +var mm = require('..'); // from the Bash 4.3 specification/unit tests var fixtures = ['*', '**', '\\*', 'a', 'a/*', 'abc', 'abd', 'abe', 'b', 'bb', 'bcd', 'bdir/', 'Beware', 'c', 'ca', 'cb', 'd', 'dd', 'de']; @@ -25,246 +21,247 @@ describe('bash options and features:', function() { // $echo a/{1..3}/b describe('bash', function() { it('should handle "regular globbing":', function() { - mm(fixtures, 'a*', ['a', 'abc', 'abd', 'abe']); - mm(fixtures, '\\a*', ['a', 'abc', 'abd', 'abe']); + match(fixtures, 'a*', ['a', 'abc', 'abd', 'abe']); + match(fixtures, '\\a*', ['a', 'abc', 'abd', 'abe']); }); it('should match directories:', function() { - mm(fixtures, 'b*/', ['bdir/']); + match(fixtures, 'b*/', ['bdir/']); }); it('should use quoted characters as literals:', function() { if (isWindows()) { - mm(fixtures, '\\*', {nonull: true}, ['*', '/*']); - mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*', '/*']); + match(fixtures, '\\*', {nonull: true}, ['*', '/*']); + match(fixtures, '\\*', {nonull: true, unescape: true}, ['*', '/*']); - mm(fixtures, '\\^', {nonull: true}, ['\\^']); - mm(fixtures, '\\^', []); + match(fixtures, '\\^', {nonull: true}, ['\\^']); + match(fixtures, '\\^', []); - mm(fixtures, 'a\\*', {nonull: true}, ['a\\*']); - mm(fixtures, 'a\\*', ['a*'], {nonull: true, unescape: true}); - mm(fixtures, 'a\\*', []); + match(fixtures, 'a\\*', {nonull: true}, ['a\\*']); + match(fixtures, 'a\\*', ['a*'], {nonull: true, unescape: true}); + match(fixtures, 'a\\*', []); - mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['*', '/*', 'a\\*']); - mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*', '/*']); - mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*', '/*']); - mm(fixtures, ['a\\*', '\\*'], ['*', '/*']); + match(fixtures, ['a\\*', '\\*'], {nonull: true}, ['*', '/*', 'a\\*']); + match(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*', '/*']); + match(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*', '/*']); + match(fixtures, ['a\\*', '\\*'], ['*', '/*']); - mm(fixtures, ['a\\*'], {nonull: true}, ['a\\*']); - mm(fixtures, ['a\\*'], []); + match(fixtures, ['a\\*'], {nonull: true}, ['a\\*']); + match(fixtures, ['a\\*'], []); - mm(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a\\*', '*q*']); - mm(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); + match(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a\\*', '*q*']); + match(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); } else { - mm(fixtures, '\\*', {nonull: true}, ['*', '\\*']); - mm(fixtures, '\\*', {nonull: true, unescape: true}, ['*']); - mm(fixtures, '\\*', {nonull: true, unescape: true, unixify: false}, ['*', '\\*']); + match(fixtures, '\\*', {nonull: true}, ['*', '\\*']); + match(fixtures, '\\*', {nonull: true, unescape: true}, ['*']); + match(fixtures, '\\*', {nonull: true, unescape: true, unixify: false}, ['*', '\\*']); - mm(fixtures, '\\^', {nonull: true}, ['\\^']); - mm(fixtures, '\\^', []); + match(fixtures, '\\^', {nonull: true}, ['\\^']); + match(fixtures, '\\^', []); - mm(fixtures, 'a\\*', {nonull: true}, ['a\\*']); - mm(fixtures, 'a\\*', ['a*'], {nonull: true, unescape: true}); - mm(fixtures, 'a\\*', []); + match(fixtures, 'a\\*', {nonull: true}, ['a\\*']); + match(fixtures, 'a\\*', ['a*'], {nonull: true, unescape: true}); + match(fixtures, 'a\\*', []); - mm(fixtures, ['a\\*', '\\*'], {nonull: true}, ['a\\*', '*', '\\*']); - mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*']); - mm(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true, unixify: false}, ['a*', '*', '\\*']); - mm(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*']); - mm(fixtures, ['a\\*', '\\*'], {unescape: true, unixify: false}, ['*', '\\*']); - mm(fixtures, ['a\\*', '\\*'], ['*', '\\*']); + match(fixtures, ['a\\*', '\\*'], {nonull: true}, ['a\\*', '*', '\\*']); + match(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true}, ['a*', '*']); + match(fixtures, ['a\\*', '\\*'], {nonull: true, unescape: true, unixify: false}, ['a*', '*', '\\*']); + match(fixtures, ['a\\*', '\\*'], {unescape: true}, ['*']); + match(fixtures, ['a\\*', '\\*'], {unescape: true, unixify: false}, ['*', '\\*']); + match(fixtures, ['a\\*', '\\*'], ['*', '\\*']); - mm(fixtures, ['a\\*'], {nonull: true}, ['a\\*']); - mm(fixtures, ['a\\*'], []); + match(fixtures, ['a\\*'], {nonull: true}, ['a\\*']); + match(fixtures, ['a\\*'], []); - mm(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a\\*', '*q*']); - mm(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); + match(fixtures, ['c*', 'a\\*', '*q*'], {nonull: true}, ['c', 'ca', 'cb', 'a\\*', '*q*']); + match(fixtures, ['c*', 'a\\*', '*q*'], ['c', 'ca', 'cb']); } }); it('should work for quoted characters', function() { - mm(fixtures, '"***"', []); - mm(fixtures, '"***"', {nonull: true}, ['"***"']); - mm(fixtures, '"*"*', ['*', '**']); + match(fixtures, '"***"', []); + match(fixtures, '"***"', {nonull: true}, ['"***"']); + match(fixtures, '"*"*', ['*', '**']); }); it('should work for escaped characters', function() { - mm(fixtures, '\\**', ['*', '**']); + match(fixtures, '\\**', ['*', '**']); }); it('should work for escaped paths/dots:', function() { - mm(fixtures, '"\\.\\./*/"', {nonull: true}, ['"\\.\\./*/"']); - mm(fixtures, '"\\.\\./*/"', {nonull: true, unescape: true}, ['"../*/"']); - mm(fixtures, 's/\\..*//', {nonull: true}, ['s/\\..*//']); + match(fixtures, '"\\.\\./*/"', {nonull: true}, ['"\\.\\./*/"']); + match(fixtures, '"\\.\\./*/"', {nonull: true, unescape: true}, ['"../*/"']); + match(fixtures, 's/\\..*//', {nonull: true}, ['s/\\..*//']); }); it('Pattern from Larry Wall\'s Configure that caused bash to blow up:', function() { - mm(fixtures, '"/^root:/{s/^[^:]*:[^:]*:\\([^:]*\\).*"\'$\'"/\\1/"', {nonull: true}, ['"/^root:/{s/^[^:]*:[^:]*:\\([^:]*\\).*"\'$\'"/\\1/"']); - mm(fixtures, '[a-c]b*', ['abc', 'abd', 'abe', 'bb', 'cb']); + match(fixtures, '"/^root:/{s/^[^:]*:[^:]*:\\([^:]*\\).*"\'$\'"/\\1/"', {nonull: true}, ['"/^root:/{s/^[^:]*:[^:]*:\\([^:]*\\).*"\'$\'"/\\1/"']); + match(fixtures, '[a-c]b*', ['abc', 'abd', 'abe', 'bb', 'cb']); }); it('should support character classes', function() { var f = fixtures.slice(); f.push('baz', 'bzz', 'BZZ', 'beware', 'BewAre'); - mm(f, 'a*[^c]', ['abd', 'abe']); - mm(['a-b', 'aXb'], 'a[X-]b', ['a-b', 'aXb']); - mm(f, '[a-y]*[^c]', ['abd', 'abe', 'baz', 'bzz', 'beware', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); - mm(['a*b/ooo'], 'a\\*b/*', ['a*b/ooo']); - mm(['a*b/ooo'], 'a\\*?/*', ['a*b/ooo']); - mm(f, 'a[b]c', ['abc']); - mm(f, 'a["b"]c', ['abc']); - mm(f, 'a[\\\\b]c', ['abc']); //<= backslash and a "b" - mm(f, 'a[\\b]c', []); //<= word boundary in a character class - mm(f, 'a[b-d]c', ['abc']); - mm(f, 'a?c', ['abc']); - mm(['a-b'], 'a[]-]b', ['a-b']); - mm(['man/man1/bash.1'], '*/man*/bash.*', ['man/man1/bash.1']); + match(f, 'a*[^c]', ['abd', 'abe']); + match(['a-b', 'aXb'], 'a[X-]b', ['a-b', 'aXb']); + match(f, '[a-y]*[^c]', ['abd', 'abe', 'baz', 'bzz', 'beware', 'bb', 'bcd', 'ca', 'cb', 'dd', 'de', 'bdir/']); + match(['a*b/ooo'], 'a\\*b/*', ['a*b/ooo']); + match(['a*b/ooo'], 'a\\*?/*', ['a*b/ooo']); + match(f, 'a[b]c', ['abc']); + match(f, 'a["b"]c', ['abc']); + match(f, 'a[\\\\b]c', ['abc']); //<= backslash and a "b" + match(f, 'a[\\b]c', []); //<= word boundary in a character class + match(f, 'a[b-d]c', ['abc']); + match(f, 'a?c', ['abc']); + match(['a-b'], 'a[]-]b', ['a-b']); + match(['man/man1/bash.1'], '*/man*/bash.*', ['man/man1/bash.1']); if (isWindows()) { // should not match backslashes on windows, since backslashes are path // separators and negation character classes should not match path separators // unless it's explicitly defined in the character class - mm(f, '[^a-c]*', ['d', 'dd', 'de', 'Beware', 'BewAre', 'BZZ', '*', '**']); - mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '**'], {bash: false}); - mm(f, '[^a-c]*', ['d', 'dd', 'de', '*', '**'], {nocase: true}); + match(f, '[^a-c]*', ['d', 'dd', 'de', 'Beware', 'BewAre', 'BZZ', '*', '**']); + match(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '**'], {bash: false}); + match(f, '[^a-c]*', ['d', 'dd', 'de', '*', '**'], {nocase: true}); } else { - mm(f, '[^a-c]*', ['d', 'dd', 'de', 'Beware', 'BewAre', 'BZZ', '*', '**', '\\*']); - mm(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '**', '\\*'], {bash: false}); - mm(f, '[^a-c]*', ['d', 'dd', 'de', '*', '**', '\\*'], {nocase: true}); + match(f, '[^a-c]*', ['d', 'dd', 'de', 'Beware', 'BewAre', 'BZZ', '*', '**', '\\*']); + match(f, '[^a-c]*', ['d', 'dd', 'de', 'BewAre', 'BZZ', '*', '**', '\\*'], {bash: false}); + match(f, '[^a-c]*', ['d', 'dd', 'de', '*', '**', '\\*'], {nocase: true}); } }); it('should support basic wildmatch (brackets) features', function() { - assert(!mm.isMatch('aab', 'a[]-]b')); - assert(!mm.isMatch('ten', '[ten]')); - assert(!mm.isMatch('ten', 't[!a-g]n')); - assert(mm.isMatch(']', ']')); - assert(mm.isMatch('a-b', 'a[]-]b')); - assert(mm.isMatch('a]b', 'a[]-]b')); - assert(mm.isMatch('a]b', 'a[]]b')); - assert(mm.isMatch('aab', 'a[\\]a\\-]b')); - assert(mm.isMatch('ten', 't[a-g]n')); - assert(mm.isMatch('ton', 't[!a-g]n')); - assert(mm.isMatch('ton', 't[^a-g]n')); + assert(!match.isMatch('aab', 'a[]-]b')); + assert(!match.isMatch('ten', '[ten]')); + assert(!match.isMatch('ten', 't[!a-g]n')); + assert(match.isMatch(']', ']')); + assert(match.isMatch('a-b', 'a[]-]b')); + assert(match.isMatch('a]b', 'a[]-]b')); + assert(match.isMatch('a]b', 'a[]]b')); + assert(match.isMatch('aab', 'a[\\]a\\-]b')); + assert(match.isMatch('ten', 't[a-g]n')); + assert(match.isMatch('ton', 't[!a-g]n')); + assert(match.isMatch('ton', 't[^a-g]n')); }); - it('should support Extended slash-matching features', function() { - assert(!mm.isMatch('foo/bar', 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r')); - assert(mm.isMatch('foo/bar', 'foo[/]bar')); - assert(mm.isMatch('foo-bar', 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r')); + it('should support extended slash-matching features', function() { + assert(!match.isMatch('foo/bar', 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r')); + assert(match.isMatch('foo/bar', 'foo[/]bar')); + assert(match.isMatch('foo-bar', 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r')); }); - it('should match braces', function() { - assert(mm.isMatch('foo{}baz', 'foo[{a,b}]+baz')); + it('should not expand literal braces inside brackets', function() { + assert.deepEqual(mm.makeRe('foo[{a,b}]+baz'), /^(?:foo[{a,b}]+baz)$/); + assert(match.isMatch('foo{}baz', 'foo[{a,b}]+baz')); }); - it('should match parens', function() { - assert(mm.isMatch('foo(bar)baz', 'foo[bar()]+baz')); + it('should match literal parens', function() { + assert(match.isMatch('foo(bar)baz', 'foo[bar()]+baz')); }); it('should match escaped characters', function() { - assert(!mm.isMatch('', '\\')); - assert(!mm.isMatch('XXX/\\', '[A-Z]+/\\')); - assert(mm.isMatch('\\', '\\')); + assert(!match.isMatch('', '\\')); + assert(!match.isMatch('XXX/\\', '[A-Z]+/\\')); + assert(match.isMatch('\\', '\\')); if (isWindows()) { - assert(!mm.isMatch('XXX/\\', '[A-Z]+/\\\\')); + assert(!match.isMatch('XXX/\\', '[A-Z]+/\\\\')); } else { - assert(mm.isMatch('XXX/\\', '[A-Z]+/\\\\')); + assert(match.isMatch('XXX/\\', '[A-Z]+/\\\\')); } - assert(mm.isMatch('[ab]', '\\[ab]')); - assert(mm.isMatch('[ab]', '[\\[:]ab]')); + assert(match.isMatch('[ab]', '\\[ab]')); + assert(match.isMatch('[ab]', '[\\[:]ab]')); }); it('should match brackets', function() { - assert(!mm.isMatch(']', '[!]-]')); - assert(mm.isMatch('a', '[!]-]')); - assert(mm.isMatch('[ab]', '[[]ab]')); + assert(!match.isMatch(']', '[!]-]')); + assert(match.isMatch('a', '[!]-]')); + assert(match.isMatch('[ab]', '[[]ab]')); }); - it('tests with multiple `*\'s:', function() { - mm(['bbc', 'abc', 'bbd'], 'a**c', ['abc']); - mm(['bbc', 'abc', 'bbd'], 'a***c', ['abc']); - mm(['bbc', 'abc', 'bbc'], 'a*****?c', ['abc']); - mm(['bbc', 'abc'], '?*****??', ['bbc', 'abc']); - mm(['bbc', 'abc'], '*****??', ['bbc', 'abc']); - mm(['bbc', 'abc'], '?*****?c', ['bbc', 'abc']); - mm(['bbc', 'abc', 'bbd'], '?***?****c', ['bbc', 'abc']); - mm(['bbc', 'abc'], '?***?****?', ['bbc', 'abc']); - mm(['bbc', 'abc'], '?***?****', ['bbc', 'abc']); - mm(['bbc', 'abc'], '*******c', ['bbc', 'abc']); - mm(['bbc', 'abc'], '*******?', ['bbc', 'abc']); - mm(['abcdecdhjk'], 'a*cd**?**??k', ['abcdecdhjk']); - mm(['abcdecdhjk'], 'a**?**cd**?**??k', ['abcdecdhjk']); - mm(['abcdecdhjk'], 'a**?**cd**?**??k***', ['abcdecdhjk']); - mm(['abcdecdhjk'], 'a**?**cd**?**??***k', ['abcdecdhjk']); - mm(['abcdecdhjk'], 'a**?**cd**?**??***k**', ['abcdecdhjk']); - mm(['abcdecdhjk'], 'a****c**?**??*****', ['abcdecdhjk']); + it('should regard multiple consecutive stars as a single star', function() { + match(['bbc', 'abc', 'bbd'], 'a**c', ['abc']); + match(['bbc', 'abc', 'bbd'], 'a***c', ['abc']); + match(['bbc', 'abc', 'bbc'], 'a*****?c', ['abc']); + match(['bbc', 'abc'], '?*****??', ['bbc', 'abc']); + match(['bbc', 'abc'], '*****??', ['bbc', 'abc']); + match(['bbc', 'abc'], '?*****?c', ['bbc', 'abc']); + match(['bbc', 'abc', 'bbd'], '?***?****c', ['bbc', 'abc']); + match(['bbc', 'abc'], '?***?****?', ['bbc', 'abc']); + match(['bbc', 'abc'], '?***?****', ['bbc', 'abc']); + match(['bbc', 'abc'], '*******c', ['bbc', 'abc']); + match(['bbc', 'abc'], '*******?', ['bbc', 'abc']); + match(['abcdecdhjk'], 'a*cd**?**??k', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a**?**cd**?**??k', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a**?**cd**?**??k***', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a**?**cd**?**??***k', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a**?**cd**?**??***k**', ['abcdecdhjk']); + match(['abcdecdhjk'], 'a****c**?**??*****', ['abcdecdhjk']); }); it('none of these should output anything:', function() { - mm(['abc'], '??**********?****?', []); - mm(['abc'], '??**********?****c', []); - mm(['abc'], '?************c****?****', []); - mm(['abc'], '*c*?**', []); - mm(['abc'], 'a*****c*?**', []); - mm(['abc'], 'a********???*******', []); - mm(['a'], '[]', []); - mm(['['], '[abc', []); + match(['abc'], '??**********?****?', []); + match(['abc'], '??**********?****c', []); + match(['abc'], '?************c****?****', []); + match(['abc'], '*c*?**', []); + match(['abc'], 'a*****c*?**', []); + match(['abc'], 'a********???*******', []); + match(['a'], '[]', []); + match(['['], '[abc', []); }); }); describe('wildmat', function() { it('Basic wildmat features', function() { - assert(!mm.isMatch('foo', '*f')); - assert(!mm.isMatch('foo', '??')); - assert(!mm.isMatch('foo', 'bar')); - assert(!mm.isMatch('foobar', 'foo\\*bar')); - assert(mm.isMatch('', '')); - assert(mm.isMatch('?a?b', '\\??\\?b')); - assert(mm.isMatch('aaaaaaabababab', '*ab')); - assert(mm.isMatch('f\\oo', 'f\\oo')); - assert(mm.isMatch('foo', '*')); - assert(mm.isMatch('foo', '*foo*')); - assert(mm.isMatch('foo', '???')); - assert(mm.isMatch('foo', 'f*')); - assert(mm.isMatch('foo', 'foo')); - assert(mm.isMatch('foo*', 'foo\\*', {unixify: false})); - assert(mm.isMatch('foobar', '*ob*a*r*')); + assert(!match.isMatch('foo', '*f')); + assert(!match.isMatch('foo', '??')); + assert(!match.isMatch('foo', 'bar')); + assert(!match.isMatch('foobar', 'foo\\*bar')); + assert(!match.isMatch('', '')); + assert(match.isMatch('?a?b', '\\??\\?b')); + assert(match.isMatch('aaaaaaabababab', '*ab')); + assert(match.isMatch('f\\oo', 'f\\oo')); + assert(match.isMatch('foo', '*')); + assert(match.isMatch('foo', '*foo*')); + assert(match.isMatch('foo', '???')); + assert(match.isMatch('foo', 'f*')); + assert(match.isMatch('foo', 'foo')); + assert(match.isMatch('foo*', 'foo\\*', {unixify: false})); + assert(match.isMatch('foobar', '*ob*a*r*')); }); it('should support recursion', function() { - assert(!mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); - assert(!mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); - assert(!mm.isMatch('ab/cXd/efXg/hi', '*X*i')); - assert(!mm.isMatch('ab/cXd/efXg/hi', '*Xg*i')); - assert(!mm.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz', '**/*a*b*g*n*t')); - assert(!mm.isMatch('foo', '*/*/*')); - assert(!mm.isMatch('foo', 'fo')); - assert(!mm.isMatch('foo/bar', '*/*/*')); - assert(!mm.isMatch('foo/bar', 'foo?bar')); - assert(!mm.isMatch('foo/bb/aa/rr', '*/*/*')); - assert(!mm.isMatch('foo/bba/arr', 'foo*')); - assert(!mm.isMatch('foo/bba/arr', 'foo**')); - assert(!mm.isMatch('foo/bba/arr', 'foo/*')); - assert(!mm.isMatch('foo/bba/arr', 'foo/**arr')); - assert(!mm.isMatch('foo/bba/arr', 'foo/**z')); - assert(!mm.isMatch('foo/bba/arr', 'foo/*arr')); - assert(!mm.isMatch('foo/bba/arr', 'foo/*z')); - assert(!mm.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*')); - assert(mm.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); - assert(mm.isMatch('ab/cXd/efXg/hi', '**/*X*/**/*i')); - assert(mm.isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i')); - assert(mm.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt', '**/*a*b*g*n*t')); - assert(mm.isMatch('abcXdefXghi', '*X*i')); - assert(mm.isMatch('foo', 'foo')); - assert(mm.isMatch('foo/bar', 'foo/*')); - assert(mm.isMatch('foo/bar', 'foo/bar')); - assert(mm.isMatch('foo/bar', 'foo[/]bar')); - assert(mm.isMatch('foo/bb/aa/rr', '**/**/**')); - assert(mm.isMatch('foo/bba/arr', '*/*/*')); - assert(mm.isMatch('foo/bba/arr', 'foo/**')); - assert(mm.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*', {unixify: false})); + assert(!match.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(!match.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(!match.isMatch('ab/cXd/efXg/hi', '*X*i')); + assert(!match.isMatch('ab/cXd/efXg/hi', '*Xg*i')); + assert(!match.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz', '**/*a*b*g*n*t')); + assert(!match.isMatch('foo', '*/*/*')); + assert(!match.isMatch('foo', 'fo')); + assert(!match.isMatch('foo/bar', '*/*/*')); + assert(!match.isMatch('foo/bar', 'foo?bar')); + assert(!match.isMatch('foo/bb/aa/rr', '*/*/*')); + assert(!match.isMatch('foo/bba/arr', 'foo*')); + assert(!match.isMatch('foo/bba/arr', 'foo**')); + assert(!match.isMatch('foo/bba/arr', 'foo/*')); + assert(!match.isMatch('foo/bba/arr', 'foo/**arr')); + assert(!match.isMatch('foo/bba/arr', 'foo/**z')); + assert(!match.isMatch('foo/bba/arr', 'foo/*arr')); + assert(!match.isMatch('foo/bba/arr', 'foo/*z')); + assert(!match.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*')); + assert(match.isMatch('-adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1', '-*-*-*-*-*-*-12-*-*-*-m-*-*-*')); + assert(match.isMatch('ab/cXd/efXg/hi', '**/*X*/**/*i')); + assert(match.isMatch('ab/cXd/efXg/hi', '*/*X*/*/*i')); + assert(match.isMatch('abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt', '**/*a*b*g*n*t')); + assert(match.isMatch('abcXdefXghi', '*X*i')); + assert(match.isMatch('foo', 'foo')); + assert(match.isMatch('foo/bar', 'foo/*')); + assert(match.isMatch('foo/bar', 'foo/bar')); + assert(match.isMatch('foo/bar', 'foo[/]bar')); + assert(match.isMatch('foo/bb/aa/rr', '**/**/**')); + assert(match.isMatch('foo/bba/arr', '*/*/*')); + assert(match.isMatch('foo/bba/arr', 'foo/**')); + assert(match.isMatch('XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1', 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*', {unixify: false})); }); }); }); diff --git a/test/extglobs.js b/test/extglobs.js index acc89d5a..62c0cc87 100644 --- a/test/extglobs.js +++ b/test/extglobs.js @@ -44,6 +44,9 @@ describe('extglobs', function() { mm(['cz', 'abz', 'az'], 'a*(z)', ['az']); mm(['cz', 'abz', 'az'], 'a**(z)', ['az', 'abz']); mm(['cz', 'abz', 'az'], 'a*!(z)', ['az', 'abz']); + mm(['cz', 'abz', 'az'], 'a!(*)', []); + mm(['a.js', 'a.txt', 'a.md'], 'a.!(js)', ['a.md', 'a.txt']); + mm(['a.js', 'a.txt', 'a.md'], 'a.!(js)*', ['a.md', 'a.txt']); }); it('should support negation', function() { @@ -300,7 +303,7 @@ describe('bash', function() { assert(!mm.isMatch('foo', 'bar')); assert(!mm.isMatch('foobar', 'foo\\*bar')); assert(!mm.isMatch('abc', '\\a\\b\\c')); - assert(mm.isMatch('', '')); + assert(!mm.isMatch('', '')); assert(mm.isMatch('?a?b', '\\??\\?b')); assert(mm.isMatch('aaaaaaabababab', '*ab')); assert(mm.isMatch('\\x\\y\\z', '\\x\\y\\z')); diff --git a/test/support/matcher.js b/test/support/matcher.js index ad3b54e8..7a4a2ca9 100644 --- a/test/support/matcher.js +++ b/test/support/matcher.js @@ -1,7 +1,7 @@ 'use strict'; var utils = require('../../lib/utils'); -var argv = require('yargs-parser')(process.argv.slice(2)); +var argv = require('minimist')(process.argv.slice(2)); var bash = require('bash-match'); var minimatch = require('minimatch'); var mu = require('multimatch'); diff --git a/test/support/utils.js b/test/support/utils.js index 89c2793d..e3fbd780 100644 --- a/test/support/utils.js +++ b/test/support/utils.js @@ -1,13 +1,13 @@ 'use strict'; -var exists = require('fs-exists-sync'); +var fs = require('fs'); var bashPath; exports.getBashPath = function() { if (bashPath) return bashPath; - if (exists('/usr/local/bin/bash')) { + if (fs.existsSync('/usr/local/bin/bash')) { bashPath = '/usr/local/bin/bash'; - } else if (exports.exists('/bin/bash')) { + } else if (fs.existsSync('/bin/bash')) { bashPath = '/bin/bash'; } else { bashPath = 'bash'; From cfeaa2933c8ed0931f37a44936a8e2bf22a0ba40 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Sun, 28 May 2017 20:03:25 -0400 Subject: [PATCH 63/68] docs --- .verb.md | 253 ++++++++++---- CHANGELOG.md | 37 ++ README.md | 567 +++++++++++++++++++++---------- appveyor.yml | 2 +- docs/minimatch.md | 214 ------------ docs/switching-from-minimatch.md | 28 -- 6 files changed, 611 insertions(+), 490 deletions(-) create mode 100644 CHANGELOG.md delete mode 100644 docs/minimatch.md delete mode 100644 docs/switching-from-minimatch.md diff --git a/.verb.md b/.verb.md index e9a45e06..88d4fd9d 100644 --- a/.verb.md +++ b/.verb.md @@ -19,9 +19,9 @@ console.log(mm.isMatch('foo', 'f*')); // true **Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-multimatch) is easy**: -* [mm()](#usage) is the same as [multimatch()][multimatch] -* [mm.match()](#match) is the same as [minimatch.match()][minimatch] -* use [mm.isMatch()](#ismatch) instead of [minimatch()][minimatch] +* use [mm.isMatch()](#ismatch) instead of `minimatch()` +* [mm.match()](#match) is the same as `minimatch.match()` +* [mm()](#usage) is the same as `multimatch()` **Heads up!** @@ -31,18 +31,29 @@ There is one notable difference between micromatch and minimatch in regards to h > micromatch is a [drop-in replacement][switch] for minimatch and multimatch -Micromatch is [safer][braces]{#braces-is-safe}, [faster](#benchmarks), more accurate, and supports all of the same matching features as [minimatch][] and [multimatch][]. +**Speed and accuracy** -Moreover, micromatch has: +Micromatch uses [snapdragon][] for parsing and compiling globs, which results in: + +- Granular control over the entire conversion process in a way that is easy to understand, reason about, and customize. +- Faster matching, from a combination of optimized glob patterns and (optional) caching. +- Much greater accuracy than minimatch. In fact, nanomatch passes _all of the spec tests_ from bash, including some that bash still fails. However, since there is no real specification for globs, if you encounter a pattern that yields unexpected match results [after researching previous issues](../../issues), [please let us know](../../issues/new). + + +- [Micromatch is safer](https://github.com/jonschlinkert/braces#braces-is-safe), and is not subject to DoS with brace patterns, like minimatch and multimatch. +- [faster](#benchmarks) matching +- More accurate, with more than 36,000 [unit tests](./test) - and thousands more patterns tested - to prove it. _(minimatch and multimatch fail a great number of the tests)_. +- More complete support for the Bash 4.3 specification than minimatch and multimatch +- More reliable windows support than minimatch and multimatch +- Supports all of the same matching features as [minimatch](https://github.com/isaacs/minimatch) and [multimatch](https://github.com/sindresorhus/multimatch) +- Micromatch uses real parsers and compilers. Although edge cases are inevitable, micromatch is better equipped to handle them. -* Better support for the Bash 4.3 specification than minimatch and multimatch -* Better windows support than minimatch and multimatch -* More than 36,000 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail a great number of the tests) ### Features * Native support for multiple glob patterns (no need for wrappers like multimatch) -* Glob pattern support (`**/*`, `a/b/*.js`, or `['a/*.js', '!b.js']`) +* Basic wildcard support (`**/*`, `a/b/*.js`, or `['a/*.js', '*b.js']`) +* Negation support (`['!a/*.js', '*!(b).js']`) * [extglob][] support (`+(x|y)`, `!(a|b)`, etc) * [POSIX character class][brackets] support (`**/[[:alpha:][:digit:]]/`) * [brace expansion][braces] support (`a/b-{1..5}.md`, `one/{two,three}/four.md`) @@ -86,32 +97,34 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); ## API {%= apidocs("index.js") %} - - ## Options -- [options.basename](#options-basename) -- [options.cache](#options-cache) -- [options.dot](#options-dot) -- [options.failglob](#options-failglob) -- [options.ignore](#options-ignore) -- [options.matchBase](#options-matchBase) -- [options.nobrace](#options-nobrace) -- [options.nocase](#options-nocase) -- [options.nodupes](#options-nodupes) -- [options.nonull](#options-nonull) -- [options.nullglob](#options-nullglob) -- [options.snapdragon](#options-snapdragon) -- [options.unescape](#options-unescape) -- [options.unixify](#options-unixify) +- [basename](#options-basename) +- [bash](#options-bash) +- [cache](#options-cache) +- [dot](#options-dot) +- [failglob](#options-failglob) +- [ignore](#options-ignore) +- [matchBase](#options-matchBase) +- [nobrace](#options-nobrace) +- [nocase](#options-nocase) +- [nodupes](#options-nodupes) +- [noext](#options-noext) +- [noglobstar](#options-noglobstar) +- [nonull](#options-nonull) +- [nullglob](#options-nullglob) +- [snapdragon](#options-snapdragon) +- [sourcemap](#options-sourcemap) +- [unescape](#options-unescape) +- [unixify](#options-unixify) ### options.basename Allow glob patterns without slashes to match a file path based on its basename. Same behavior as [minimatch][] option `matchBase`. -Type: `Boolean` +**Type**: `Boolean` -Default: `false` +**Default**: `false` **Example** @@ -123,40 +136,58 @@ mm(['a/b.js', 'a/c.md'], '*.js', {matchBase: true}); //=> ['a/b.js'] ``` +### options.bash + +Enabled by default, this option enforces bash-like behavior with stars immediately following a bracket expression. Bash bracket expressions are similar to regex character classes, but unlike regex, a star following a bracket expression **does not repeat the bracketed characters**. Instead, the star is treated the same as an other star. + +**Type**: `Boolean` + +**Default**: `true` + +**Example** + +```js +var files = ['abc', 'ajz']; +console.log(mm(files, '[a-c]*')); +//=> ['abc', 'ajz'] + +console.log(mm(files, '[a-c]*', {bash: false})); +``` + ### options.cache Disable regex and function memoization. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` ### options.dot Match dotfiles. Same behavior as [minimatch][] option `dot`. -Type: `Boolean` +**Type**: `Boolean` -Default: `false` +**Default**: `false` ### options.failglob Similar to the `--failglob` behavior in Bash, throws an error when no matches are found. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` ### options.ignore String or array of glob patterns to match files to ignore. -Type: `String|Array` +**Type**: `String|Array` -Default: `undefined` +**Default**: `undefined` ### options.matchBase @@ -168,9 +199,9 @@ Alias for [options.basename](#options-basename). Disable expansion of brace patterns. Same behavior as [minimatch][] option `nobrace`. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` See [braces][] for more information about extended brace expansion. @@ -179,18 +210,18 @@ See [braces][] for more information about extended brace expansion. Use a case-insensitive regex for matching files. Same behavior as [minimatch][]. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` ### options.nodupes Remove duplicate elements from the result array. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` **Example** @@ -204,15 +235,50 @@ mm.match(['a/b/c', 'a/b/c'], 'a/b/c', {nodupes: true}); //=> ['abc'] ``` +### options.noext + +Disable extglob support, so that extglobs are regarded as literal characters. + +**Type**: `Boolean` + +**Default**: `undefined` + +**Examples** + +```js +mm(['a/z', 'a/b', 'a/!(z)'], 'a/!(z)'); +//=> ['a/b', 'a/!(z)'] + +mm(['a/z', 'a/b', 'a/!(z)'], 'a/!(z)', {noext: true}); +//=> ['a/!(z)'] (matches only as literal characters) +``` + + ### options.nonegate Disallow negation (`!`) patterns, and treat leading `!` as a literal character to match. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` +### options.noglobstar + +Disable matching with globstars (`**`). + +**Type**: `Boolean` + +**Default**: `undefined` + +```js +mm(['a/b', 'a/b/c', 'a/b/c/d'], 'a/**'); +//=> ['a/b', 'a/b/c', 'a/b/c/d'] + +mm(['a/b', 'a/b/c', 'a/b/c/d'], 'a/**', {noglobstar: true}); +//=> ['a/b'] +``` + ### options.nonull Alias for [options.nullglob](#options-nullglob). @@ -222,27 +288,66 @@ Alias for [options.nullglob](#options-nullglob). If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch][] option `nonull`. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` ### options.snapdragon Pass your own instance of [snapdragon][], to customize parsers or compilers. -Type: `Object` +**Type**: `Object` + +**Default**: `undefined` + -Default: `undefined` +### options.sourcemap +Generate a source map by enabling the `sourcemap` option with the `.parse`, `.compile`, or `.create` methods. + +_(Note that sourcemaps are currently not enabled for brace patterns)_ + +**Examples** + +``` js +var mm = require('micromatch'); +var pattern = '*(*(of*(a)x)z)'; + +var res = mm.create('abc/*.js', {sourcemap: true}); +console.log(res.map); +// { version: 3, +// sources: [ 'string' ], +// names: [], +// mappings: 'AAAA,GAAG,EAAC,iBAAC,EAAC,EAAE', +// sourcesContent: [ 'abc/*.js' ] } + +var ast = mm.parse('abc/**/*.js'); +var res = mm.compile(ast, {sourcemap: true}); +console.log(res.map); +// { version: 3, +// sources: [ 'string' ], +// names: [], +// mappings: 'AAAA,GAAG,EAAC,2BAAE,EAAC,iBAAC,EAAC,EAAE', +// sourcesContent: [ 'abc/**/*.js' ] } + +var ast = mm.parse(pattern); +var res = mm.compile(ast, {sourcemap: true}); +console.log(res.map); +// { version: 3, +// sources: [ 'string' ], +// names: [], +// mappings: 'AAAA,CAAE,CAAE,EAAE,CAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC', +// sourcesContent: [ '*(*(of*(a)x)z)' ] } +``` ### options.unescape Remove backslashes from returned matches. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` **Example** @@ -260,9 +365,9 @@ mm.match(['abc', 'a\\*c'], 'a\\*c', {unescape: true}); Convert path separators on returned files to posix/unix-style forward slashes. -Type: `Boolean` +**Type**: `Boolean` -Default: `true` +**Default**: `true` on windows, `false` everywhere else **Example** @@ -284,18 +389,16 @@ Extended globbing, as described by the bash man page: | **pattern** | **regex equivalent** | **description** | | --- | --- | --- | -| `?(pattern-list)` | `(... | ...)?` | Matches zero or one occurrence of the given patterns | -| `*(pattern-list)` | `(... | ...)*` | Matches zero or more occurrences of the given patterns | -| `+(pattern-list)` | `(... | ...)+` | Matches one or more occurrences of the given patterns | -| `@(pattern-list)` | `(... | ...)` * | Matches one of the given patterns | -| `!(pattern-list)` | N/A | Matches anything except one of the given patterns | +| `?(pattern-list)` | `(foo|bar)?` | Matches zero or one occurrence of the given patterns | +| `*(pattern-list)` | `(foo|bar)*` | Matches zero or more occurrences of the given patterns | +| `+(pattern-list)` | `(foo|bar)+` | Matches one or more occurrences of the given patterns | +| `@(pattern-list)` | `(foo|bar)` * | Matches one of the given patterns | +| `!(pattern-list)` | N/A (equivalent regex is much more complicated) | Matches anything except one of the given patterns | -* `@` isn't a RegEx character. +* Note that `@` isn't a RegEx character. Powered by [extglob](https://github.com/jonschlinkert/extglob). Visit that library for the full range of options or to report extglob related issues. -See [extglob](https://github.com/jonschlinkert/extglob) for more information about extended globs. - ### braces **Expanded braces** @@ -309,7 +412,7 @@ Braces are expanded when `` By default, brace patterns work the same way regex logical `OR` operators. For example, `(a|b)` will achieve the same result as `{a,b}`. -Visit [braces](https://github.com/jonschlinkert/braces) to ask questions and create an issue related to brace-expansion, or to see the full range of features and options related to brace expansion. +Visit [braces](https://github.com/jonschlinkert/braces) to see the full range of features and options related to brace expansion, or to create brace matching or expansion related issues. ### regex character classes @@ -330,26 +433,34 @@ Given `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: * `(b|d).js`: would match either `b` or `d`, returning `['b.js', 'd.js']` * `(b|[A-Z]).js`: would match either `b` or an uppercase letter, returning `['b.js', 'E.js']` -As with regex, parenthese can be nested, so patterns like `((a|b)|c)/b` will work. But it might be easier to achieve your goal using brace expansion. +As with regex, parens can be nested, so patterns like `((a|b)|c)/b` will work. Although brace expansion might be friendlier to use, depending on preference. ### POSIX bracket expressions +POSIX brackets are intended to be more user-friendly than regex character classes. This of course is in the eye of the beholder. + **Example** ```js mm.isMatch('a1', '[[:alpha:][:digit:]]'); //=> true + +mm.isMatch('a1', '[[:alpha:][:alpha:]]'); +//=> false ``` See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more information about bracket expressions. *** + ## Notes ### Bash 4.3 parity -Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3, which is mostly also constistent with minimatch. Patterns that aren't described in enough detail by the Bash spec follow wildmatch spec (used by git). +Whenever possible matching behavior is based on behavior Bash 4.3, which is mostly consistent with minimatch. + +However, it's suprising how many edge cases and rabbit holes there are with glob matching, and since there is no real glob specification, and micromatch is more accurate than both Bash and minimatch, there are cases where best-guesses were made for behavior. In a few cases where Bash had no answers, we used wildmatch (used by git) as a fallback. ### Backslashes @@ -365,21 +476,21 @@ We made this decision for micromatch for a couple of reasons: **A note about joining paths to globs** -Note that when you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting it to still work as a glob pattern. This causes problems on windows, since the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. - -In other words, since `\\` is reserved as an escape character in globs, on windows `path.join('foo', '*')` would result in `foo\\*`, which tells micromatch to match `*` as a literal character (fwiw this is the same behavior as bash). - - - -This is the convention in all mainstream globbing libs, including bash glob, minimatch and node-glob (although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212) +Note that when you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting it to still work as a glob pattern. This causes problems on windows, since the `path.sep` is `\\`. +In other words, since `\\` is reserved as an escape character in globs, on windows `path.join('foo', '*')` would result in `foo\\*`, which tells micromatch to match `*` as a literal character. This is the same behavior as bash. +## Contributing -, and minimatch enforces this convention by converting backslashes to forward slashes). +All contributions are welcome! Please read [the contributing guide](.github/contributing.md) to get started. +**A special note about bug reports** +Please feel free to create an issue if you find something that you think isn't right. However, especially (but not exclusively) if you find a matching-related issue, please please try do the following first: -To get around this, you can either do the joining manually or find a lib on npm that does this. +- research existing issues first +- visit the [GNU Bash documentation](https://www.gnu.org/software/bash/manual/) to see how Bash deals with the pattern +- visit the [minimatch][] documentation to cross-check expected behavior ## Benchmarks diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..6ba17ef9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,37 @@ +## History + +### key + +Changelog entries are classified using the following labels _(from [keep-a-changelog][]_): + +- `added`: for new features +- `changed`: for changes in existing functionality +- `deprecated`: for once-stable features removed in upcoming releases +- `removed`: for deprecated features removed in this release +- `fixed`: for any bug fixes +- `bumped`: updated dependencies, only minor or higher will be listed. + +### [3.0.0] - 2017-04-11 + +TODO + +### [1.0.1] - 2016-12-12 + +**Added** + +- Support for windows path edge cases where backslashes are used in brackets or other unusual combinations. + +### [1.0.0] - 2016-12-12 + +Stable release. + +### [0.1.0] - 2016-10-08 + +First release. + + +[Unreleased]: https://github.com/jonschlinkert/micromatch/compare/0.1.0...HEAD +[0.2.0]: https://github.com/jonschlinkert/micromatch/compare/0.1.0...0.2.0 + +[keep-a-changelog]: https://github.com/olivierlacan/keep-a-changelog + diff --git a/README.md b/README.md index c6e3ab0c..2f731f9f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# micromatch [![NPM version](https://img.shields.io/npm/v/micromatch.svg?style=flat)](https://www.npmjs.com/package/micromatch) [![NPM monthly downloads](https://img.shields.io/npm/dm/micromatch.svg?style=flat)](https://npmjs.org/package/micromatch) [![NPM total downloads](https://img.shields.io/npm/dt/micromatch.svg?style=flat)](https://npmjs.org/package/micromatch) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/micromatch.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/micromatch) [![Windows Build Status](https://img.shields.io/appveyor/ci/jonschlinkert/micromatch.svg?style=flat&label=AppVeyor)](https://ci.appveyor.com/project/jonschlinkert/micromatch) +# micromatch [![NPM version](https://img.shields.io/npm/v/micromatch.svg?style=flat)](https://www.npmjs.com/package/micromatch) [![NPM monthly downloads](https://img.shields.io/npm/dm/micromatch.svg?style=flat)](https://npmjs.org/package/micromatch) [![NPM total downloads](https://img.shields.io/npm/dt/micromatch.svg?style=flat)](https://npmjs.org/package/micromatch) [![Linux Build Status](https://img.shields.io/travis/micromatch/micromatch.svg?style=flat&label=Travis)](https://travis-ci.org/micromatch/micromatch) [![Windows Build Status](https://img.shields.io/appveyor/ci/micromatch/micromatch.svg?style=flat&label=AppVeyor)](https://ci.appveyor.com/project/micromatch/micromatch) > Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch. @@ -13,6 +13,7 @@ - [API](#api) - [Options](#options) * [options.basename](#optionsbasename) + * [options.bash](#optionsbash) * [options.cache](#optionscache) * [options.dot](#optionsdot) * [options.failglob](#optionsfailglob) @@ -21,10 +22,13 @@ * [options.nobrace](#optionsnobrace) * [options.nocase](#optionsnocase) * [options.nodupes](#optionsnodupes) + * [options.noext](#optionsnoext) * [options.nonegate](#optionsnonegate) + * [options.noglobstar](#optionsnoglobstar) * [options.nonull](#optionsnonull) * [options.nullglob](#optionsnullglob) * [options.snapdragon](#optionssnapdragon) + * [options.sourcemap](#optionssourcemap) * [options.unescape](#optionsunescape) * [options.unixify](#optionsunixify) - [Extended globbing](#extended-globbing) @@ -34,18 +38,13 @@ * [regex groups](#regex-groups) * [POSIX bracket expressions](#posix-bracket-expressions) - [Notes](#notes) + * [Bash 4.3 parity](#bash-43-parity) + * [Backslashes](#backslashes) +- [Contributing](#contributing) - [Benchmarks](#benchmarks) * [Running benchmarks](#running-benchmarks) * [Latest results](#latest-results) - [About](#about) - * [Related projects](#related-projects) - * [Contributing](#contributing) - * [Contributors](#contributors) - * [Release history](#release-history) - * [Building docs](#building-docs) - * [Running tests](#running-tests) - * [Author](#author) - * [License](#license) _(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_ @@ -78,26 +77,38 @@ console.log(mm.isMatch('foo', 'f*')); // true **Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-multimatch) is easy**: -* [mm()](#usage) is the same as [multimatch()](https://github.com/sindresorhus/multimatch) -* [mm.match()](#match) is the same as [minimatch.match()](https://github.com/isaacs/minimatch) -* use [mm.isMatch()](#ismatch) instead of [minimatch()](https://github.com/isaacs/minimatch) +* use [mm.isMatch()](#ismatch) instead of `minimatch()` +* [mm.match()](#match) is the same as `minimatch.match()` +* [mm()](#usage) is the same as `multimatch()` + +**Heads up!** + +There is one notable difference between micromatch and minimatch in regards to how backslashes are handled. See [the notes about backslashes](#backslashes) for more information. ## Why use micromatch? > micromatch is a [drop-in replacement](#switch-from-minimatch) for minimatch and multimatch -Micromatch is [safer](https://github.com/jonschlinkert/braces#braces-is-safe), [faster](#benchmarks), more accurate, and supports all of the same matching features as [minimatch](https://github.com/isaacs/minimatch) and [multimatch](https://github.com/sindresorhus/multimatch). +**Speed and accuracy** -Moreover, micromatch has: +Micromatch uses [snapdragon](https://github.com/jonschlinkert/snapdragon) for parsing and compiling globs, which results in: -* Better support for the Bash 4.3 specification than minimatch and multimatch -* Better windows support than minimatch and multimatch -* More than 36,000 [unit tests](./test), with thousands more patterns tested (minimatch and multimatch fail a great number of the tests) +* Granular control over the entire conversion process in a way that is easy to understand, reason about, and customize. +* Faster matching, from a combination of optimized glob patterns and (optional) caching. +* Much greater accuracy than minimatch. In fact, nanomatch passes _all of the spec tests_ from bash, including some that bash still fails. However, since there is no real specification for globs, if you encounter a pattern that yields unexpected match results [after researching previous issues](../../issues), [please let us know](../../issues/new). +* [Micromatch is safer](https://github.com/jonschlinkert/braces#braces-is-safe), and is not subject to DoS with brace patterns, like minimatch and multimatch. +* [faster](#benchmarks) matching +* More accurate, with more than 36,000 [unit tests](./test) - and thousands more patterns tested - to prove it. _(minimatch and multimatch fail a great number of the tests)_. +* More complete support for the Bash 4.3 specification than minimatch and multimatch +* More reliable windows support than minimatch and multimatch +* Supports all of the same matching features as [minimatch](https://github.com/isaacs/minimatch) and [multimatch](https://github.com/sindresorhus/multimatch) +* Micromatch uses real parsers and compilers. Although edge cases are inevitable, micromatch is better equipped to handle them. ### Features * Native support for multiple glob patterns (no need for wrappers like multimatch) -* Glob pattern support (`**/*`, `a/b/*.js`, or `['a/*.js', '!b.js']`) +* Basic wildcard support (`**/*`, `a/b/*.js`, or `['a/*.js', '*b.js']`) +* Negation support (`['!a/*.js', '*!(b).js']`) * [extglob](https://github.com/jonschlinkert/extglob) support (`+(x|y)`, `!(a|b)`, etc) * [POSIX character class](https://github.com/jonschlinkert/expand-brackets) support (`**/[[:alpha:][:digit:]]/`) * [brace expansion](https://github.com/jonschlinkert/braces) support (`a/b-{1..5}.md`, `one/{two,three}/four.md`) @@ -140,10 +151,17 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); ## API -### [micromatch](index.js#L40) +### [micromatch](index.js#L41) The main function takes a list of strings and one or more glob patterns to use for matching. +**Params** + +* `list` **{Array}**: A list of strings to match +* `patterns` **{String|Array}**: One or more glob patterns to use for matching. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed +* `returns` **{Array}**: Returns an array of matches + **Example** ```js @@ -154,16 +172,16 @@ console.log(mm(['a.js', 'a.txt'], ['*.js'])); //=> [ 'a.js' ] ``` -**Params** +### [.match](index.js#L107) -* `list` **{Array}**: A list of strings to match -* `patterns` **{String|Array}**: One or more glob patterns to use for matching. -* `options` **{Object}**: Any [options](#options) to change how matches are performed -* `returns` **{Array}**: Returns an array of matches +Similar to the main function, but `pattern` must be a string. -### [.match](index.js#L103) +**Params** -Similar to the main function, but `pattern` must be a string. +* `list` **{Array}**: Array of strings to match +* `pattern` **{String}**: Glob pattern to use for matching. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed +* `returns` **{Array}**: Returns an array of matches **Example** @@ -175,16 +193,16 @@ console.log(mm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); //=> ['a.a', 'a.aa'] ``` -**Params** +### [.isMatch](index.js#L168) -* `list` **{Array}**: Array of strings to match -* `pattern` **{String}**: Glob pattern to use for matching. -* `options` **{Object}**: Any [options](#options) to change how matches are performed -* `returns` **{Array}**: Returns an array of matches +Returns true if the specified `string` matches the given glob `pattern`. -### [.isMatch](index.js#L166) +**Params** -Returns true if the specified `string` matches the given glob `pattern`. +* `string` **{String}**: String to match +* `pattern` **{String}**: Glob pattern to use for matching. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed +* `returns` **{Boolean}**: Returns true if the string matches the glob pattern. **Example** @@ -198,37 +216,66 @@ console.log(mm.isMatch('a.b', '*.a')); //=> false ``` -**Params** +### [.some](index.js#L206) -* `string` **{String}**: String to match -* `pattern` **{String}**: Glob pattern to use for matching. -* `options` **{Object}**: Any [options](#options) to change how matches are performed -* `returns` **{Boolean}**: Returns true if the string matches the glob pattern. +Returns true if some of the elements in the given `list` match any of the given glob `patterns`. -### [.not](index.js#L200) +**Params** -Returns a list of strings that _DO NOT MATCH_ any of the given `patterns`. +* `list` **{String|Array}**: The string or array of strings to test. Returns as soon as the first match is found. +* `patterns` **{String|Array}**: One or more glob patterns to use for matching. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed +* `returns` **{Boolean}**: Returns true if any patterns match `str` **Example** ```js var mm = require('micromatch'); -mm.not(list, patterns[, options]); +mm.some(list, patterns[, options]); -console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); -//=> ['b.b', 'c.c'] +console.log(mm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); +// true +console.log(mm.some(['foo.js'], ['*.js', '!foo.js'])); +// false ``` +### [.every](index.js#L244) + +Returns true if every element in the given `list` matches at least one of the given glob `patterns`. + **Params** -* `list` **{Array}**: Array of strings to match. -* `patterns` **{String|Array}**: One or more glob pattern to use for matching. -* `options` **{Object}**: Any [options](#options) to change how matches are performed -* `returns` **{Array}**: Returns an array of strings that **do not match** the given patterns. +* `list` **{String|Array}**: The string or array of strings to test. +* `patterns` **{String|Array}**: One or more glob patterns to use for matching. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed +* `returns` **{Boolean}**: Returns true if any patterns match `str` -### [.any](index.js#L237) +**Example** -Returns true if the given `string` matches any of the given glob `patterns`. +```js +var mm = require('micromatch'); +mm.every(list, patterns[, options]); + +console.log(mm.every('foo.js', ['foo.js'])); +// true +console.log(mm.every(['foo.js', 'bar.js'], ['*.js'])); +// true +console.log(mm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); +// false +console.log(mm.every(['foo.js'], ['*.js', '!foo.js'])); +// false +``` + +### [.any](index.js#L278) + +Returns true if **any** of the given glob `patterns` match the specified `string`. + +**Params** + +* `str` **{String|Array}**: The string to test. +* `patterns` **{String|Array}**: One or more glob patterns to use for matching. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed +* `returns` **{Boolean}**: Returns true if any patterns match `str` **Example** @@ -242,17 +289,68 @@ console.log(mm.any('a.a', 'b.*')); //=> false ``` +### [.all](index.js#L326) + +Returns true if **all** of the given `patterns` match the specified string. + **Params** -* `list` **{String|Array}**: The string or array of strings to test. Returns as soon as the first match is found. +* `str` **{String|Array}**: The string to test. * `patterns` **{String|Array}**: One or more glob patterns to use for matching. -* `options` **{Object}**: Any [options](#options) to change how matches are performed +* `options` **{Object}**: See available [options](#options) for changing how matches are performed * `returns` **{Boolean}**: Returns true if any patterns match `str` -### [.contains](index.js#L280) +**Example** + +```js +var mm = require('micromatch'); +mm.all(string, patterns[, options]); + +console.log(mm.all('foo.js', ['foo.js'])); +// true + +console.log(mm.all('foo.js', ['*.js', '!foo.js'])); +// false + +console.log(mm.all('foo.js', ['*.js', 'foo.js'])); +// true + +console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); +// true +``` + +### [.not](index.js#L360) + +Returns a list of strings that _**do not match any**_ of the given `patterns`. + +**Params** + +* `list` **{Array}**: Array of strings to match. +* `patterns` **{String|Array}**: One or more glob pattern to use for matching. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed +* `returns` **{Array}**: Returns an array of strings that **do not match** the given patterns. + +**Example** + +```js +var mm = require('micromatch'); +mm.not(list, patterns[, options]); + +console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); +//=> ['b.b', 'c.c'] +``` + +### [.contains](index.js#L395) Returns true if the given `string` contains the given pattern. Similar to [.isMatch](#isMatch) but the pattern can match any part of the string. +**Params** + +* `str` **{String}**: The string to match. +* `patterns` **{String|Array}**: Glob pattern to use for matching. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed +* `returns` **{Boolean}**: Returns true if the patter matches any part of `str`. + **Example** ```js @@ -265,16 +363,16 @@ console.log(mm.contains('aa/bb/cc', '*d')); //=> false ``` -**Params** +### [.matchKeys](index.js#L451) -* `str` **{String}**: The string to match. -* `pattern` **{String}**: Glob pattern to use for matching. -* `options` **{Object}**: Any [options](#options) to change how matches are performed -* `returns` **{Boolean}**: Returns true if the patter matches any part of `str`. +Filter the keys of the given object with the given `glob` pattern and `options`. Does not attempt to match nested keys. If you need this feature, use [glob-object](https://github.com/jonschlinkert/glob-object) instead. -### [.matchKeys](index.js#L329) +**Params** -Filter the keys of the given object with the given `glob` pattern and `options`. Does not attempt to match nested keys. If you need this feature, use [glob-object](https://github.com/jonschlinkert/glob-object) instead. +* `object` **{Object}**: The object with keys to filter. +* `patterns` **{String|Array}**: One or more glob patterns to use for matching. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed +* `returns` **{Object}**: Returns an object with only keys that match the given patterns. **Example** @@ -287,16 +385,15 @@ console.log(mm.matchKeys(obj, '*b')); //=> { ab: 'b' } ``` -**Params** +### [.matcher](index.js#L480) -* `object` **{Object}**: The object with keys to filter. -* `patterns` **{String|Array}**: One or more glob patterns to use for matching. -* `options` **{Object}**: Any [options](#options) to change how matches are performed -* `returns` **{Object}**: Returns an object with only keys that match the given patterns. +Returns a memoized matcher function from the given glob `pattern` and `options`. The returned function takes a string to match as its only argument and returns true if the string is a match. -### [.matcher](index.js#L358) +**Params** -Returns a memoized matcher function from the given glob `pattern` and `options`. The returned function takes a string to match as its only argument and returns true if the string is a match. +* `pattern` **{String}**: Glob pattern +* `options` **{Object}**: See available [options](#options) for changing how matches are performed. +* `returns` **{Function}**: Returns a matcher function. **Example** @@ -311,15 +408,15 @@ console.log(isMatch('a.b')); //=> true ``` -**Params** +### [.makeRe](index.js#L554) -* `pattern` **{String}**: Glob pattern -* `options` **{Object}**: Any [options](#options) to change how matches are performed. -* `returns` **{Function}**: Returns a matcher function. +Create a regular expression from the given glob `pattern`. -### [.makeRe](index.js#L420) +**Params** -Create a regular expression from the given glob `pattern`. +* `pattern` **{String}**: A glob pattern to convert to regex. +* `options` **{Object}**: See available [options](#options) for changing how matches are performed. +* `returns` **{RegExp}**: Returns a regex created from the given pattern. **Example** @@ -331,15 +428,15 @@ console.log(mm.makeRe('*.js')); //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ ``` -**Params** +### [.braces](index.js#L601) -* `pattern` **{String}**: A glob pattern to convert to regex. -* `options` **{Object}**: Any [options](#options) to change how matches are performed. -* `returns` **{RegExp}**: Returns a regex created from the given pattern. +Expand the given brace `pattern`. -### [.braces](index.js#L463) +**Params** -Expand the given brace `pattern`. +* `pattern` **{String}**: String with brace pattern to expand. +* `options` **{Object}**: Any [options](#options) to change how expansion is performed. See the [braces](https://github.com/jonschlinkert/braces) library for all available options. +* `returns` **{Array}** **Example** @@ -352,15 +449,15 @@ console.log(mm.braces('foo/{a,b}/bar', {expand: true})); //=> ['foo/(a|b)/bar'] ``` -**Params** +### [.create](index.js#L665) -* `pattern` **{String}**: String with brace pattern to expand. -* `options` **{Object}**: Any [options](#options) to change how expansion is performed. See the [braces](https://github.com/jonschlinkert/braces) library for all available options. -* `returns` **{Array}** +Parses the given glob `pattern` and returns an array of abstract syntax trees (ASTs), with the compiled `output` and optional source `map` on each AST. -### [.create](index.js#L516) +**Params** -Parses the given glob `pattern` and returns an object with the compiled `output` and optional source `map`. +* `pattern` **{String}**: Glob pattern to parse and compile. +* `options` **{Object}**: Any [options](#options) to change how parsing and compiling is performed. +* `returns` **{Object}**: Returns an object with the parsed AST, compiled string and optional source map. **Example** @@ -369,7 +466,7 @@ var mm = require('micromatch'); mm.create(pattern[, options]); console.log(mm.create('abc/*.js')); -// { options: { source: 'string', sourcemap: true }, +// [{ options: { source: 'string', sourcemap: true }, // state: {}, // compilers: // { ... }, @@ -391,18 +488,18 @@ console.log(mm.create('abc/*.js')); // position: { line: 1, column: 28 }, // content: {}, // files: {}, -// idx: 6 } +// idx: 6 }] ``` -**Params** +### [.parse](index.js#L712) -* `pattern` **{String}**: Glob pattern to parse and compile. -* `options` **{Object}**: Any [options](#options) to change how parsing and compiling is performed. -* `returns` **{Object}**: Returns an object with the parsed AST, compiled string and optional source map. +Parse the given `str` with the given `options`. -### [.parse](index.js#L573) +**Params** -Parse the given `str` with the given `options`. +* `str` **{String}** +* `options` **{Object}** +* `returns` **{Object}**: Returns an AST **Example** @@ -427,15 +524,15 @@ console.log(ast); // { type: 'eos', val: '' } ] } ``` -**Params** +### [.compile](index.js#L765) -* `str` **{String}** -* `options` **{Object}** -* `returns` **{Object}**: Returns an AST +Compile the given `ast` or string with the given `options`. -### [.compile](index.js#L626) +**Params** -Compile the given `ast` or string with the given `options`. +* `ast` **{Object|String}** +* `options` **{Object}** +* `returns` **{Object}**: Returns an object that has an `output` property with the compiled string. **Example** @@ -461,13 +558,7 @@ console.log(mm.compile(ast)); // parsingErrors: [] } ``` -**Params** - -* `ast` **{Object|String}** -* `options` **{Object}** -* `returns` **{Object}**: Returns an object that has an `output` property with the compiled string. - -### [.clearCache](index.js#L649) +### [.clearCache](index.js#L786) Clear the regex cache. @@ -479,28 +570,32 @@ mm.clearCache(); ## Options -* [options.basename](#options-basename) -* [options.cache](#options-cache) -* [options.dot](#options-dot) -* [options.failglob](#options-failglob) -* [options.ignore](#options-ignore) -* [options.matchBase](#options-matchBase) -* [options.nobrace](#options-nobrace) -* [options.nocase](#options-nocase) -* [options.nodupes](#options-nodupes) -* [options.nonull](#options-nonull) -* [options.nullglob](#options-nullglob) -* [options.snapdragon](#options-snapdragon) -* [options.unescape](#options-unescape) -* [options.unixify](#options-unixify) +* [basename](#options-basename) +* [bash](#options-bash) +* [cache](#options-cache) +* [dot](#options-dot) +* [failglob](#options-failglob) +* [ignore](#options-ignore) +* [matchBase](#options-matchBase) +* [nobrace](#options-nobrace) +* [nocase](#options-nocase) +* [nodupes](#options-nodupes) +* [noext](#options-noext) +* [noglobstar](#options-noglobstar) +* [nonull](#options-nonull) +* [nullglob](#options-nullglob) +* [snapdragon](#options-snapdragon) +* [sourcemap](#options-sourcemap) +* [unescape](#options-unescape) +* [unixify](#options-unixify) ### options.basename Allow glob patterns without slashes to match a file path based on its basename. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `matchBase`. -Type: `Boolean` +**Type**: `Boolean` -Default: `false` +**Default**: `false` **Example** @@ -512,37 +607,55 @@ mm(['a/b.js', 'a/c.md'], '*.js', {matchBase: true}); //=> ['a/b.js'] ``` +### options.bash + +Enabled by default, this option enforces bash-like behavior with stars immediately following a bracket expression. Bash bracket expressions are similar to regex character classes, but unlike regex, a star following a bracket expression **does not repeat the bracketed characters**. Instead, the star is treated the same as an other star. + +**Type**: `Boolean` + +**Default**: `true` + +**Example** + +```js +var files = ['abc', 'ajz']; +console.log(mm(files, '[a-c]*')); +//=> ['abc', 'ajz'] + +console.log(mm(files, '[a-c]*', {bash: false})); +``` + ### options.cache Disable regex and function memoization. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` ### options.dot Match dotfiles. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `dot`. -Type: `Boolean` +**Type**: `Boolean` -Default: `false` +**Default**: `false` ### options.failglob Similar to the `--failglob` behavior in Bash, throws an error when no matches are found. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` ### options.ignore String or array of glob patterns to match files to ignore. -Type: `String|Array` +**Type**: `String|Array` -Default: `undefined` +**Default**: `undefined` ### options.matchBase @@ -552,9 +665,9 @@ Alias for [options.basename](#options-basename). Disable expansion of brace patterns. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `nobrace`. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` See [braces](https://github.com/jonschlinkert/braces) for more information about extended brace expansion. @@ -562,17 +675,17 @@ See [braces](https://github.com/jonschlinkert/braces) for more information about Use a case-insensitive regex for matching files. Same behavior as [minimatch](https://github.com/isaacs/minimatch). -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` ### options.nodupes Remove duplicate elements from the result array. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` **Example** @@ -586,13 +699,47 @@ mm.match(['a/b/c', 'a/b/c'], 'a/b/c', {nodupes: true}); //=> ['abc'] ``` +### options.noext + +Disable extglob support, so that extglobs are regarded as literal characters. + +**Type**: `Boolean` + +**Default**: `undefined` + +**Examples** + +```js +mm(['a/z', 'a/b', 'a/!(z)'], 'a/!(z)'); +//=> ['a/b', 'a/!(z)'] + +mm(['a/z', 'a/b', 'a/!(z)'], 'a/!(z)', {noext: true}); +//=> ['a/!(z)'] (matches only as literal characters) +``` + ### options.nonegate Disallow negation (`!`) patterns, and treat leading `!` as a literal character to match. -Type: `Boolean` +**Type**: `Boolean` + +**Default**: `undefined` + +### options.noglobstar -Default: `undefined` +Disable matching with globstars (`**`). + +**Type**: `Boolean` + +**Default**: `undefined` + +```js +mm(['a/b', 'a/b/c', 'a/b/c/d'], 'a/**'); +//=> ['a/b', 'a/b/c', 'a/b/c/d'] + +mm(['a/b', 'a/b/c', 'a/b/c/d'], 'a/**', {noglobstar: true}); +//=> ['a/b'] +``` ### options.nonull @@ -602,25 +749,64 @@ Alias for [options.nullglob](#options-nullglob). If `true`, when no matches are found the actual (arrayified) glob pattern is returned instead of an empty array. Same behavior as [minimatch](https://github.com/isaacs/minimatch) option `nonull`. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` ### options.snapdragon Pass your own instance of [snapdragon](https://github.com/jonschlinkert/snapdragon), to customize parsers or compilers. -Type: `Object` +**Type**: `Object` + +**Default**: `undefined` + +### options.sourcemap + +Generate a source map by enabling the `sourcemap` option with the `.parse`, `.compile`, or `.create` methods. + +_(Note that sourcemaps are currently not enabled for brace patterns)_ -Default: `undefined` +**Examples** + +``` js +var mm = require('micromatch'); +var pattern = '*(*(of*(a)x)z)'; + +var res = mm.create('abc/*.js', {sourcemap: true}); +console.log(res.map); +// { version: 3, +// sources: [ 'string' ], +// names: [], +// mappings: 'AAAA,GAAG,EAAC,iBAAC,EAAC,EAAE', +// sourcesContent: [ 'abc/*.js' ] } + +var ast = mm.parse('abc/**/*.js'); +var res = mm.compile(ast, {sourcemap: true}); +console.log(res.map); +// { version: 3, +// sources: [ 'string' ], +// names: [], +// mappings: 'AAAA,GAAG,EAAC,2BAAE,EAAC,iBAAC,EAAC,EAAE', +// sourcesContent: [ 'abc/**/*.js' ] } + +var ast = mm.parse(pattern); +var res = mm.compile(ast, {sourcemap: true}); +console.log(res.map); +// { version: 3, +// sources: [ 'string' ], +// names: [], +// mappings: 'AAAA,CAAE,CAAE,EAAE,CAAE,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC', +// sourcesContent: [ '*(*(of*(a)x)z)' ] } +``` ### options.unescape Remove backslashes from returned matches. -Type: `Boolean` +**Type**: `Boolean` -Default: `undefined` +**Default**: `undefined` **Example** @@ -638,9 +824,9 @@ mm.match(['abc', 'a\\*c'], 'a\\*c', {unescape: true}); Convert path separators on returned files to posix/unix-style forward slashes. -Type: `Boolean` +**Type**: `Boolean` -Default: `true` +**Default**: `true` on windows, `false` everywhere else **Example** @@ -662,18 +848,16 @@ Extended globbing, as described by the bash man page: | **pattern** | **regex equivalent** | **description** | | --- | --- | --- | -| `?(pattern-list)` | `(... | ...)?` | Matches zero or one occurrence of the given patterns | -| `*(pattern-list)` | `(... | ...)*` | Matches zero or more occurrences of the given patterns | -| `+(pattern-list)` | `(... | ...)+` | Matches one or more occurrences of the given patterns | -| `@(pattern-list)` | `(... | ...)` * | Matches one of the given patterns | -| `!(pattern-list)` | N/A | Matches anything except one of the given patterns | +| `?(pattern-list)` | `(foo | bar)?` | Matches zero or one occurrence of the given patterns | +| `*(pattern-list)` | `(foo | bar)*` | Matches zero or more occurrences of the given patterns | +| `+(pattern-list)` | `(foo | bar)+` | Matches one or more occurrences of the given patterns | +| `@(pattern-list)` | `(foo | bar)` * | Matches one of the given patterns | +| `!(pattern-list)` | N/A (equivalent regex is much more complicated) | Matches anything except one of the given patterns | -* `@` isn't a RegEx character. +* Note that `@` isn't a RegEx character. Powered by [extglob](https://github.com/jonschlinkert/extglob). Visit that library for the full range of options or to report extglob related issues. -See [extglob](https://github.com/jonschlinkert/extglob) for more information about extended globs. - ### braces **Expanded braces** @@ -687,7 +871,7 @@ Braces are expanded when `` By default, brace patterns work the same way regex logical `OR` operators. For example, `(a|b)` will achieve the same result as `{a,b}`. -Visit [braces](https://github.com/jonschlinkert/braces) to ask questions and create an issue related to brace-expansion, or to see the full range of features and options related to brace expansion. +Visit [braces](https://github.com/jonschlinkert/braces) to see the full range of features and options related to brace expansion, or to create brace matching or expansion related issues. ### regex character classes @@ -708,15 +892,20 @@ Given `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: * `(b|d).js`: would match either `b` or `d`, returning `['b.js', 'd.js']` * `(b|[A-Z]).js`: would match either `b` or an uppercase letter, returning `['b.js', 'E.js']` -As with regex, parenthese can be nested, so patterns like `((a|b)|c)/b` will work. But it might be easier to achieve your goal using brace expansion. +As with regex, parens can be nested, so patterns like `((a|b)|c)/b` will work. Although brace expansion might be friendlier to use, depending on preference. ### POSIX bracket expressions +POSIX brackets are intended to be more user-friendly than regex character classes. This of course is in the eye of the beholder. + **Example** ```js mm.isMatch('a1', '[[:alpha:][:digit:]]'); //=> true + +mm.isMatch('a1', '[[:alpha:][:alpha:]]'); +//=> false ``` See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more information about bracket expressions. @@ -725,17 +914,41 @@ See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more ## Notes -**Bash 4.3 parity** +### Bash 4.3 parity + +Whenever possible matching behavior is based on behavior Bash 4.3, which is mostly consistent with minimatch. + +However, it's suprising how many edge cases and rabbit holes there are with glob matching, and since there is no real glob specification, and micromatch is more accurate than both Bash and minimatch, there are cases where best-guesses were made for behavior. In a few cases where Bash had no answers, we used wildmatch (used by git) as a fallback. + +### Backslashes + +There is an important, notable difference between minimatch and micromatch _in regards to how backslashes are handled_ in glob patterns. + +* Micromatch exclusively and explicitly reserves backslashes for escaping characters in a glob pattern, even on windows. This is consistent with bash behavior. +* Minimatch converts all backslashes to forward slashes, which means you can't use backslashes to escape any characters in your glob patterns. + +We made this decision for micromatch for a couple of reasons: -Whenever possible parsing behavior for patterns is based on globbing specifications in Bash 4.3, which is mostly also constistent with minimatch. Patterns that aren't described in enough detail by the Bash spec follow wildmatch spec (used by git). +* consistency with bash conventions. +* glob patterns are not filepaths. They are a type of [regular language](https://en.wikipedia.org/wiki/Regular_language) that is converted to a JavaScript regular expression. Thus, when forward slashes are defined in a glob pattern, the resulting regular expression will match windows or POSIX path separators just fine. -**Escaping** +**A note about joining paths to globs** -Backslashes are exclusively and explicitly reserved for escaping characters in a glob pattern, even on windows. This is the convention in all globbing libs, including minimatch and node-glob, although some users are [confused about how this works](https://github.com/isaacs/node-glob/issues/212). +Note that when you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting it to still work as a glob pattern. This causes problems on windows, since the `path.sep` is `\\`. -To be clear, _a glob pattern is not a filepath_, it's a [regular language](https://en.wikipedia.org/wiki/Regular_language) that is converted to a JavaScript regular expression. When you pass something like `path.join('foo', '*')` to micromatch, you are creating a filepath and expecting it to still work as a glob pattern. This causes problems on windows, since the node.js `path` module converts `/` to `\\` and/or uses `\\` as the path separator when joining paths. Since `\\` is an escape character in globs, on windows `path.join('foo', '*')` would result in `foo\\*`, which tells micromatch to match `*` as a literal character. +In other words, since `\\` is reserved as an escape character in globs, on windows `path.join('foo', '*')` would result in `foo\\*`, which tells micromatch to match `*` as a literal character. This is the same behavior as bash. -To get around this, you can either do the joining manually or find a lib on npm that does this. +## Contributing + +All contributions are welcome! Please read [the contributing guide](.github/contributing.md) to get started. + +**A special note about bug reports** + +Please feel free to create an issue if you find something that you think isn't right. However, especially (but not exclusively) if you find a matching-related issue, please please try do the following first: + +* research existing issues first +* visit the [GNU Bash documentation](https://www.gnu.org/software/bash/manual/) to see how Bash deals with the pattern +* visit the [minimatch](https://github.com/isaacs/minimatch) documentation to cross-check expected behavior ## Benchmarks @@ -749,7 +962,7 @@ npm i -d && npm benchmark ### Latest results -As of December 13, 2016 (longer bars are better): +As of May 28, 2017 (longer bars are better): ```sh # braces-globstar-large-list @@ -801,13 +1014,14 @@ multimatch █████████████████████ (3,39 micromatch ██████████████████████████████████████████████████████████████████████ (9,578 ops/sec) minimatch ████████████████████ (2,865 ops/sec) multimatch ████████████████████ (2,873 ops/sec) + ``` ## About ### Related projects -* [braces](https://www.npmjs.com/package/braces): Fast, comprehensive, bash-like brace expansion implemented in JavaScript. Complete support for the Bash 4.3 braces… [more](https://github.com/jonschlinkert/braces) | [homepage](https://github.com/jonschlinkert/braces "Fast, comprehensive, bash-like brace expansion implemented in JavaScript. Complete support for the Bash 4.3 braces specification, without sacrificing speed.") +* [braces](https://www.npmjs.com/package/braces): Bash-like brace expansion, implemented in JavaScript. Safer than other brace expansion libs, with complete support… [more](https://github.com/micromatch/braces) | [homepage](https://github.com/micromatch/braces "Bash-like brace expansion, implemented in JavaScript. Safer than other brace expansion libs, with complete support for the Bash 4.3 braces specification, without sacrificing speed.") * [expand-brackets](https://www.npmjs.com/package/expand-brackets): Expand POSIX bracket expressions (character classes) in glob patterns. | [homepage](https://github.com/jonschlinkert/expand-brackets "Expand POSIX bracket expressions (character classes) in glob patterns.") * [extglob](https://www.npmjs.com/package/extglob): Extended glob support for JavaScript. Adds (almost) the expressive power of regular expressions to glob… [more](https://github.com/jonschlinkert/extglob) | [homepage](https://github.com/jonschlinkert/extglob "Extended glob support for JavaScript. Adds (almost) the expressive power of regular expressions to glob patterns.") * [fill-range](https://www.npmjs.com/package/fill-range): Fill in a range of numbers or letters, optionally passing an increment or `step` to… [more](https://github.com/jonschlinkert/fill-range) | [homepage](https://github.com/jonschlinkert/fill-range "Fill in a range of numbers or letters, optionally passing an increment or `step` to use, or create a regex-compatible range with `options.toRegex`") @@ -817,13 +1031,13 @@ multimatch ████████████████████ (2,873 o Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). -Please read the [contributing guide](.github/contributing.md) for avice on opening issues, pull requests, and coding standards. +Please read the [contributing guide](.github/contributing.md) for advice on opening issues, pull requests, and coding standards. ### Contributors -| **Commits** | **Contributor**
| -| --- | --- | --- | --- | --- | -| 345 | [jonschlinkert](https://github.com/jonschlinkert) | +| **Commits** | **Contributor** | +| --- | --- | +| 346 | [jonschlinkert](https://github.com/jonschlinkert) | | 12 | [es128](https://github.com/es128) | | 3 | [paulmillr](https://github.com/paulmillr) | | 2 | [TrySound](https://github.com/TrySound) | @@ -831,25 +1045,26 @@ Please read the [contributing guide](.github/contributing.md) for avice on openi | 2 | [MartinKolarik](https://github.com/MartinKolarik) | | 2 | [tunnckoCore](https://github.com/tunnckoCore) | | 1 | [amilajack](https://github.com/amilajack) | +| 1 | [DianeLooney](https://github.com/DianeLooney) | | 1 | [UltCombo](https://github.com/UltCombo) | | 1 | [tomByrer](https://github.com/tomByrer) | ### Building docs -_(This document was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme) (a [verb](https://github.com/verbose/verb) generator), please don't edit the readme directly. Any changes to the readme must be made in [.verb.md](.verb.md).)_ +_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_ -To generate the readme and API documentation with [verb](https://github.com/verbose/verb): +To generate the readme, run the following command: ```sh -$ npm install -g verb verb-generate-readme && verb +$ npm install -g verbose/verb#dev verb-generate-readme && verb ``` ### Running tests -Install dev dependencies: +Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command: ```sh -$ npm install -d && npm test +$ npm install && npm test ``` ### Author @@ -857,13 +1072,13 @@ $ npm install -d && npm test **Jon Schlinkert** * [github/jonschlinkert](https://github.com/jonschlinkert) -* [twitter/jonschlinkert](http://twitter.com/jonschlinkert) +* [twitter/jonschlinkert](https://twitter.com/jonschlinkert) ### License -Copyright © 2016, [Jon Schlinkert](https://github.com/jonschlinkert). -Released under the [MIT license](https://github.com/jonschlinkert/micromatch/blob/master/LICENSE). +Copyright © 2017, [Jon Schlinkert](https://github.com/jonschlinkert). +Released under the [MIT License](LICENSE). *** -_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.0, on December 13, 2016._ \ No newline at end of file +_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on May 28, 2017._ \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 3b8ac52c..ad16679b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,8 +4,8 @@ environment: # node.js - nodejs_version: "7.0" - nodejs_version: "6.0" - - nodejs_version: "4.0" - nodejs_version: "5.0" + - nodejs_version: "4.0" - nodejs_version: "0.12" - nodejs_version: "0.10" diff --git a/docs/minimatch.md b/docs/minimatch.md deleted file mode 100644 index d568279c..00000000 --- a/docs/minimatch.md +++ /dev/null @@ -1,214 +0,0 @@ -# Comparison: micromatch vs. minimatch - -> This document is based on the readme from [minimatch], with additions to show how the two libraries, minimatch and micromatch, compare to one another. - -**Matching with RegExp** - -Both libraries work by converting glob expressions into JavaScript `RegExp` objects. However, there are key differences in approach. - -**Parse > Tokenize > Convert to regex** - -For the most part, both libraries follow this formula. - -- glob pattern is parsed into tokens -- if applicable, pattern is expanded to multiple patterns, as with brace patterns (`/{a,b}/*.js`) - - -**Major implementation differences** - -Micromatch's huge speed advantage comes from a few different areas: - -- basic caching -- tokenization strategy -- regex optimizations -- single responsibility functions - - -**Example compiled regex** - -```js -micro.makeRe('*.{yml,json}'); -//=> /^(?:(?!\.)(?=.)[^/]*?\.(yml|json))$/ - -mini.makeRe('*.{yml,json}'); -//=> /^(?:(?!\.)(?=.)[^/]*?\.yml|(?!\.)(?=.)[^/]*?\.json)$/ -``` - - -## Usage - -```js -var minimatch = require("minimatch"); -var micromatch = require('micromatch'); -``` - -**Minimatch** - -Match the path on the left against the pattern on the right: - -```js -minimatch("foo.js", "*.js"); // true! -``` - -**Micromatch** - -The micromatch equivalent is `micromatch.isMatch()` - - -```js -minimatch.isMatch('foo.js', '*.js'); // true! -``` - - -## Features - -Both libraries support these glob features: - -* Brace Expansion -* Extended glob matching -* "Globstar" `**` matching - - -## Constructor - -**Minimatch Class** - -Create a minimatch object by instanting the `minimatch.Minimatch` class. - -```js -var Minimatch = require("minimatch").Minimatch; -var mm = new Minimatch(pattern, options); -``` - -**Micromatch** - -No support. If you need access to tokens as they are generated (to avoid parsing the glob more than once), you can use `micromatch.expand()`. - - -## Functions - -### minimatch(path, pattern, options) - -Main export. Tests a path against the pattern using the options. - -```js -var isJS = minimatch(file, "*.js", { matchBase: true }) -``` - -### minimatch.filter(pattern, options) - -Returns a function that tests its -supplied argument, suitable for use with `Array.filter`. Example: - -```js -var javascripts = fileList.filter(minimatch.filter("*.js", {matchBase: true})) -``` - -### minimatch.match(list, pattern, options) - -Match against the list of -files, in the style of fnmatch or glob. If nothing is matched, and -options.nonull is set, then return a list containing the pattern itself. - -```js -var javascripts = minimatch.match(fileList, "*.js", {matchBase: true})) -``` - -### minimatch.makeRe(pattern, options) - -Make a regular expression object from the pattern. - -## Options - -All options are `false` by default. - -### debug - -Dump a ton of stuff to stderr. - -### nobrace - -Do not expand `{a,b}` and `{1..3}` brace sets. - -### noglobstar - -Disable `**` matching against multiple folder names. - -### dot - -Allow patterns to match filenames starting with a period, even if -the pattern does not explicitly have a period in that spot. - -Note that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot` -is set. - -### noext - -Disable "extglob" style patterns like `+(a|b)`. - -### nocase - -Perform a case-insensitive match. - -### nonull - -When a match is not found by `minimatch.match`, return a list containing -the pattern itself if this option is set. When not set, an empty list -is returned if there are no matches. - -### matchBase - -If set, then patterns without slashes will be matched -against the basename of the path if it contains slashes. For example, -`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`. - -### nocomment - -Suppress the behavior of treating `#` at the start of a pattern as a -comment. - -### nonegate - -Suppress the behavior of treating a leading `!` character as negation. - -### flipNegate - -Returns from negate expressions the same as if they were not negated. -(Ie, true on a hit, false on a miss.) - - -## Comparisons to other fnmatch/glob implementations - -While strict compliance with the existing standards is a worthwhile -goal, some discrepancies exist between minimatch and other -implementations, and are intentional. - -If the pattern starts with a `!` character, then it is negated. Set the -`nonegate` flag to suppress this behavior, and treat leading `!` -characters normally. This is perhaps relevant if you wish to start the -pattern with a negative extglob pattern like `!(a|B)`. Multiple `!` -characters at the start of a pattern will negate the pattern multiple -times. - -If a pattern starts with `#`, then it is treated as a comment, and -will not match anything. Use `\#` to match a literal `#` at the -start of a line, or set the `nocomment` flag to suppress this behavior. - -The double-star character `**` is supported by default, unless the -`noglobstar` flag is set. This is supported in the manner of bsdglob -and bash 4.1, where `**` only has special significance if it is the only -thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but -`a/**b` will not. - -If an escaped pattern has no matches, and the `nonull` flag is set, -then minimatch.match returns the pattern as-provided, rather than -interpreting the character escapes. For example, -`minimatch.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than -`"*a?"`. This is akin to setting the `nullglob` option in bash, except -that it does not resolve escaped pattern characters. - -If brace expansion is not disabled, then it is performed before any -other interpretation of the glob pattern. Thus, a pattern like -`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded -**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are -checked for validity. Since those two are valid, matching proceeds. diff --git a/docs/switching-from-minimatch.md b/docs/switching-from-minimatch.md deleted file mode 100644 index bd7cec44..00000000 --- a/docs/switching-from-minimatch.md +++ /dev/null @@ -1,28 +0,0 @@ -# Switching from minimatch - -> Use `mm.isMatch()` instead of `minimatch()` - -**Minimatch** - -The main `minimatch()` function returns true/false for a single file path and pattern: - -```js -var minimatch = require('minimatch'); -minimatch('foo.js', '*.js'); -//=> 'true' -``` - -**Micromatch** - -With micromatch, `.isMatch()` to get the same result: - -```js -var mm = require('micromatch'); -mm.isMatch('foo.js', '*.js'); -//=> 'true' -``` - -This implementation difference is necessary since the main `micromatch()` method supports matching on multiple globs, with behavior similar to [multimatch][]. - -[multimatch]: https://github.com/sindresorhus/multimatch -[minimatch]: https://github.com/isaacs/minimatch From c013ef98f456b9dca5e81234d4c4f11edc79d6b1 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Sun, 28 May 2017 20:33:36 -0400 Subject: [PATCH 64/68] fix grammar --- .verb.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.verb.md b/.verb.md index 88d4fd9d..f27086bd 100644 --- a/.verb.md +++ b/.verb.md @@ -484,9 +484,9 @@ In other words, since `\\` is reserved as an escape character in globs, on windo All contributions are welcome! Please read [the contributing guide](.github/contributing.md) to get started. -**A special note about bug reports** +**Bug reports** -Please feel free to create an issue if you find something that you think isn't right. However, especially (but not exclusively) if you find a matching-related issue, please please try do the following first: +Please feel free to create an issue if you find something that you think isn't right. However, if you find a matching-related issue, please try do the following first: - research existing issues first - visit the [GNU Bash documentation](https://www.gnu.org/software/bash/manual/) to see how Bash deals with the pattern From 8d217f5b9d04bb1370097e9c2588b03a295e4d05 Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Sun, 28 May 2017 20:33:52 -0400 Subject: [PATCH 65/68] update benchmarks --- benchmark/last.md | 64 +++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/benchmark/last.md b/benchmark/last.md index 0d5c4b5d..ca7368bb 100644 --- a/benchmark/last.md +++ b/benchmark/last.md @@ -1,4 +1,4 @@ -enchmarking: (10 of 10) +Benchmarking: (10 of 10) · braces-globstar-large-list · braces-multiple · braces-range @@ -11,71 +11,71 @@ enchmarking: (10 of 10) · star # benchmark/fixtures/match/braces-globstar-large-list.js (485691 bytes) - micromatch x 413 ops/sec ±1.10% (82 runs sampled) - minimatch x 13.20 ops/sec ±2.02% (36 runs sampled) - multimatch x 12.47 ops/sec ±2.24% (36 runs sampled) + micromatch x 595 ops/sec ±0.42% (89 runs sampled) + minimatch x 13.95 ops/sec ±1.04% (37 runs sampled) + multimatch x 14.09 ops/sec ±0.63% (37 runs sampled) fastest is micromatch -# benchmark/fixtures/match/braces-multiple.js (3143 bytes) - micromatch x 36,121 ops/sec ±1.96% (82 runs sampled) - minimatch x 1.59 ops/sec ±3.57% (7 runs sampled) - multimatch x 1.46 ops/sec ±2.41% (7 runs sampled) +# benchmark/fixtures/match/braces-multiple.js (3362 bytes) + micromatch x 48,362 ops/sec ±0.63% (84 runs sampled) + minimatch x 2.18 ops/sec ±1.95% (9 runs sampled) + multimatch x 2.15 ops/sec ±3.75% (9 runs sampled) fastest is micromatch # benchmark/fixtures/match/braces-range.js (727 bytes) - micromatch x 210,437 ops/sec ±1.31% (81 runs sampled) - minimatch x 8,559 ops/sec ±1.33% (85 runs sampled) - multimatch x 8,342 ops/sec ±2.42% (84 runs sampled) + micromatch x 187,481 ops/sec ±0.84% (88 runs sampled) + minimatch x 12,366 ops/sec ±1.45% (88 runs sampled) + multimatch x 11,841 ops/sec ±1.04% (92 runs sampled) fastest is micromatch # benchmark/fixtures/match/braces-set.js (2858 bytes) - micromatch x 25,350 ops/sec ±1.68% (82 runs sampled) - minimatch x 2,067 ops/sec ±1.54% (84 runs sampled) - multimatch x 1,815 ops/sec ±1.69% (83 runs sampled) + micromatch x 24,344 ops/sec ±1.07% (90 runs sampled) + minimatch x 2,255 ops/sec ±1.30% (88 runs sampled) + multimatch x 2,199 ops/sec ±0.40% (92 runs sampled) fastest is micromatch # benchmark/fixtures/match/globstar-large-list.js (485686 bytes) - micromatch x 399 ops/sec ±1.36% (82 runs sampled) - minimatch x 23.99 ops/sec ±2.16% (43 runs sampled) - multimatch x 25.91 ops/sec ±1.89% (43 runs sampled) + micromatch x 561 ops/sec ±0.37% (85 runs sampled) + minimatch x 25.43 ops/sec ±0.55% (44 runs sampled) + multimatch x 25.27 ops/sec ±0.37% (44 runs sampled) fastest is micromatch # benchmark/fixtures/match/globstar-long-list.js (90647 bytes) - micromatch x 3,639 ops/sec ±1.45% (83 runs sampled) - minimatch x 504 ops/sec ±1.78% (83 runs sampled) - multimatch x 539 ops/sec ±1.68% (81 runs sampled) + micromatch x 3,257 ops/sec ±0.53% (89 runs sampled) + minimatch x 485 ops/sec ±1.01% (89 runs sampled) + multimatch x 485 ops/sec ±0.41% (89 runs sampled) fastest is micromatch # benchmark/fixtures/match/globstar-short-list.js (182 bytes) - micromatch x 436,248 ops/sec ±1.66% (84 runs sampled) - minimatch x 30,473 ops/sec ±1.54% (85 runs sampled) - multimatch x 26,826 ops/sec ±1.88% (85 runs sampled) + micromatch x 359,991 ops/sec ±1.04% (88 runs sampled) + minimatch x 44,763 ops/sec ±1.07% (90 runs sampled) + multimatch x 39,977 ops/sec ±0.50% (90 runs sampled) fastest is micromatch # benchmark/fixtures/match/no-glob.js (701 bytes) - micromatch x 625,755 ops/sec ±1.50% (84 runs sampled) - minimatch x 39,617 ops/sec ±1.64% (84 runs sampled) - multimatch x 33,846 ops/sec ±2.06% (81 runs sampled) + micromatch x 443,740 ops/sec ±1.36% (87 runs sampled) + minimatch x 44,152 ops/sec ±1.82% (90 runs sampled) + multimatch x 41,077 ops/sec ±0.45% (90 runs sampled) fastest is micromatch # benchmark/fixtures/match/star-basename.js (12339 bytes) - micromatch x 11,281 ops/sec ±1.55% (82 runs sampled) - minimatch x 3,028 ops/sec ±1.61% (83 runs sampled) - multimatch x 3,395 ops/sec ±1.74% (81 runs sampled) + micromatch x 10,286 ops/sec ±0.46% (92 runs sampled) + minimatch x 3,059 ops/sec ±0.37% (90 runs sampled) + multimatch x 3,129 ops/sec ±1.36% (90 runs sampled) fastest is micromatch # benchmark/fixtures/match/star.js (12338 bytes) - micromatch x 9,578 ops/sec ±1.31% (83 runs sampled) - minimatch x 2,865 ops/sec ±2.12% (84 runs sampled) - multimatch x 2,873 ops/sec ±2.06% (83 runs sampled) + micromatch x 9,756 ops/sec ±0.81% (88 runs sampled) + minimatch x 2,978 ops/sec ±0.38% (90 runs sampled) + multimatch x 2,970 ops/sec ±1.22% (91 runs sampled) fastest is micromatch From 0f6565145d885b91efcc70917626ca608c0c45bf Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 29 May 2017 02:09:18 -0400 Subject: [PATCH 66/68] lint --- index.js | 34 ++++++---------------- lib/compilers.js | 12 +------- lib/parsers.js | 5 +--- lib/utils.js | 73 ++++++------------------------------------------ package.json | 8 ++++-- 5 files changed, 24 insertions(+), 108 deletions(-) diff --git a/index.js b/index.js index 6c9d8a89..9f0acacf 100644 --- a/index.js +++ b/index.js @@ -184,7 +184,7 @@ micromatch.isMatch = function(str, pattern, options) { }; /** - * Returns true if some of the elements in the given `list` match any of the + * Returns true if some of the strings in the given `list` match any of the * given glob `patterns`. * * ```js @@ -207,19 +207,17 @@ micromatch.some = function(list, patterns, options) { if (typeof list === 'string') { list = [list]; } - for (var i = 0; i < list.length; i++) { if (micromatch(list[i], patterns, options).length === 1) { return true; } } - return false; }; /** - * Returns true if every element in the given `list` matches - * at least one of the given glob `patterns`. + * Returns true if every string in the given `list` matches + * any of the given glob `patterns`. * * ```js * var mm = require('micromatch'); @@ -245,13 +243,11 @@ micromatch.every = function(list, patterns, options) { if (typeof list === 'string') { list = [list]; } - for (var i = 0; i < list.length; i++) { if (micromatch(list[i], patterns, options).length !== 1) { return false; } } - return true; }; @@ -297,8 +293,8 @@ micromatch.any = function(str, patterns, options) { }; /** - * Returns true if **all** of the given `patterns` - * match the specified string. + * Returns true if **all** of the given `patterns` match + * the specified string. * * ```js * var mm = require('micromatch'); @@ -327,11 +323,9 @@ micromatch.all = function(str, patterns, options) { if (typeof str !== 'string') { throw new TypeError('expected a string: "' + util.inspect(str) + '"'); } - if (typeof patterns === 'string') { patterns = [patterns]; } - for (var i = 0; i < patterns.length; i++) { if (!micromatch.isMatch(str, patterns[i], options)) { return false; @@ -478,12 +472,6 @@ micromatch.matchKeys = function(obj, patterns, options) { */ micromatch.matcher = function matcher(pattern, options) { - if (isEmptyString(pattern)) { - return function() { - return false; - } - } - if (Array.isArray(pattern)) { return compose(pattern, options, matcher); } @@ -552,10 +540,6 @@ micromatch.matcher = function matcher(pattern, options) { */ micromatch.makeRe = function(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } - if (typeof pattern !== 'string') { throw new TypeError('expected pattern to be a string'); } @@ -763,11 +747,11 @@ micromatch.parse = function(pattern, options) { */ micromatch.compile = function(ast, options) { - return memoize('compile', ast.input, options, function() { - if (typeof ast === 'string') { - ast = micromatch.parse(ast, options); - } + if (typeof ast === 'string') { + ast = micromatch.parse(ast, options); + } + return memoize('compile', ast.input, options, function() { var snapdragon = utils.instantiate(ast, options); compilers(snapdragon, options); return snapdragon.compile(ast, options); diff --git a/lib/compilers.js b/lib/compilers.js index 016a330e..d39f27dd 100644 --- a/lib/compilers.js +++ b/lib/compilers.js @@ -7,8 +7,6 @@ module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; var opts = snapdragon.options; - snapdragon.state = snapdragon.state || {}; - // register nanomatch compilers snapdragon.use(nanomatch.compilers); @@ -46,15 +44,7 @@ module.exports = function(snapdragon) { .set('slash', slash) .set('qmark', qmark) .set('star', star) - .set('text', text) - - // customize end-of-string compiler - .set('eos', function(node) { - if (typeof eos === 'function') { - return eos.apply(this, arguments); - } - return this.emit(node.val, node); - }); + .set('text', text); }; function escapeExtglobs(compiler) { diff --git a/lib/parsers.js b/lib/parsers.js index 7edfa65e..f80498ce 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -4,7 +4,6 @@ var extglob = require('extglob'); var nanomatch = require('nanomatch'); var regexNot = require('regex-not'); var toRegex = require('to-regex'); -var cached; var not; /** @@ -78,9 +77,7 @@ module.exports = function(snapdragon) { */ function textRegex(pattern) { - if (cached) return cached; var notStr = regexNot.create(pattern, {contains: true, strictClose: false}); var prefix = '(?:[\\^]|\\\\|'; - var re = toRegex(prefix + notStr + ')', {strictClose: false}); - return (cached = re); + return toRegex(prefix + notStr + ')', {strictClose: false}); } diff --git a/lib/utils.js b/lib/utils.js index 962523be..0dc0982e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -26,14 +26,6 @@ utils.isWindows = function() { return path.sep === '\\' || process.platform === 'win32'; }; -/** - * Return the last element from an array - */ - -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - /** * Get the `Snapdragon` instance to use */ @@ -92,13 +84,13 @@ utils.createKey = function(pattern, options) { if (typeof options === 'undefined') { return pattern; } - var key = pattern; - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - key += ';' + prop + '=' + String(options[prop]); - } + var val = pattern; + var keys = Object.keys(options); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + val += ';' + key + '=' + String(options[key]); } - return key; + return val; }; /** @@ -119,14 +111,6 @@ utils.isString = function(val) { return typeof val === 'string'; }; -/** - * Return true if `val` is a non-empty string - */ - -utils.isRegex = function(val) { - return utils.typeOf(val) === 'regexp'; -}; - /** * Return true if `val` is a non-empty string */ @@ -135,14 +119,6 @@ utils.isObject = function(val) { return utils.typeOf(val) === 'object'; }; -/** - * Escape regex characters in the given string - */ - -utils.escapeRegex = function(str) { - return str.replace(/[-[\]{}()^$|*+?.\\\/\s]/g, '\\$&'); -}; - /** * Combines duplicate characters in the provided string. * @param {String} `str` @@ -150,11 +126,8 @@ utils.escapeRegex = function(str) { */ utils.combineDuplicates = function(str, val) { - if (typeof val === 'string') { - var re = new RegExp('(' + val + ')(?=(?:' + val + ')*\\1)', 'g'); - return str.replace(re, ''); - } - return str.replace(/(.)(?=.*\1)/g, ''); + var re = new RegExp('(' + val + ')(?=(?:' + val + ')*\\1)', 'g'); + return str.replace(re, ''); }; /** @@ -187,16 +160,6 @@ utils.unescape = function(str) { return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); }; -/** - * Strip the drive letter from a windows filepath - * @param {String} `fp` - * @return {String} - */ - -utils.stripDrive = function(fp) { - return utils.isWindows() ? fp.replace(/^[a-z]:[\\\/]+?/i, '/') : fp; -}; - /** * Strip the prefix from a filepath * @param {String} `fp` @@ -214,17 +177,6 @@ utils.stripPrefix = function(str) { return str; }; -/** - * Returns true if `str` is a common character that doesn't need - * to be processed to be used for matching. - * @param {String} `str` - * @return {Boolean} - */ - -utils.isSimpleChar = function(str) { - return str === '' || str === ' ' || str === '.'; -}; - /** * Returns true if the given str is an escaped or * unescaped path character @@ -324,15 +276,6 @@ utils.matchBasename = function(re) { }; }; -/** - * Returns the given value unchanced. - * @return {any} - */ - -utils.identity = function(val) { - return val; -}; - /** * Determines the filepath to return based on the provided options. * @return {any} diff --git a/package.json b/package.json index 7ea50928..4c78130a 100644 --- a/package.json +++ b/package.json @@ -104,14 +104,14 @@ ] }, "files": [ - "gulpfile.js", "examples/*.js", + "gulpfile.js", "test/**/*.js" ] } }, "verb": { - "toc": true, + "toc": "collapsible", "layout": "default", "tasks": [ "readme" @@ -138,7 +138,9 @@ "extglob", "glob-object", "minimatch", - "snapdragon" + "multimatch", + "snapdragon", + "expand-brackets" ] } } From c3bc2099dcd3decc7c339789b41bdf9bcd645c8f Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 29 May 2017 02:09:27 -0400 Subject: [PATCH 67/68] add more unit tests --- test/api.all.js | 27 +++++++++++++++++++++++ test/api.any.js | 8 +++++++ test/api.braceExpand.js | 17 +++++++++++++++ test/api.braces.js | 21 ++++++++++++++++++ test/api.compile.js | 47 +++++++++++++++++++++++++++++++++++++++++ test/api.contains.js | 8 +++++++ test/api.every.js | 21 ++++++++++++++++++ test/api.js | 12 +++++++++++ test/api.makeRe.js | 21 ++++++++++++++++++ test/api.match.js | 11 +++++++++- test/api.matchKeys.js | 2 +- test/api.matcher.js | 19 ++++++++++++++++- test/api.not.js | 2 +- test/api.parse.js | 47 +++++++++++++++++++++++++++++++++++++++++ test/api.some.js | 21 ++++++++++++++++++ 15 files changed, 280 insertions(+), 4 deletions(-) create mode 100644 test/api.all.js create mode 100644 test/api.braceExpand.js create mode 100644 test/api.braces.js create mode 100644 test/api.compile.js create mode 100644 test/api.every.js create mode 100644 test/api.makeRe.js create mode 100644 test/api.parse.js create mode 100644 test/api.some.js diff --git a/test/api.all.js b/test/api.all.js new file mode 100644 index 00000000..3927d802 --- /dev/null +++ b/test/api.all.js @@ -0,0 +1,27 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var mm = require('..'); + +describe('.all()', function() { + it('should throw an error when value is not a string', function() { + assert.throws(function() { + mm.all(); + }); + }); + + it('should return true when all patterns match the given string', function() { + assert(mm.all('z', ['z', '*', '[a-z]'])); + assert(mm.all('b', 'b')); + assert(mm.all('b', '*')); + }); + + it('should return false when some patterns do not match', function() { + assert(!mm.all('a', ['a', 'b', '*'])); + }); + + it('should arrayify a string value', function() { + assert(mm.all('a', ['*'])); + }); +}); diff --git a/test/api.any.js b/test/api.any.js index 204f95e5..185d4d82 100644 --- a/test/api.any.js +++ b/test/api.any.js @@ -5,6 +5,14 @@ var assert = require('assert'); var mm = require('..'); describe('.any()', function() { + describe('errors', function() { + it('should throw an error when value is not a string', function() { + assert.throws(function() { + mm.any(); + }); + }); + }); + describe('empty patterns', function() { it('should correctly handle empty patterns', function() { assert(!mm.any('', '')); diff --git a/test/api.braceExpand.js b/test/api.braceExpand.js new file mode 100644 index 00000000..c57b26fe --- /dev/null +++ b/test/api.braceExpand.js @@ -0,0 +1,17 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var mm = require('..'); + +describe('.braceExpand()', function() { + it('should throw an error when arguments are invalid', function() { + assert.throws(function() { + mm.braceExpand(); + }); + }); + + it('should expand a brace pattern', function() { + assert.deepEqual(mm.braceExpand('{a,b}'), ['a', 'b']); + }); +}); diff --git a/test/api.braces.js b/test/api.braces.js new file mode 100644 index 00000000..1e59577c --- /dev/null +++ b/test/api.braces.js @@ -0,0 +1,21 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var mm = require('..'); + +describe('.braces()', function() { + it('should throw an error when arguments are invalid', function() { + assert.throws(function() { + mm.braces(); + }); + }); + + it('should create a regex source string from a brace pattern', function() { + assert.deepEqual(mm.braces('{a,b}'), ['(a|b)']); + }); + + it('should expand a brace pattern', function() { + assert.deepEqual(mm.braces('{a,b}', {expand: true}), ['a', 'b']); + }); +}); diff --git a/test/api.compile.js b/test/api.compile.js new file mode 100644 index 00000000..665fa7a0 --- /dev/null +++ b/test/api.compile.js @@ -0,0 +1,47 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var mm = require('..'); + +describe('.compile()', function() { + it('should throw an error when arguments are invalid', function() { + assert.throws(function() { + mm.compile(); + }); + }); + + it('should return an AST for a glob', function() { + var foo = mm.compile('a/*'); + delete foo.ast.state; + assert.deepEqual(foo.ast, { + type: 'root', + errors: [], + nodes: [ + { type: 'bos', val: '' }, + { type: 'text', val: 'a' }, + { type: 'slash', val: '/' }, + { type: 'star', val: '*' }, + { type: 'eos', val: '' } + ], + input: 'a/*' + }); + + var bar = mm.compile('a/**/*'); + delete bar.ast.state; + assert.deepEqual(bar.ast, { + type: 'root', + errors: [], + nodes: [ + { type: 'bos', val: '' }, + { type: 'text', val: 'a' }, + { type: 'slash', val: '/' }, + { type: 'globstar', val: '**' }, + { type: 'slash', val: '/' }, + { type: 'star', val: '*' }, + { type: 'eos', val: '' } + ], + input: 'a/**/*' + }); + }); +}); diff --git a/test/api.contains.js b/test/api.contains.js index fb96f90c..f05895a5 100644 --- a/test/api.contains.js +++ b/test/api.contains.js @@ -6,6 +6,14 @@ var assert = require('assert'); var mm = require('..'); describe('.contains()', function() { + describe('errors', function() { + it('should throw an error arguments are invalid', function() { + assert.throws(function() { + mm.contains(); + }); + }); + }); + describe('patterns', function() { it('should correctly deal with empty patterns', function() { assert(!mm.contains('ab', '')); diff --git a/test/api.every.js b/test/api.every.js new file mode 100644 index 00000000..cb7b361e --- /dev/null +++ b/test/api.every.js @@ -0,0 +1,21 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var mm = require('..'); + +describe('.every()', function() { + it('should return true if every string matches', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + assert(mm.every(fixtures, ['z', '*/*'])); + }); + + it('should return false when not all strings match', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + assert(!mm.every(fixtures, ['a/*', 'x/*'])); + }); + + it('should arrayify a string value', function() { + assert(mm.every('a', ['*'])); + }); +}); diff --git a/test/api.js b/test/api.js index b3cfedb1..c8be4501 100644 --- a/test/api.js +++ b/test/api.js @@ -5,6 +5,18 @@ var sep = path.sep; var mm = require('./support/match'); describe('micromatch', function() { + describe('empty list', function() { + it('should return an empty array', function() { + mm([], '*', []); + }); + }); + + describe('options.nodupes', function() { + it('should return an array with duplicates', function() { + mm(['a', 'a', 'a'], ['*', 'a*'], {nodupes: false}, ['a', 'a', 'a', 'a', 'a', 'a']); + }); + }); + describe('posix paths', function() { it('should return an array of matches for a literal string', function() { mm(['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c'], '(a/b)', ['a/b']); diff --git a/test/api.makeRe.js b/test/api.makeRe.js new file mode 100644 index 00000000..891a9655 --- /dev/null +++ b/test/api.makeRe.js @@ -0,0 +1,21 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var mm = require('..'); + +describe('.makeRe()', function() { + it('should throw an error when value is not a string', function() { + assert.throws(function() { + mm.makeRe(); + }); + }); + + it('should create a regex for a glob pattern', function() { + assert(mm.makeRe('*') instanceof RegExp); + }); + + it('should create a regex for a string', function() { + assert.deepEqual(mm.makeRe('abc').source, '^(?:abc)$'); + }); +}); diff --git a/test/api.match.js b/test/api.match.js index f66f3110..404f3258 100644 --- a/test/api.match.js +++ b/test/api.match.js @@ -1,9 +1,18 @@ 'use strict'; var path = require('path'); +var assert = require('assert'); var mm = require('./support/match'); -describe('.match method', function() { +describe('.match()', function() { + describe('errors', function() { + it('should throw an error when pattern is not a string', function() { + assert.throws(function() { + require('../').match([], []); + }); + }); + }); + describe('posix paths', function() { it('should return an array of matches for a literal string', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; diff --git a/test/api.matchKeys.js b/test/api.matchKeys.js index a27c4a74..5c257e60 100644 --- a/test/api.matchKeys.js +++ b/test/api.matchKeys.js @@ -3,7 +3,7 @@ var assert = require('assert'); var mm = require('..'); -describe('.matchKeys method', function() { +describe('.matchKeys()', function() { describe('error handling', function() { it('should throw when the first argument is not an object', function() { assert.throws(function() { diff --git a/test/api.matcher.js b/test/api.matcher.js index 415236b6..429db951 100644 --- a/test/api.matcher.js +++ b/test/api.matcher.js @@ -1,9 +1,26 @@ 'use strict'; var path = require('path'); +var assert = require('assert'); var mm = require('./support/match'); -describe('.match method', function() { +describe('.matcher()', function() { + describe('errors', function() { + it('should throw an error when arguments are invalid', function() { + assert.throws(function() { + mm.matcher(null); + }); + + assert.throws(function() { + mm.matcher(); + }); + + assert.throws(function() { + mm.matcher(function() {}); + }); + }); + }); + describe('posix paths', function() { it('should return an array of matches for a literal string', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; diff --git a/test/api.not.js b/test/api.not.js index c133a1c0..b26fa07e 100644 --- a/test/api.not.js +++ b/test/api.not.js @@ -4,7 +4,7 @@ var path = require('path'); var sep = path.sep; var mm = require('./support/match'); -describe('.not method', function() { +describe('.not()', function() { describe('posix paths', function() { it('should return an array of matches for a literal string', function() { var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; diff --git a/test/api.parse.js b/test/api.parse.js new file mode 100644 index 00000000..12df972d --- /dev/null +++ b/test/api.parse.js @@ -0,0 +1,47 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var mm = require('..'); + +describe('.parse()', function() { + it('should throw an error when arguments are invalid', function() { + assert.throws(function() { + mm.parse(); + }); + }); + + it('should return an AST for a glob', function() { + var ast = mm.parse('a/*'); + delete ast.state; + assert.deepEqual(ast, { + type: 'root', + errors: [], + nodes: [ + { type: 'bos', val: '' }, + { type: 'text', val: 'a' }, + { type: 'slash', val: '/' }, + { type: 'star', val: '*' }, + { type: 'eos', val: '' } + ], + input: 'a/*' + }); + + ast = mm.parse('a/**/*'); + delete ast.state; + assert.deepEqual(ast, { + type: 'root', + errors: [], + nodes: [ + { type: 'bos', val: '' }, + { type: 'text', val: 'a' }, + { type: 'slash', val: '/' }, + { type: 'globstar', val: '**' }, + { type: 'slash', val: '/' }, + { type: 'star', val: '*' }, + { type: 'eos', val: '' } + ], + input: 'a/**/*' + }); + }); +}); diff --git a/test/api.some.js b/test/api.some.js new file mode 100644 index 00000000..7e81561d --- /dev/null +++ b/test/api.some.js @@ -0,0 +1,21 @@ +'use strict'; + +var path = require('path'); +var assert = require('assert'); +var mm = require('..'); + +describe('.some()', function() { + it('should return true if any matches are found', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + assert(mm.some(fixtures, ['z', 'b/*'])); + }); + + it('should return false if no matches are found', function() { + var fixtures = ['a/a', 'a/b', 'a/c', 'b/a', 'b/b', 'b/c']; + assert(!mm.some(fixtures, ['z', 'x/*'])); + }); + + it('should arrayify a string value', function() { + assert(mm.some('a', ['*'])); + }); +}); From 914059ff42485487d101da82c97d661a61cb8a3c Mon Sep 17 00:00:00 2001 From: jonschlinkert Date: Mon, 29 May 2017 02:09:36 -0400 Subject: [PATCH 68/68] run verb to generate readme --- .verb.md | 177 +++++++++++++++++------------------- README.md | 267 ++++++++++++++++++++++++++---------------------------- 2 files changed, 211 insertions(+), 233 deletions(-) diff --git a/.verb.md b/.verb.md index f27086bd..56ae4d85 100644 --- a/.verb.md +++ b/.verb.md @@ -1,5 +1,6 @@ ## Quickstart + ```js var mm = require('micromatch'); mm(list, patterns[, options]); @@ -8,84 +9,66 @@ mm(list, patterns[, options]); The [main export](#micromatch) takes a list of strings and one or more glob patterns: ```js -console.log(mm(['foo', 'bar', 'qux'], ['f*', 'b*'])); // ['foo', 'bar'] +console.log(mm(['foo', 'bar', 'qux'], ['f*', 'b*'])); +//=> ['foo', 'bar'] ``` -Use [.isMatch](#ismatch) to get true/false: +Use [.isMatch()](#ismatch) to get true/false: ```js -console.log(mm.isMatch('foo', 'f*')); // true +console.log(mm.isMatch('foo', 'f*')); +//=> true ``` -**Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-multimatch) is easy**: - -* use [mm.isMatch()](#ismatch) instead of `minimatch()` -* [mm.match()](#match) is the same as `minimatch.match()` -* [mm()](#usage) is the same as `multimatch()` +[Switching](#switching-to-micromatch) from minimatch and multimatch is easy! -**Heads up!** - -There is one notable difference between micromatch and minimatch in regards to how backslashes are handled. See [the notes about backslashes](#backslashes) for more information. ## Why use micromatch? -> micromatch is a [drop-in replacement][switch] for minimatch and multimatch - -**Speed and accuracy** +> micromatch is a [drop-in replacement](#switching-to-micromatch) for minimatch and multimatch -Micromatch uses [snapdragon][] for parsing and compiling globs, which results in: +- Supports all of the same matching features as [minimatch][] and [multimatch][] +- Micromatch uses [snapdragon][] for parsing and compiling globs, which provides granular control over the entire conversion process in a way that is easy to understand, reason about, and maintain. +- More accurate, with more than 36,000 [test assertions](./test) to prove it. +- More complete support for the Bash 4.3 specification than minimatch and multimatch. Micromatch passes _all of the spec tests_ from bash, including some that bash still fails. +- [Faster matching](#benchmarks), from a combination of optimized glob patterns, faster algorithms, and regex caching. +- [Micromatch is safer][braces]{#braces-is-safe}, and is not subject to DoS with brace patterns, like minimatch and multimatch. +- More reliable windows support than minimatch and multimatch. -- Granular control over the entire conversion process in a way that is easy to understand, reason about, and customize. -- Faster matching, from a combination of optimized glob patterns and (optional) caching. -- Much greater accuracy than minimatch. In fact, nanomatch passes _all of the spec tests_ from bash, including some that bash still fails. However, since there is no real specification for globs, if you encounter a pattern that yields unexpected match results [after researching previous issues](../../issues), [please let us know](../../issues/new). +### Matching features - -- [Micromatch is safer](https://github.com/jonschlinkert/braces#braces-is-safe), and is not subject to DoS with brace patterns, like minimatch and multimatch. -- [faster](#benchmarks) matching -- More accurate, with more than 36,000 [unit tests](./test) - and thousands more patterns tested - to prove it. _(minimatch and multimatch fail a great number of the tests)_. -- More complete support for the Bash 4.3 specification than minimatch and multimatch -- More reliable windows support than minimatch and multimatch -- Supports all of the same matching features as [minimatch](https://github.com/isaacs/minimatch) and [multimatch](https://github.com/sindresorhus/multimatch) -- Micromatch uses real parsers and compilers. Although edge cases are inevitable, micromatch is better equipped to handle them. - - -### Features - -* Native support for multiple glob patterns (no need for wrappers like multimatch) -* Basic wildcard support (`**/*`, `a/b/*.js`, or `['a/*.js', '*b.js']`) -* Negation support (`['!a/*.js', '*!(b).js']`) -* [extglob][] support (`+(x|y)`, `!(a|b)`, etc) -* [POSIX character class][brackets] support (`**/[[:alpha:][:digit:]]/`) -* [brace expansion][braces] support (`a/b-{1..5}.md`, `one/{two,three}/four.md`) -* regex character classes (`a/b/baz-[1-5].js`) -* regex logical or (`a/b/(abc|xyz).js`) +* Support for multiple glob patterns (no need for wrappers like multimatch) +* Wildcards (`**`, `*.js`) +* Negation (`'!a/*.js'`, `'*!(b).js']`) +* [extglobs][extglob] (`+(x|y)`, `!(a|b)`) +* [POSIX character classes][brackets] (`[[:alpha:][:digit:]]`) +* [brace expansion][braces] (`foo/{1..5}.md`, `bar/{a,b,c}.js`) +* regex character classes (`foo-[1-5].js`) +* regex logical "or" (`foo/(abc|xyz).js`) You can mix and match these features to create whatever patterns you need! -**Example** +## Switching to micromatch -```js -mm(['a/b.js', 'a/b.md'], 'a/*.!(js)'); -//=> ['a/b.md'] -``` +There is one notable difference between micromatch and minimatch in regards to how backslashes are handled. See [the notes about backslashes](#backslashes) for more information. -## Switching from minimatch +### From minimatch -Use `mm.isMatch()` instead of `minimatch()`: +Use [mm.isMatch()](#ismatch) instead of `minimatch()`: ```js mm.isMatch('foo', 'b*'); //=> false ``` -Use `mm.match()` instead of `minimatch.match()`: +Use [mm.match()](#match) instead of `minimatch.match()`: ```js mm.match(['foo', 'bar'], 'b*'); //=> 'bar' ``` -## Switching from multimatch +### From multimatch Same signature: @@ -99,24 +82,24 @@ mm(['foo', 'bar', 'baz'], ['f*', '*z']); ## Options -- [basename](#options-basename) -- [bash](#options-bash) -- [cache](#options-cache) -- [dot](#options-dot) -- [failglob](#options-failglob) -- [ignore](#options-ignore) -- [matchBase](#options-matchBase) -- [nobrace](#options-nobrace) -- [nocase](#options-nocase) -- [nodupes](#options-nodupes) -- [noext](#options-noext) -- [noglobstar](#options-noglobstar) -- [nonull](#options-nonull) -- [nullglob](#options-nullglob) -- [snapdragon](#options-snapdragon) -- [sourcemap](#options-sourcemap) -- [unescape](#options-unescape) -- [unixify](#options-unixify) +- [basename](#optionsbasename) +- [bash](#optionsbash) +- [cache](#optionscache) +- [dot](#optionsdot) +- [failglob](#optionsfailglob) +- [ignore](#optionsignore) +- [matchBase](#optionsmatchBase) +- [nobrace](#optionsnobrace) +- [nocase](#optionsnocase) +- [nodupes](#optionsnodupes) +- [noext](#optionsnoext) +- [noglobstar](#optionsnoglobstar) +- [nonull](#optionsnonull) +- [nullglob](#optionsnullglob) +- [snapdragon](#optionssnapdragon) +- [sourcemap](#optionssourcemap) +- [unescape](#optionsunescape) +- [unixify](#optionsunixify) ### options.basename @@ -389,30 +372,30 @@ Extended globbing, as described by the bash man page: | **pattern** | **regex equivalent** | **description** | | --- | --- | --- | -| `?(pattern-list)` | `(foo|bar)?` | Matches zero or one occurrence of the given patterns | -| `*(pattern-list)` | `(foo|bar)*` | Matches zero or more occurrences of the given patterns | -| `+(pattern-list)` | `(foo|bar)+` | Matches one or more occurrences of the given patterns | -| `@(pattern-list)` | `(foo|bar)` * | Matches one of the given patterns | -| `!(pattern-list)` | N/A (equivalent regex is much more complicated) | Matches anything except one of the given patterns | +| `?(pattern)` | `(pattern)?` | Matches zero or one occurrence of the given patterns | +| `*(pattern)` | `(pattern)*` | Matches zero or more occurrences of the given patterns | +| `+(pattern)` | `(pattern)+` | Matches one or more occurrences of the given patterns | +| `@(pattern)` | `(pattern)` * | Matches one of the given patterns | +| `!(pattern)` | N/A (equivalent regex is much more complicated) | Matches anything except one of the given patterns | * Note that `@` isn't a RegEx character. -Powered by [extglob](https://github.com/jonschlinkert/extglob). Visit that library for the full range of options or to report extglob related issues. +Powered by [extglob][]. Visit that library for the full range of options or to report extglob related issues. ### braces -**Expanded braces** - -Braces are expanded when `` - -* range expansion: `a{1..3}b/*.js` expands to: `['a1b/*.js', 'a2b/*.js', 'a3b/*.js']` -* nesting: `a{c,{d,e}}b/*.js` expands to: `['acb/*.js', 'adb/*.js', 'aeb/*.js']` - -**Optimized braces (not expanded)** +Brace patterns can be used to match specific ranges or sets of characters. For example, the pattern `*/{1..3}/*` would match any of following strings: -By default, brace patterns work the same way regex logical `OR` operators. For example, `(a|b)` will achieve the same result as `{a,b}`. +``` +foo/1/bar +foo/2/bar +foo/3/bar +baz/1/qux +baz/2/qux +baz/3/qux +``` -Visit [braces](https://github.com/jonschlinkert/braces) to see the full range of features and options related to brace expansion, or to create brace matching or expansion related issues. +Visit [braces][] to see the full range of features and options related to brace expansion, or to create brace matching or expansion related issues. ### regex character classes @@ -423,7 +406,7 @@ Given the list: `['a.js', 'b.js', 'c.js', 'd.js', 'E.js']`: * `[b-d].js`: matches from `b` to `d`, returning `['b.js', 'c.js', 'd.js']` * `a/[A-Z].js`: matches and uppercase letter, returning `['a/E.md']` -Learn about [regex character classes](http://www.regular-expressions.info/charclass.html). +Learn about [regex character classes][charclass]. ### regex groups @@ -449,7 +432,7 @@ mm.isMatch('a1', '[[:alpha:][:alpha:]]'); //=> false ``` -See [expand-brackets](https://github.com/jonschlinkert/expand-brackets) for more information about bracket expressions. +See [expand-brackets][] for more information about bracket expressions. *** @@ -472,7 +455,7 @@ There is an important, notable difference between minimatch and micromatch _in r We made this decision for micromatch for a couple of reasons: - consistency with bash conventions. -- glob patterns are not filepaths. They are a type of [regular language](https://en.wikipedia.org/wiki/Regular_language) that is converted to a JavaScript regular expression. Thus, when forward slashes are defined in a glob pattern, the resulting regular expression will match windows or POSIX path separators just fine. +- glob patterns are not filepaths. They are a type of [regular language][regular-language] that is converted to a JavaScript regular expression. Thus, when forward slashes are defined in a glob pattern, the resulting regular expression will match windows or POSIX path separators just fine. **A note about joining paths to globs** @@ -486,11 +469,16 @@ All contributions are welcome! Please read [the contributing guide](.github/cont **Bug reports** -Please feel free to create an issue if you find something that you think isn't right. However, if you find a matching-related issue, please try do the following first: +Please create an issue if you encounter a bug or matching behavior that doesn't seem correct. If you find a matching-related issue, please: + +- [research existing issues first](../../issues) (open and closed) +- visit the [GNU Bash documentation][bash] to see how Bash deals with the pattern +- visit the [minimatch][] documentation to cross-check expected behavior in node.js +- if all else fails, since there is no real specification for globs we will probably need to discuss expected behavior and decide how to resolve it. which means any detail you can provide to help with this discussion would be greatly appreciated. -- research existing issues first -- visit the [GNU Bash documentation](https://www.gnu.org/software/bash/manual/) to see how Bash deals with the pattern -- visit the [minimatch][] documentation to cross-check expected behavior +**Platform issues** + +It's important to us that micromatch work consistently on all platforms. If you encounter any platform-specific matching or path related issues, please let us know (pull requests are also greatly appreciated). ## Benchmarks @@ -499,7 +487,7 @@ Please feel free to create an issue if you find something that you think isn't r Install dev dependencies: ```bash -npm i -d && npm benchmark +npm i -d && npm run benchmark ``` ### Latest results @@ -510,10 +498,9 @@ As of {%= date() %} (longer bars are better): {%= bench() %} ``` - -[switch]: #switch-from-minimatch -[expand]: #expand -[character-classes]: http://www.regular-expressions.info/charclass.html +[regular-language]: https://en.wikipedia.org/wiki/Regular_language +[bash]: https://www.gnu.org/software/bash/manual/ +[charclass]: http://www.regular-expressions.info/charclass.html [extended]: http://mywiki.wooledge.org/BashGuide/Patterns#Extended_Globs -[brackets]: https://github.com/jonschlinkert/expand-brackets -[braces]: https://github.com/jonschlinkert/braces +[brackets]: https://github.com/micromatch/expand-brackets +[braces]: https://github.com/micromatch/braces diff --git a/README.md b/README.md index 2f731f9f..86ae723c 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,16 @@ > Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch. -## Table of Contents +
+Table of Contents - [Install](#install) - [Quickstart](#quickstart) - [Why use micromatch?](#why-use-micromatch) - * [Features](#features) -- [Switching from minimatch](#switching-from-minimatch) -- [Switching from multimatch](#switching-from-multimatch) + * [Matching features](#matching-features) +- [Switching to micromatch](#switching-to-micromatch) + * [From minimatch](#from-minimatch) + * [From multimatch](#from-multimatch) - [API](#api) - [Options](#options) * [options.basename](#optionsbasename) @@ -46,7 +48,7 @@ * [Latest results](#latest-results) - [About](#about) -_(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_ +
## Install @@ -66,81 +68,65 @@ mm(list, patterns[, options]); The [main export](#micromatch) takes a list of strings and one or more glob patterns: ```js -console.log(mm(['foo', 'bar', 'qux'], ['f*', 'b*'])); // ['foo', 'bar'] +console.log(mm(['foo', 'bar', 'qux'], ['f*', 'b*'])); +//=> ['foo', 'bar'] ``` -Use [.isMatch](#ismatch) to get true/false: +Use [.isMatch()](#ismatch) to get true/false: ```js -console.log(mm.isMatch('foo', 'f*')); // true +console.log(mm.isMatch('foo', 'f*')); +//=> true ``` -**Switching from [minimatch](#switching-from-minimatch) and [multimatch](#switching-from-multimatch) is easy**: - -* use [mm.isMatch()](#ismatch) instead of `minimatch()` -* [mm.match()](#match) is the same as `minimatch.match()` -* [mm()](#usage) is the same as `multimatch()` - -**Heads up!** - -There is one notable difference between micromatch and minimatch in regards to how backslashes are handled. See [the notes about backslashes](#backslashes) for more information. +[Switching](#switching-to-micromatch) from minimatch and multimatch is easy! ## Why use micromatch? -> micromatch is a [drop-in replacement](#switch-from-minimatch) for minimatch and multimatch +> micromatch is a [drop-in replacement](#switching-to-micromatch) for minimatch and multimatch -**Speed and accuracy** - -Micromatch uses [snapdragon](https://github.com/jonschlinkert/snapdragon) for parsing and compiling globs, which results in: - -* Granular control over the entire conversion process in a way that is easy to understand, reason about, and customize. -* Faster matching, from a combination of optimized glob patterns and (optional) caching. -* Much greater accuracy than minimatch. In fact, nanomatch passes _all of the spec tests_ from bash, including some that bash still fails. However, since there is no real specification for globs, if you encounter a pattern that yields unexpected match results [after researching previous issues](../../issues), [please let us know](../../issues/new). -* [Micromatch is safer](https://github.com/jonschlinkert/braces#braces-is-safe), and is not subject to DoS with brace patterns, like minimatch and multimatch. -* [faster](#benchmarks) matching -* More accurate, with more than 36,000 [unit tests](./test) - and thousands more patterns tested - to prove it. _(minimatch and multimatch fail a great number of the tests)_. -* More complete support for the Bash 4.3 specification than minimatch and multimatch -* More reliable windows support than minimatch and multimatch * Supports all of the same matching features as [minimatch](https://github.com/isaacs/minimatch) and [multimatch](https://github.com/sindresorhus/multimatch) -* Micromatch uses real parsers and compilers. Although edge cases are inevitable, micromatch is better equipped to handle them. - -### Features - -* Native support for multiple glob patterns (no need for wrappers like multimatch) -* Basic wildcard support (`**/*`, `a/b/*.js`, or `['a/*.js', '*b.js']`) -* Negation support (`['!a/*.js', '*!(b).js']`) -* [extglob](https://github.com/jonschlinkert/extglob) support (`+(x|y)`, `!(a|b)`, etc) -* [POSIX character class](https://github.com/jonschlinkert/expand-brackets) support (`**/[[:alpha:][:digit:]]/`) -* [brace expansion](https://github.com/jonschlinkert/braces) support (`a/b-{1..5}.md`, `one/{two,three}/four.md`) -* regex character classes (`a/b/baz-[1-5].js`) -* regex logical or (`a/b/(abc|xyz).js`) +* Micromatch uses [snapdragon](https://github.com/jonschlinkert/snapdragon) for parsing and compiling globs, which provides granular control over the entire conversion process in a way that is easy to understand, reason about, and maintain. +* More accurate, with more than 36,000 [test assertions](./test) to prove it. +* More complete support for the Bash 4.3 specification than minimatch and multimatch. Micromatch passes _all of the spec tests_ from bash, including some that bash still fails. +* [Faster matching](#benchmarks), from a combination of optimized glob patterns, faster algorithms, and regex caching. +* [Micromatch is safer](https://github.com/micromatch/braces#braces-is-safe), and is not subject to DoS with brace patterns, like minimatch and multimatch. +* More reliable windows support than minimatch and multimatch. + +### Matching features + +* Support for multiple glob patterns (no need for wrappers like multimatch) +* Wildcards (`**`, `*.js`) +* Negation (`'!a/*.js'`, `'*!(b).js']`) +* [extglobs](https://github.com/jonschlinkert/extglob) (`+(x|y)`, `!(a|b)`) +* [POSIX character classes](https://github.com/micromatch/expand-brackets) (`[[:alpha:][:digit:]]`) +* [brace expansion](https://github.com/micromatch/braces) (`foo/{1..5}.md`, `bar/{a,b,c}.js`) +* regex character classes (`foo-[1-5].js`) +* regex logical "or" (`foo/(abc|xyz).js`) You can mix and match these features to create whatever patterns you need! -**Example** +## Switching to micromatch -```js -mm(['a/b.js', 'a/b.md'], 'a/*.!(js)'); -//=> ['a/b.md'] -``` +There is one notable difference between micromatch and minimatch in regards to how backslashes are handled. See [the notes about backslashes](#backslashes) for more information. -## Switching from minimatch +### From minimatch -Use `mm.isMatch()` instead of `minimatch()`: +Use [mm.isMatch()](#ismatch) instead of `minimatch()`: ```js mm.isMatch('foo', 'b*'); //=> false ``` -Use `mm.match()` instead of `minimatch.match()`: +Use [mm.match()](#match) instead of `minimatch.match()`: ```js mm.match(['foo', 'bar'], 'b*'); //=> 'bar' ``` -## Switching from multimatch +### From multimatch Same signature: @@ -218,7 +204,7 @@ console.log(mm.isMatch('a.b', '*.a')); ### [.some](index.js#L206) -Returns true if some of the elements in the given `list` match any of the given glob `patterns`. +Returns true if some of the strings in the given `list` match any of the given glob `patterns`. **Params** @@ -239,9 +225,9 @@ console.log(mm.some(['foo.js'], ['*.js', '!foo.js'])); // false ``` -### [.every](index.js#L244) +### [.every](index.js#L242) -Returns true if every element in the given `list` matches at least one of the given glob `patterns`. +Returns true if every string in the given `list` matches any of the given glob `patterns`. **Params** @@ -266,7 +252,7 @@ console.log(mm.every(['foo.js'], ['*.js', '!foo.js'])); // false ``` -### [.any](index.js#L278) +### [.any](index.js#L274) Returns true if **any** of the given glob `patterns` match the specified `string`. @@ -289,7 +275,7 @@ console.log(mm.any('a.a', 'b.*')); //=> false ``` -### [.all](index.js#L326) +### [.all](index.js#L322) Returns true if **all** of the given `patterns` match the specified string. @@ -319,7 +305,7 @@ console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); // true ``` -### [.not](index.js#L360) +### [.not](index.js#L354) Returns a list of strings that _**do not match any**_ of the given `patterns`. @@ -340,7 +326,7 @@ console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); //=> ['b.b', 'c.c'] ``` -### [.contains](index.js#L395) +### [.contains](index.js#L389) Returns true if the given `string` contains the given pattern. Similar to [.isMatch](#isMatch) but the pattern can match any part of the string. @@ -363,7 +349,7 @@ console.log(mm.contains('aa/bb/cc', '*d')); //=> false ``` -### [.matchKeys](index.js#L451) +### [.matchKeys](index.js#L445) Filter the keys of the given object with the given `glob` pattern and `options`. Does not attempt to match nested keys. If you need this feature, use [glob-object](https://github.com/jonschlinkert/glob-object) instead. @@ -385,7 +371,7 @@ console.log(mm.matchKeys(obj, '*b')); //=> { ab: 'b' } ``` -### [.matcher](index.js#L480) +### [.matcher](index.js#L474) Returns a memoized matcher function from the given glob `pattern` and `options`. The returned function takes a string to match as its only argument and returns true if the string is a match. @@ -408,7 +394,7 @@ console.log(isMatch('a.b')); //=> true ``` -### [.makeRe](index.js#L554) +### [.makeRe](index.js#L542) Create a regular expression from the given glob `pattern`. @@ -428,14 +414,14 @@ console.log(mm.makeRe('*.js')); //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ ``` -### [.braces](index.js#L601) +### [.braces](index.js#L585) Expand the given brace `pattern`. **Params** * `pattern` **{String}**: String with brace pattern to expand. -* `options` **{Object}**: Any [options](#options) to change how expansion is performed. See the [braces](https://github.com/jonschlinkert/braces) library for all available options. +* `options` **{Object}**: Any [options](#options) to change how expansion is performed. See the [braces](https://github.com/micromatch/braces) library for all available options. * `returns` **{Array}** **Example** @@ -449,7 +435,7 @@ console.log(mm.braces('foo/{a,b}/bar', {expand: true})); //=> ['foo/(a|b)/bar'] ``` -### [.create](index.js#L665) +### [.create](index.js#L649) Parses the given glob `pattern` and returns an array of abstract syntax trees (ASTs), with the compiled `output` and optional source `map` on each AST. @@ -491,7 +477,7 @@ console.log(mm.create('abc/*.js')); // idx: 6 }] ``` -### [.parse](index.js#L712) +### [.parse](index.js#L696) Parse the given `str` with the given `options`. @@ -524,7 +510,7 @@ console.log(ast); // { type: 'eos', val: '' } ] } ``` -### [.compile](index.js#L765) +### [.compile](index.js#L749) Compile the given `ast` or string with the given `options`. @@ -558,7 +544,7 @@ console.log(mm.compile(ast)); // parsingErrors: [] } ``` -### [.clearCache](index.js#L786) +### [.clearCache](index.js#L770) Clear the regex cache. @@ -570,24 +556,24 @@ mm.clearCache(); ## Options -* [basename](#options-basename) -* [bash](#options-bash) -* [cache](#options-cache) -* [dot](#options-dot) -* [failglob](#options-failglob) -* [ignore](#options-ignore) -* [matchBase](#options-matchBase) -* [nobrace](#options-nobrace) -* [nocase](#options-nocase) -* [nodupes](#options-nodupes) -* [noext](#options-noext) -* [noglobstar](#options-noglobstar) -* [nonull](#options-nonull) -* [nullglob](#options-nullglob) -* [snapdragon](#options-snapdragon) -* [sourcemap](#options-sourcemap) -* [unescape](#options-unescape) -* [unixify](#options-unixify) +* [basename](#optionsbasename) +* [bash](#optionsbash) +* [cache](#optionscache) +* [dot](#optionsdot) +* [failglob](#optionsfailglob) +* [ignore](#optionsignore) +* [matchBase](#optionsmatchBase) +* [nobrace](#optionsnobrace) +* [nocase](#optionsnocase) +* [nodupes](#optionsnodupes) +* [noext](#optionsnoext) +* [noglobstar](#optionsnoglobstar) +* [nonull](#optionsnonull) +* [nullglob](#optionsnullglob) +* [snapdragon](#optionssnapdragon) +* [sourcemap](#optionssourcemap) +* [unescape](#optionsunescape) +* [unixify](#optionsunixify) ### options.basename @@ -669,7 +655,7 @@ Disable expansion of brace patterns. Same behavior as [minimatch](https://github **Default**: `undefined` -See [braces](https://github.com/jonschlinkert/braces) for more information about extended brace expansion. +See [braces](https://github.com/micromatch/braces) for more information about extended brace expansion. ### options.nocase @@ -848,11 +834,11 @@ Extended globbing, as described by the bash man page: | **pattern** | **regex equivalent** | **description** | | --- | --- | --- | -| `?(pattern-list)` | `(foo | bar)?` | Matches zero or one occurrence of the given patterns | -| `*(pattern-list)` | `(foo | bar)*` | Matches zero or more occurrences of the given patterns | -| `+(pattern-list)` | `(foo | bar)+` | Matches one or more occurrences of the given patterns | -| `@(pattern-list)` | `(foo | bar)` * | Matches one of the given patterns | -| `!(pattern-list)` | N/A (equivalent regex is much more complicated) | Matches anything except one of the given patterns | +| `?(pattern)` | `(pattern)?` | Matches zero or one occurrence of the given patterns | +| `*(pattern)` | `(pattern)*` | Matches zero or more occurrences of the given patterns | +| `+(pattern)` | `(pattern)+` | Matches one or more occurrences of the given patterns | +| `@(pattern)` | `(pattern)` * | Matches one of the given patterns | +| `!(pattern)` | N/A (equivalent regex is much more complicated) | Matches anything except one of the given patterns | * Note that `@` isn't a RegEx character. @@ -860,18 +846,18 @@ Powered by [extglob](https://github.com/jonschlinkert/extglob). Visit that libra ### braces -**Expanded braces** - -Braces are expanded when `` - -* range expansion: `a{1..3}b/*.js` expands to: `['a1b/*.js', 'a2b/*.js', 'a3b/*.js']` -* nesting: `a{c,{d,e}}b/*.js` expands to: `['acb/*.js', 'adb/*.js', 'aeb/*.js']` +Brace patterns can be used to match specific ranges or sets of characters. For example, the pattern `*/{1..3}/*` would match any of following strings: -**Optimized braces (not expanded)** - -By default, brace patterns work the same way regex logical `OR` operators. For example, `(a|b)` will achieve the same result as `{a,b}`. +``` +foo/1/bar +foo/2/bar +foo/3/bar +baz/1/qux +baz/2/qux +baz/3/qux +``` -Visit [braces](https://github.com/jonschlinkert/braces) to see the full range of features and options related to brace expansion, or to create brace matching or expansion related issues. +Visit [braces](https://github.com/micromatch/braces) to see the full range of features and options related to brace expansion, or to create brace matching or expansion related issues. ### regex character classes @@ -942,13 +928,18 @@ In other words, since `\\` is reserved as an escape character in globs, on windo All contributions are welcome! Please read [the contributing guide](.github/contributing.md) to get started. -**A special note about bug reports** +**Bug reports** -Please feel free to create an issue if you find something that you think isn't right. However, especially (but not exclusively) if you find a matching-related issue, please please try do the following first: +Please create an issue if you encounter a bug or matching behavior that doesn't seem correct. If you find a matching-related issue, please: -* research existing issues first +* [research existing issues first](../../issues) (open and closed) * visit the [GNU Bash documentation](https://www.gnu.org/software/bash/manual/) to see how Bash deals with the pattern -* visit the [minimatch](https://github.com/isaacs/minimatch) documentation to cross-check expected behavior +* visit the [minimatch](https://github.com/isaacs/minimatch) documentation to cross-check expected behavior in node.js +* if all else fails, since there is no real specification for globs we will probably need to discuss expected behavior and decide how to resolve it. which means any detail you can provide to help with this discussion would be greatly appreciated. + +**Platform issues** + +It's important to us that micromatch work consistently on all platforms. If you encounter any platform-specific matching or path related issues, please let us know (pull requests are also greatly appreciated). ## Benchmarks @@ -957,63 +948,63 @@ Please feel free to create an issue if you find something that you think isn't r Install dev dependencies: ```bash -npm i -d && npm benchmark +npm i -d && npm run benchmark ``` ### Latest results -As of May 28, 2017 (longer bars are better): +As of May 29, 2017 (longer bars are better): ```sh # braces-globstar-large-list -micromatch ██████████████████████████████████████████████████████████████████████ (413 ops/sec) -minimatch ██ (13.20 ops/sec) -multimatch ██ (12.47 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (595 ops/sec) +minimatch █ (13.95 ops/sec) +multimatch █ (14.09 ops/sec) # braces-multiple -micromatch ██████████████████████████████████████████████████████████████████████ (36,121 ops/sec) -minimatch (1.59 ops/sec) -multimatch (1.46 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (48,362 ops/sec) +minimatch (2.18 ops/sec) +multimatch (2.15 ops/sec) # braces-range -micromatch ██████████████████████████████████████████████████████████████████████ (210,437 ops/sec) -minimatch ██ (8,559 ops/sec) -multimatch ██ (8,342 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (187,481 ops/sec) +minimatch ████ (12,366 ops/sec) +multimatch ████ (11,841 ops/sec) # braces-set -micromatch ██████████████████████████████████████████████████████████████████████ (25,350 ops/sec) -minimatch █████ (2,067 ops/sec) -multimatch █████ (1,815 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (24,344 ops/sec) +minimatch ██████ (2,255 ops/sec) +multimatch ██████ (2,199 ops/sec) # globstar-large-list -micromatch ██████████████████████████████████████████████████████████████████████ (399 ops/sec) -minimatch ████ (23.99 ops/sec) -multimatch ████ (25.91 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (561 ops/sec) +minimatch ███ (25.43 ops/sec) +multimatch ███ (25.27 ops/sec) # globstar-long-list -micromatch ██████████████████████████████████████████████████████████████████████ (3,639 ops/sec) -minimatch █████████ (504 ops/sec) -multimatch ██████████ (539 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (3,257 ops/sec) +minimatch ██████████ (485 ops/sec) +multimatch ██████████ (485 ops/sec) # globstar-short-list -micromatch ██████████████████████████████████████████████████████████████████████ (436,248 ops/sec) -minimatch ████ (30,473 ops/sec) -multimatch ████ (26,826 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (359,991 ops/sec) +minimatch ████████ (44,763 ops/sec) +multimatch ███████ (39,977 ops/sec) # no-glob -micromatch ██████████████████████████████████████████████████████████████████████ (625,755 ops/sec) -minimatch ████ (39,617 ops/sec) -multimatch ███ (33,846 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (443,740 ops/sec) +minimatch ██████ (44,152 ops/sec) +multimatch ██████ (41,077 ops/sec) # star-basename -micromatch ██████████████████████████████████████████████████████████████████████ (11,281 ops/sec) -minimatch ██████████████████ (3,028 ops/sec) -multimatch █████████████████████ (3,395 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (10,286 ops/sec) +minimatch ████████████████████ (3,059 ops/sec) +multimatch █████████████████████ (3,129 ops/sec) # star -micromatch ██████████████████████████████████████████████████████████████████████ (9,578 ops/sec) -minimatch ████████████████████ (2,865 ops/sec) -multimatch ████████████████████ (2,873 ops/sec) +micromatch ██████████████████████████████████████████████████████████████████████ (9,756 ops/sec) +minimatch █████████████████████ (2,978 ops/sec) +multimatch █████████████████████ (2,970 ops/sec) ``` @@ -1081,4 +1072,4 @@ Released under the [MIT License](LICENSE). *** -_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on May 28, 2017._ \ No newline at end of file +_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on May 29, 2017._ \ No newline at end of file