micromatch
Advanced tools
Comparing version 0.2.2 to 1.0.0
290
index.js
@@ -10,2 +10,4 @@ /*! | ||
var path = require('path'); | ||
var filenameRe = require('filename-regex'); | ||
var unixify = require('unixify'); | ||
@@ -16,61 +18,9 @@ var union = require('arr-union'); | ||
function makeRe(glob, options) { | ||
var opts = options || {}; | ||
var flags = ''; | ||
var i = 0; | ||
// only recompile regex if options change | ||
optsCache = optsCache || opts; | ||
if (!equal(optsCache, opts)) { | ||
regex = null; | ||
cache = glob; | ||
} | ||
// only recompile regex if glob changes | ||
cache = cache || glob; | ||
if (cache !== glob) { | ||
glob = unixify(glob); | ||
regex = null; | ||
cache = glob; | ||
} | ||
// if `true`, then we can just return | ||
// the regex that was previously cached | ||
if (regex instanceof RegExp) { | ||
return regex; | ||
} | ||
// expand `{1..5}` braces | ||
if (/\{/.test(glob)) { | ||
glob = expand(glob); | ||
} | ||
var len = tokens.length; | ||
while (i < len) { | ||
var group = tokens[i++]; | ||
var re = group[1].re; | ||
var to = group[1].to; | ||
// apply special cases from options | ||
for (var key in opts) { | ||
if (group[1].hasOwnProperty(key)) { | ||
to += group[1][key]; | ||
} | ||
} | ||
glob = glob.replace(re, to); | ||
} | ||
if (opts.nocase) flags += 'i'; | ||
// cache the regex | ||
regex = globRegex(glob, flags); | ||
// return the result | ||
return regex; | ||
} | ||
/** | ||
* Pass an array of files and a glob pattern as a string. | ||
* | ||
* This function is called by the main `micromatch` function | ||
* If you only need to pass a single pattern you might get | ||
* minor speed improvements using this function. | ||
* very minor speed improvements using this function. | ||
* | ||
@@ -88,3 +38,13 @@ * @param {Array} `files` | ||
var opts = options || {}; | ||
files = arrayify(files); | ||
var negate = opts.negate || pattern.charAt(0) === '!'; | ||
if (negate) { | ||
pattern = pattern.slice(1); | ||
} | ||
var doubleStar = /\*\*/.test(pattern); | ||
var regex = makeRe(pattern, opts); | ||
var len = files.length; | ||
@@ -95,7 +55,26 @@ var res = []; | ||
while (i < len) { | ||
var fp = unixify(files[i++]); | ||
if (makeRe(pattern, options).test(fp)) { | ||
var file = files[i++]; | ||
var fp = unixify(file); | ||
if (!/\//.test(fp) && doubleStar) { | ||
regex = baseRe(pattern, opts); | ||
} | ||
if (opts.matchBase) { | ||
var filename = fp.match(filenameRe())[0]; | ||
if (regex.test(filename)) { | ||
res.push(fp); | ||
} | ||
} else if (regex.test(fp)) { | ||
res.push(fp); | ||
} | ||
} | ||
if (negate) { | ||
return diff(files, res); | ||
} | ||
if (opts.nonull && !res.length) { | ||
return pattern; | ||
} | ||
return res; | ||
@@ -145,29 +124,7 @@ } | ||
/** | ||
* Create the regex to do the matching. If | ||
* the leading character in the `glob` is `!` | ||
* a negation regex is returned. | ||
* | ||
* @param {String} `glob` | ||
* @param {String} `flags` | ||
*/ | ||
function globRegex(glob, flags) { | ||
var res = '^' + glob + '$'; | ||
if (/^!/.test(glob)) { | ||
res = '^(?!((?!\\.)' + glob.slice(1) + ')$)'; | ||
} | ||
return new RegExp(res, flags); | ||
} | ||
/** | ||
* Regex for matching single-level braces | ||
*/ | ||
function bracesRegex() { | ||
return /\{([^{]+)\}/g; | ||
} | ||
/** | ||
* Expand braces in the given glob pattern. | ||
* | ||
* We only need to use the [braces] lib when | ||
* patterns are nested. | ||
* | ||
* @param {String} `glob` | ||
@@ -177,12 +134,11 @@ * @return {String} | ||
function expand (glob) { | ||
if (!isBasicBrace(glob)) { | ||
// avoid sending the glob to the `braces` lib if not necessary | ||
return glob.replace(bracesRegex(), function (_, inner) { | ||
function expand(glob, fn) { | ||
if (isBasicBrace(glob)) { | ||
return glob.replace(bracesRegex(), function(_, inner) { | ||
return '(' + inner.split(',').join('|') + ')'; | ||
}); | ||
} else { | ||
// if it's nested, we'll use `braces` | ||
return braces(glob).join('|'); | ||
return braces(glob, fn).join('|'); | ||
} | ||
// return braces(glob, fn).join('|'); | ||
} | ||
@@ -201,4 +157,4 @@ | ||
function isBasicBrace(str) { | ||
if (/\.{2}/.test(str)) { | ||
return true; | ||
if (/\.{2}|\(/.test(str)) { | ||
return false; | ||
} | ||
@@ -213,9 +169,9 @@ | ||
if (ch === '{') { | ||
return true; | ||
return false; | ||
} | ||
if (ch === '}') { | ||
return false; | ||
return true; | ||
} | ||
} | ||
return false; | ||
return true; | ||
} | ||
@@ -234,3 +190,2 @@ | ||
if (!b) return false; | ||
for (var prop in b) { | ||
@@ -248,2 +203,10 @@ if (!a.hasOwnProperty(prop)) { | ||
/** | ||
* Regex for matching single-level braces | ||
*/ | ||
function bracesRegex() { | ||
return /\{([^{]+)\}/g; | ||
} | ||
/** | ||
* Coerce `val` to an array | ||
@@ -262,31 +225,138 @@ * | ||
/** | ||
* Results cache | ||
* Special patterns to be converted to regex | ||
*/ | ||
var regex; | ||
var cache; | ||
var optsCache; | ||
var dots = '\\.{1,2}'; | ||
var slashQ = '[^/]%%%~'; | ||
var slashStar = '\\.' + slashQ; | ||
var star = '(%~=.)\\.' + slashQ; | ||
var dotstarbase = function(dot) { | ||
var re = dot ? ('(%~:^|\\/)' + dots + '(%~:$|\\/)') : '\\.'; | ||
return '(%~!' + re + ')(%~=.)'; | ||
}; | ||
var dotstars = function (dot) { | ||
var re = dot ? '(%~:' + dots + ')($|\\/)': '\\.'; | ||
return '(%~:(%~!(%~:\\/|^)' + re + ').)%%%~'; | ||
}; | ||
var stardot = function (dot) { | ||
return dotstarbase(dot) + slashQ; | ||
}; | ||
/** | ||
* Special patterns | ||
* Create a regular expression for matching | ||
* file paths. | ||
* | ||
* @param {String} glob | ||
* @param {Object} options | ||
* @return {RegExp} | ||
*/ | ||
var matchBase = '[\\s\\S]+'; | ||
var dotfile = '[^\\/]*?'; | ||
function makeRe(glob, options) { | ||
var opts = options || {}; | ||
// reset cache, recompile regex if options change | ||
optsCache = optsCache || opts; | ||
if (!equal(optsCache, opts)) { | ||
cache = glob; | ||
globRe = null; | ||
} | ||
// reset cache, recompile regex if glob changes | ||
cache = cache || glob; | ||
if (cache !== glob) { | ||
glob = unixify(glob); | ||
cache = glob; | ||
globRe = null; | ||
} | ||
// if `true`, then we can just return | ||
// the regex that was previously cached | ||
if (globRe instanceof RegExp) { | ||
return globRe; | ||
} | ||
var negate = glob.charAt(0) === '!'; | ||
if (negate) { | ||
glob = glob.slice(1); | ||
} | ||
var flags = opts.flags || ''; | ||
var i = 0; | ||
// expand `{1..5}` braces | ||
if (/\{/.test(glob) && !opts.nobraces) { | ||
glob = expand(glob); | ||
} | ||
glob = glob.replace(/\[/g, dotstarbase(opts.dot) + '['); | ||
glob = glob.replace(/^(\w):([\\\/]*)\*\*/gi, '(%~=.)$1:$2' + slashQ + slashQ); | ||
glob = glob.replace(/\/\*$/g, '\\/' + dotstarbase(opts.dot) + slashQ); | ||
glob = glob.replace(/\*\.\*/g, stardot(opts.dot) + slashStar); | ||
glob = glob.replace(/^\.\*/g, star); | ||
glob = glob.replace(/\/\.\*/g, '\\/' + star); | ||
glob = glob.replace(/[^?]\?/g, '\\/'+ dotstarbase(opts.dot) + '[^/]'); | ||
glob = glob.replace(/\?/g, '[^/]'); | ||
glob = glob.replace(/\*\./g, stardot(opts.dot) + '\.'); | ||
glob = glob.replace(/\//g, '\\/'); | ||
glob = glob.replace(/\.(\w+|$)/g, '\\.$1'); | ||
glob = glob.replace(/\*\*/g, dotstars(opts.dot)); | ||
glob = glob.replace(/(?!\/)\*$/g, slashQ); | ||
glob = glob.replace(/\*/g, stardot(opts.dot)); | ||
// clean up | ||
glob = glob.replace(/%~/g, '?'); | ||
glob = glob.replace(/%%/g, '*'); | ||
glob = glob.replace(/[\\]+\//g, '\\/'); | ||
glob = glob.replace(/\[\^\\\/\]/g, '[^/]'); | ||
if (opts.nocase) flags += 'i'; | ||
// cache the regex | ||
globRe = new RegExp(globRegex(glob, negate), flags); | ||
return globRe; | ||
} | ||
/** | ||
* Glob tokens to match and replace with | ||
* regular expressions | ||
* Create the regex to do the matching. If | ||
* the leading character in the `glob` is `!` | ||
* a negation regex is returned. | ||
* | ||
* @param {String} `glob` | ||
* @param {String} `flags` | ||
*/ | ||
var tokens = [ | ||
['\\\\', {re: /\\{2}/g, to: '\\/'}], | ||
['/', {re: /\//g, to: '\\/'}], | ||
['.', {re: /[.]/g, to: '\\.'}], | ||
['?', {re: /\?/g, to: '.'}], | ||
['**', {re: /[*]{2}/g, to: '[\\s\\S]+'}], | ||
['*', {re: /[*]/g, to: '[^\\/]*?', matchBase: matchBase, dot: dotfile}], | ||
]; | ||
function globRegex(glob, negate) { | ||
glob = ('(?:' + glob + ')$'); | ||
glob = negate | ||
? ('(?!^' + glob + ').*$') | ||
: glob; | ||
return '^' + glob; | ||
} | ||
/** | ||
* Create a regular expression for matching basenames | ||
* | ||
* @param {String} pattern | ||
* @param {Object} opts | ||
* @return {RegExp} | ||
*/ | ||
function baseRe(pattern, opts) { | ||
var re = pattern + '|' + pattern.replace(/\/?\*\*\/?/, ''); | ||
return makeRe(re, opts); | ||
} | ||
/** | ||
* Results cache | ||
*/ | ||
var globRe; | ||
var cache; | ||
var optsCache; | ||
/** | ||
* Expose `micromatch` | ||
@@ -293,0 +363,0 @@ */ |
{ | ||
"name": "micromatch", | ||
"description": "Glob matching for javascript/node.js. Like minimatch, but 10-40x faster.", | ||
"version": "0.2.2", | ||
"description": "Glob matching for javascript/node.js. A faster alternative to minimatch (10-20x faster on avg), with all the features you're used to using in your Grunt and gulp tasks.", | ||
"version": "1.0.0", | ||
"homepage": "https://github.com/jonschlinkert/micromatch", | ||
@@ -29,5 +29,6 @@ "author": { | ||
"dependencies": { | ||
"arr-diff": "^0.2.2", | ||
"arr-diff": "^1.0.1", | ||
"arr-union": "^1.0.0", | ||
"braces": "^1.0.0", | ||
"filename-regex": "^0.1.0", | ||
"unixify": "^0.1.0" | ||
@@ -39,2 +40,3 @@ }, | ||
"minimatch": "^2.0.1", | ||
"minimist": "^1.1.0", | ||
"mocha": "*", | ||
@@ -52,5 +54,7 @@ "should": "*", | ||
"glob", | ||
"globbing", | ||
"globstar", | ||
"match", | ||
"matches", | ||
"matching", | ||
"minimatch", | ||
@@ -60,5 +64,6 @@ "multimatch", | ||
"regex", | ||
"regexp", | ||
"regular", | ||
"shell" | ||
] | ||
} | ||
} |
# micromatch [![NPM version](https://badge.fury.io/js/micromatch.svg)](http://badge.fury.io/js/micromatch) | ||
> Glob matching for javascript/node.js. Like minimatch, but 10-40x faster. | ||
> Glob matching for javascript/node.js. A faster and more stable alternative to minimatch (bencharks show micromatch is 10-40x faster on avg). | ||
- 5-40x faster than minimatch ([benchmarks](#benchmarks)) | ||
- 10-20x faster than minimatch ([benchmarks](#benchmarks)) on average | ||
- Focus on core Bash 4.3 specification features that are actually used (or can be used) in node.js | ||
- Supports passing glob patterns as a string or array | ||
- Extensive unit tests | ||
@@ -15,8 +16,12 @@ | ||
+ [Brace Expansion] - ex. `foo/bar-{1..5}.md`, `one/{two,three}/four.md` | ||
+ Globstar matching - ex. `**/*`, `a/b/*.js` | ||
+ [Brace Expansion][braces] (`foo/bar-{1..5}.md`, `one/{two,three}/four.md`) | ||
+ Globstar matching (`**/*`, `a/b/*.js`, etc) | ||
+ Logical `OR` (`foo/bar/(abc|xyz).js`) | ||
+ Regex character classes (`foo/bar/baz-[1-5].js`) | ||
You can combine these features to achieve whatever matching patterns you need. | ||
**Does not support** | ||
+ [Extended glob matching][extended]. This might be supported in the future, either in core or as an extension, but it's hard to justify the cost in terms of speed and complexity for features no that are rarely used. | ||
+ [Extended glob matching][extended]. This might be supported in the future, either in core or as an extension, but it's hard to justify the cost in terms of speed and complexity for features that are rarely used. | ||
@@ -33,3 +38,3 @@ | ||
### micromatch() | ||
Works exactly the same as minimatch. | ||
@@ -53,8 +58,45 @@ ```js | ||
### micromatch.matchRe() | ||
## Special characters | ||
> 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. | ||
**Square brackets** | ||
Given `['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][character-classes]. | ||
**Parentheses** | ||
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. | ||
**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: | ||
- range expansion: `a{1..3}b/*.js` expands to: `['a1b/*.js', 'a2b/*.js', 'a3b/*.js']` | ||
Learn about [brace expansion][braces], or 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. | ||
## .matchRe | ||
Generate a regular expression for matching file paths based on the given pattern: | ||
```js | ||
var | ||
micromatch.makeRe('a/?/c.md'); | ||
@@ -103,5 +145,6 @@ //=> /^a\/.\/c\.md$/ | ||
_This file was generated by [verb](https://github.com/assemble/verb) on December 23, 2014._ | ||
_This file was generated by [verb](https://github.com/assemble/verb) on December 28, 2014._ | ||
[extended]: http://mywiki.wooledge.org/BashGuide/Patterns#Extended_Globs | ||
[Brace Expansion]: https://github.com/jonschlinkert/braces | ||
[braces]: https://github.com/jonschlinkert/braces | ||
[character-classes]: http://www.regular-expressions.info/charclass.html |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
14473
302
0
146
5
7
+ Addedfilename-regex@^0.1.0
+ Addedarr-diff@1.1.0(transitive)
+ Addedarr-flatten@1.1.0(transitive)
+ Addedarray-slice@0.2.3(transitive)
+ Addedfilename-regex@0.1.0(transitive)
- Removedarr-diff@0.2.2(transitive)
Updatedarr-diff@^1.0.1