Socket
Socket
Sign inDemoInstall

nanomatch

Package Overview
Dependencies
14
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.0 to 0.1.1

CHANGELOG.md

572

index.js
'use strict';
var path = require('path');
var util = require('util');
var toRegex = require('to-regex');
var Snapdragon = require('snapdragon');
var debug = require('debug')('nanomatch');
var Nanomatch = require('./lib/nanomatch');
var compilers = require('./lib/compilers');
var parsers = require('./lib/parsers');
var utils = require('./lib/utils');
var regexCache = {};
var cache = require('./lib/cache');
var MAX_LENGTH = 1024 * 64;
/**
* Convert the given `extglob` 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 extglob = require('extglob');
* var str = extglob('*.!(*a)');
* console.log(str);
* var nanomatch = require('nanomatch');
* console.log(nanomatch(['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 nanomatch(str, options) {
var matcher = new Nanomatch(options);
var ast = matcher.parse(str, options);
return matcher.compile(ast, options);
function nanomatch(list, patterns, options) {
debug('nanomatch <%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 nanomatch.match(list, patterns[0], options);
}
var opts = utils.extend({}, 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, nanomatch.match(list, pattern.slice(1), opts));
negated = true;
} else {
keep.push.apply(keep, nanomatch.match(list, pattern, opts));
}
}
// minimatch.match parity
if (negated && keep.length === 0) {
keep = list;
}
var matches = utils.diff(keep, omit);
return opts.nodupes !== false ? utils.unique(matches) : matches;
}
/**
* Takes an array of strings and a glob pattern and returns a new
* array that contains only the strings that match the pattern.
* Similar to the main function, but `pattern` must be a string.
*
* ```js
* var nano = require('nanomatch');
* console.log(nano.match(['a.a', 'a.b', 'a.c'], '*.!(*a)'));
* //=> ['a.b', 'a.c']
* var nanomatch = require('nanomatch');
* console.log(nanomatch.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
*/
nanomatch.match = function(files, pattern, options) {
var opts = utils.extend({}, options);
var isMatch = nanomatch.matcher(pattern, opts);
var unixify = utils.unixify(opts);
nanomatch.match = function(list, pattern, options) {
debug('match <%s>', pattern);
list = utils.arrayify(list);
var unixify = utils.unixify(options);
var isMatch = memoize('match', pattern, options, nanomatch.matcher);
var matches = [];
files = utils.arrayify(files);
var len = files.length;
var len = list.length;
var idx = -1;
while (++idx < len) {
nanomatch.file = unixify(files[idx]);
if (isMatch(nanomatch.file)) {
matches.push(nanomatch.file);
var file = list[idx];
if (file === pattern) {
matches.push(file);
continue;
}
var unix = unixify(file);
if (unix === pattern) {
matches.push(options && options.unixify ? unix : file);
continue;
}
if (isMatch(unix)) {
matches.push(options && options.unixify ? unix : file);
}
}
// if not options were passed, return now
if (typeof options === 'undefined') {
return utils.unique(matches);
}
var opts = utils.extend({}, options);
if (matches.length === 0) {

@@ -70,79 +125,171 @@ if (opts.failglob === true) {

if (opts.nonull === true || opts.nullglob === true) {
return [pattern.split('\\').join('')];
return [opts.unescape ? utils.unescape(pattern) : pattern];
}
}
// if `ignore` was defined, diff ignored files
// if `opts.ignore` was defined, diff ignored list
if (opts.ignore) {
var ignore = utils.arrayify(opts.ignore);
delete opts.ignore;
var ignored = nanomatch.matchEach(matches, ignore, opts);
matches = utils.diff(matches, ignored);
matches = nanomatch.not(matches, opts.ignore, opts);
}
return opts.nodupes ? utils.unique(matches) : matches;
return opts.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.
* 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('nanomatch');
* console.log(nano.matchEach(['a.a', 'a.b', 'a.c'], ['*.!(*a)']));
* //=> ['a.b', 'a.c']
* var nanomatch = require('nanomatch');
* var isMatch = nanomatch.matcher('*.!(*a)');
*
* console.log(isMatch('a.a'));
* //=> false
* console.log(isMatch('a.b'));
* //=> true
* ```
* @param {Array} `arr` Array of strings to match
* @param {String} `pattern` Glob pattern
* @param {Object} `options`
* @return {Array}
* @param {String} `options`
* @return {Function} Returns a matcher function.
* @api public
*/
nanomatch.matchEach = function(files, patterns, options) {
if (!Array.isArray(files)) {
return [];
nanomatch.matcher = function(pattern, options) {
function matcher() {
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(unixify(fp));
};
}
if (typeof pattern !== 'string') {
throw new TypeError('expected pattern to be a string, regex or function');
}
// pattern is a non-glob string
if (!utils.hasSpecialChars(pattern)) {
return utils.matchPath(unixify(pattern), opts);
}
// pattern is a glob string
var re = nanomatch.makeRe(pattern, options);
// `options.matchBase` or `options.basename` is defined
if (nanomatch.matchBase(pattern, options)) {
return utils.matchBasename(re);
}
// everything else...
return function(fp) {
return re.test(unixify(fp));
};
}
if (!Array.isArray(patterns)) {
return nanomatch.match.apply(this, arguments);
return memoize('matcher', pattern, options, matcher);
};
/**
* Returns true if the specified `string` matches the given glob `pattern`.
*
* ```js
* var nanomatch = require('nanomatch');
* console.log(nanomatch.isMatch('a.a', '*.a'));
* //=> true
* console.log(nanomatch.isMatch('a.b', '*.a'));
* //=> false
* ```
* @param {String} `string` String to match
* @param {String} `pattern` Glob pattern
* @param {String} `options`
* @return {Boolean} Returns true if the string matches the glob pattern.
* @api public
*/
nanomatch.isMatch = function(str, pattern, options) {
if (typeof str === 'undefined') {
throw new TypeError('expected a string');
}
var opts = utils.extend({cache: true}, options);
var omit = [];
var keep = [];
if (typeof pattern === 'undefined') {
throw new TypeError('expected pattern to be a string, regex or function');
}
var len = patterns.length;
var idx = -1;
if (pattern === '' || pattern === ' ') {
return str === pattern;
}
while (++idx < len) {
var pattern = patterns[idx];
if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) {
omit.push.apply(omit, nanomatch.match(files, pattern.slice(1), opts));
} else {
keep.push.apply(keep, nanomatch.match(files, pattern, opts));
}
if (options && nanomatch.matchBase(pattern, options)) {
str = path.basename(str);
}
return utils.diff(keep, omit);
return nanomatch.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.
* ```js
* var nanomatch = require('nanomatch');
* console.log(nanomatch.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
*/
nanomatch.not = function(list, patterns, options) {
var opts = utils.extend({}, options);
var ignore = opts.ignore;
delete opts.ignore;
var matches = utils.diff(list.slice(), nanomatch(list, patterns, opts));
if (ignore) {
return utils.diff(matches, nanomatch(list, ignore));
}
return matches;
};
/**
* Returns true if the given `string` matches any of the given glob `patterns`.
*
* ```js
* var nanomatch = require('nanomatch');
* console.log(nanomatch.any('a.a', ['b.*', '*.a']));
* //=> true
* console.log(nanomatch.any('a.a', 'b.*'));
* //=> false
* ```
* @param {String} `str` The string to test.
* @param {String|Array} `patterns` Glob patterns to use.
* @param {Object} `opts` Options to pass to the `matcher()` function.
* @return {String}
* @param {Object} `options` Options to pass to the `matcher()` function.
* @return {Boolean} Returns true if any patterns match `str`
* @api public
*/
nanomatch.any = function(filepath, patterns, options) {
if (!Array.isArray(patterns) && typeof patterns !== 'string') {
nanomatch.any = function(str, patterns, options) {
if (typeof patterns === 'string') {
patterns = [patterns];
}
if (!Array.isArray(patterns)) {
throw new TypeError('expected patterns to be a string or array');
}
debug('match <%s>', patterns);
var unixify = utils.unixify(opts);
var opts = utils.extend({}, options);
patterns = utils.arrayify(patterns);
filepath = unixify(filepath);
str = unixify(str);
var len = patterns.length;

@@ -152,11 +299,7 @@

var pattern = patterns[i];
if (!utils.isString(pattern)) {
continue;
}
if (!utils.isGlob(pattern)) {
if (filepath === pattern) {
if (str === pattern) {
return true;
}
if (opts.contains && filepath.indexOf(pattern) !== -1) {
if (opts.contains && str.indexOf(pattern) !== -1) {
return true;

@@ -166,4 +309,3 @@ }

}
if (nanomatch.isMatch(filepath, pattern, opts)) {
if (nanomatch.isMatch(str, pattern, opts)) {
return true;

@@ -176,10 +318,24 @@ }

/**
* 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 nanomatch = require('nanomatch');
* console.log(nanomatch.contains('aa/bb/cc', '*b'));
* //=> true
* console.log(nanomatch.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
*/
nanomatch.contains = function(filepath, pattern, options) {
if (typeof filepath !== 'string') {
throw new TypeError('expected filepath to be a string');
nanomatch.contains = function(str, pattern, options) {
if (typeof str !== 'string') {
throw new TypeError('expected a string');
}
if (typeof pattern !== 'string') {

@@ -194,156 +350,185 @@ throw new TypeError('expected pattern to be a string');

if (opts.contains && !utils.isGlob(pattern)) {
filepath = utils.unixify(opts)(filepath);
return filepath.indexOf(pattern) !== -1;
str = utils.unixify(opts)(str);
return str.indexOf(pattern) !== -1;
}
return nanomatch.matcher(pattern, opts)(filepath);
return nanomatch.matcher(pattern, opts)(str);
};
/**
* 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}
*/
nanomatch.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('nanomatch');
*
* console.log(nano.isMatch('a.a', '*.!(*a)'));
* //=> false
* console.log(nano.isMatch('a.b', '*.!(*a)'));
* //=> true
* var nanomatch = require('nanomatch');
* var obj = { aa: 'a', ab: 'b', ac: 'c' };
* console.log(nanomatch.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
*/
nanomatch.isMatch = function(filepath, pattern, options) {
if (pattern === '' || pattern === ' ') {
return filepath === pattern;
nanomatch.matchKeys = function(obj, patterns, options) {
if (!utils.isObject(obj)) {
throw new TypeError('expected the first argument to be an object');
}
var opts = utils.extend({}, options);
if (nanomatch.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 = nanomatch.makeRe(pattern, utils.extend({prepend: false}, opts));
return re.test(filepath);
var keys = nanomatch(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.
* Create a regular expression from the given glob `pattern`.
*
* ```js
* var nano = require('nanomatch');
* var isMatch = nanomatch.matcher('*.!(*a)');
*
* console.log(isMatch('a.a'));
* //=> false
* console.log(isMatch('a.b'));
* //=> true
* var nanomatch = require('nanomatch');
* console.log(nanomatch.makeRe('*.js'));
* //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/
* ```
* @param {String} `pattern` Glob pattern
* @param {String} `options`
* @return {Boolean}
* @param {String} `pattern` The pattern to convert to regex.
* @param {Object} `options`
* @return {RegExp} Returns a regex created from the given pattern.
* @api public
*/
nanomatch.matcher = function(pattern, options) {
// pattern is a function
if (typeof pattern === 'function') {
nanomatch.makeRe = function(pattern, options) {
if (pattern instanceof RegExp) {
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(unixify(fp));
};
if (pattern.length > MAX_LENGTH) {
throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters');
}
if (typeof pattern !== 'string') {
throw new TypeError('expected pattern to be a string, regex or function');
function makeRe() {
var res = nanomatch.create(pattern, options);
var opts = utils.extend({strictErrors: false, wrap: false}, options);
return toRegex(res.output, opts);
}
// pattern is a non-glob string
if (!utils.hasSpecialChars(pattern)) {
return utils.matchPath(unixify(pattern), opts);
var regex = memoize('makeRe', pattern, options, makeRe);
if (regex.source.length > MAX_LENGTH) {
throw new SyntaxError('potentially malicious regex detected');
}
// pattern is a glob string
var re = nanomatch.makeRe(pattern, utils.extend({prepend: false}, opts));
// `matchBase` is defined
if (nanomatch.matchBase(pattern, options)) {
return utils.matchBasename(re);
}
// `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}
*/
nanomatch.matchBase = function(pattern, options) {
if (pattern && pattern.indexOf('/') !== -1 || !options) return false;
return options.basename === true
|| options.matchBase === true;
};
/**
* 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 nanomatch = require('nanomatch');
* var re = nanomatch.makeRe('[[:alpha:]]');
* console.log(re);
* //=> /^(?:[a-zA-Z])$/
* console.log(nanomatch.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
*/
nanomatch.makeRe = function(pattern, options) {
var key = pattern;
var regex;
nanomatch.create = function(pattern, options) {
debug('nanomatch.create <%s>', pattern);
options = options || {};
if (options) {
for (var prop in options) {
if (options.hasOwnProperty(prop)) {
key += ';' + prop + '=' + String(options[prop]);
}
}
var snapdragon = options.snapdragon || new Snapdragon(options);
compilers(snapdragon);
parsers(snapdragon);
var ast = snapdragon.parse(pattern, options);
ast.input = pattern;
var res = snapdragon.compile(ast, options);
return res;
};
/**
* Memoize a generated regex or function
*/
function memoize(type, pattern, options, fn) {
if (!utils.isString(pattern)) {
return fn(pattern, options);
}
options = options || {};
if (options.cache !== false && regexCache.hasOwnProperty(key)) {
return regexCache[key];
var key = createKey(pattern, options);
if (cache.has(type, key)) {
return cache.get(type, key);
}
var nm = new Nanomatch(options);
regex = regexCache[key] = nm.makeRe(pattern, options);
return regex;
};
var val = fn(pattern, options);
if (options && options.cache === false) {
return val;
}
val.key = key;
cache.set(type, key, val);
return val;
}
/**
* Expose `Nanomatch` constructor
* 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.
*/
function createKey(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 key;
}
/**
* Expose parser, compiler and constructor on `nanomatch`
*/
nanomatch.compilers = compilers;
nanomatch.parsers = parsers;
/**
* Expose `nanomatch`
* @type {Function}

@@ -353,4 +538,1 @@ */

module.exports = nanomatch;
module.exports.Nanomatch = Nanomatch;
module.exports.compilers = compilers;
module.exports.parsers = parsers;
'use strict';
var utils = require('./utils');
/**
* Nanomatch compilers
*/
module.exports = function(nanomatch) {
var state = {};
var star = '[^/]*?';
var star = '[^\\/]*?';

@@ -12,13 +13,2 @@ nanomatch.compiler

/**
* beginning-of-string
*/
.set('bos', function(node) {
return this.emit(node.val, node);
})
.set('noop', function(node) {
return this.emit(node.val, node);
})
/**
* Negation / escaping

@@ -28,17 +18,15 @@ */

.set('not', function(node) {
return this.emit('', node);
return this.emit(node.val, node);
})
.set('escape', function(node) {
if (/^\w/.test(node.val)) {
return this.emit(node.val);
}
return this.emit('\\' + node.val, node);
var val = this.options.unescape ? node.ch : node.val;
return this.emit(val, node);
})
/**
* Text
* Regex
*/
.set('text', function(node) {
return this.emit(node.val, node);
.set('dollar', function(node) {
return this.emit('\\' + node.val, node);
})

@@ -51,25 +39,52 @@

.set('dot', function(node) {
if (node.dotfiles === true) {
this.dotfiles = true;
}
return this.emit('\\' + node.val, node);
})
.set('dots', function(node) {
return this.emit('[.]{2}', node);
})
/**
* Slash: "/"
* Slashes: "/" and "\"
*/
.set('slash', function(node) {
if (node.parsed === '**') {
return this.emit('/?', node);
.set('slash', function(node, nodes, i) {
var parsed = node.parsed;
if (parsed === '**') {
this.output = '(' + this.output;
return this.emit('\\/)?', node);
}
return this.emit('/', node);
if (parsed === '!**') {
return this.emit('\\/?', node);
}
return this.emit('\\/', node);
})
/**
* Square: "[/]"
* Square brackets
*/
.set('square', function(node) {
var val = /^\w/.test(node.val) ? node.val : '\\' + node.val;
.set('bracket', function(node) {
var close = node.close;
var open = !node.escaped ? '[' : '\\[';
var prefix = node.prefix;
var inner = node.inner;
var val = node.val;
var len = inner.length;
if (inner !== '\\\\' && len > 1) {
inner = inner.replace(/\\/, '\\\\');
}
if (inner === ']-') {
inner = '\\]\\-';
}
if (prefix && inner.indexOf('.') === -1) {
inner += '.';
}
if (prefix && inner.indexOf('/') === -1) {
inner += '/';
}
val = open + prefix + inner + close;
return this.emit(val, node);

@@ -79,7 +94,8 @@ })

/**
* Plus
* Square: "[.]" (only matches a single character in brackets)
*/
.set('plus', function(node) {
return this.emit('\\' + node.val, node);
.set('square', function(node) {
var val = !/^\w/.test(node.val) ? '\\' + node.val : node.val;
return this.emit(val, node);
})

@@ -92,10 +108,13 @@

.set('qmark', function(node) {
var prefix = this.options.dot ? '[^/]' : '[^/.]';
var val = this.options.dot ? '[^/\\\\]' : '[^/.\\\\]';
var prev = this.prev();
if (prev.type === 'text') {
return this.emit(node.val, node);
if (prev.type === 'text' && prev.val) {
return this.emit(val, node);
}
var val = prefix + '{' + node.val.length + '}';
if (node.val.length > 1) {
val = '.{' + node.val.length + '}';
}
if (prev.type === 'bos' && !this.options.dot) {

@@ -108,15 +127,38 @@ val = '(?!\\.)' + val;

/**
* Plus
*/
.set('plus', function(node) {
var prev = node.parsed.slice(-1);
if ((prev === ']' || prev === ')')) {
return this.emit(node.val, node);
}
if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) {
return this.emit('\\+', node);
}
var ch = this.output.slice(-1);
if (/\w/.test(ch) && !node.inside) {
return this.emit('+\\+?', node);
}
return this.emit('+', node);
})
/**
* globstar: '**'
*/
.set('globstar', function(node) {
var prevCh = this.output[this.output.length - 1];
var nextCh = node.rest.charAt(0);
.set('globstar', function(node, nodes, i) {
var prev = this.prev();
var type = prev.type;
var val = node.val;
if (prev.type !== 'slash' && prev.type !== 'bos') {
var parsed = node.parsed;
if (parsed.charAt(0) === '!') {
parsed = parsed.slice(1);
}
if (parsed && type !== 'slash' && type !== 'bos') {
val = star;
} else {
val = !this.options.dot
val = this.options.dot !== true
? '(?:(?!(?:\\/|^)\\.).)*?'

@@ -126,6 +168,13 @@ : '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?';

if (prevCh === '/' && nextCh === '/') {
var prior = nodes[i - 2] || {};
if (type === 'slash' && node.rest.charAt(0) === '/' && prior.type !== 'qmark') {
this.output += '?';
} else if (!node.rest) {
}
if ((type === 'slash' || type === 'bos') && this.options.dot !== true) {
this.output += '(?!\\.)';
}
return this.emit(val, node);

@@ -139,21 +188,32 @@ })

.set('star', function(node) {
var prevCh = this.output[this.output.length - 1];
var nextCh = node.rest.charAt(0);
var isAlpha = prevCh && /[\w.]/.test(prevCh) && nextCh && /[\w.]/.test(nextCh);
var prev = this.prev();
var next = this.next();
var type = prev.type;
var prefix = !this.dot && !isAlpha && node.rest
var prefix = !this.dotfiles && type !== 'text' && type !== 'escape'
? (this.options.dot ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))(?=.)' : '(?!\\.)')
: '';
return this.emit(prefix + star, node);
var isStart = type === 'slash' || type === 'bos';
if (prefix !== '(?!\\.)' && isStart && type !== 'dot') {
prefix += '(?!\\.([.\/]|$))';
}
if (prefix.indexOf('(?=.)') === -1 && isStart) {
prefix += '(?=.)';
}
var val = prefix + star;
if (!isStart && next.type !== 'eos') {
val = '(' + val + ')?';
}
return this.emit(val, node);
})
/**
* Misc
* Text
*/
.set('dollar', function(node) {
return this.emit('\\' + node.val, node);
})
.set('colon', function(node) {
.set('text', function(node) {
return this.emit(node.val, node);

@@ -167,4 +227,7 @@ })

.set('eos', function(node) {
if (typeof this.ast.strict === 'undefined' && this.options.strictOpen !== true) {
this.output = '(\\.[\\\\\\/])?' + this.output;
}
return this.emit(node.val, node);
});
};
'use strict';
var utils = require('./utils');
var regex = require('regex-not');
var isOdd = require('is-odd');
/**
* Negation regex cache
*/
var cache = {};
/**
* Characters to use in negation regex (we want to "not" match
* characters that are matched by other parsers)
*/
var NOT_REGEX = '[!*+?$\\[/.\\\\]+';
/**
* Regex
*/
var not = createRegex(NOT_REGEX);
/**
* Nanomatch parsers
*/
module.exports = function(nanomatch) {
nanomatch.parser
/**
* Character parsers
* Beginning-of-string
*/
.capture('dot', /^\./)
.capture('plus', /^\+(?!\()/)
.capture('slash', /^\//)
.capture('qmark', /^\?+(?!\()/)
.capture('globstar', /^\*{2}(?!\*)/)
.capture('star', /^(?:\*(?!\*)|[*]{3,})/)
.set('square', function() {
.capture('bos', function() {
if (this.parsed) return;
var pos = this.position();
var m = this.match(/^\[(.)\]/);
var m = this.match(/^\.[\\/]/);
if (!m) return;
var val = '\\.\\/';
var strict = true;
if (this.options.strictOpen === false) {
val = '(\\.\\/|^)';
strict = false;
}
this.ast.strictOpen = strict;
return pos({
type: 'square',
val: m[1]
type: 'bos',
val: val
});

@@ -31,15 +58,37 @@ })

/**
* Parse negations
* Escape: "\\."
*/
.set('not', function() {
.capture('escape', function() {
var pos = this.position();
var m = this.match(/^\\(.)/);
if (!m) return;
var ch = !/[*?+]/.test(m[1]) ? m[1] : m[0];
return pos({
type: 'escape',
val: m[0],
ch: ch
});
})
/**
* Negations: "!"
*/
.capture('not', function() {
var parsed = this.parsed;
var pos = this.position();
var m = this.match(/^\!/);
if (!m || !m[0]) return;
var m = this.match(/^\!+/);
if (!m) return;
var prev = this.prev();
var val = m[0];
var isNegated = isOdd(val.length);
if (parsed === '' && !isNegated) {
val = '';
}
var node = pos({
type: 'not',
val: m[0]
val: val
});

@@ -49,3 +98,3 @@

// so we need to wrap the result in a negation regex
if (!parsed) {
if (parsed === '' && isNegated && !this.options.nonegate) {
this.bos.val = '(?!^(?:';

@@ -55,19 +104,128 @@ this.append = ')$).*';

}
utils.define(node, 'parent', prev);
prev.nodes.push(node);
return node;
})
.set('text', function() {
/**
* Dot: "."
*/
.capture('dot', function() {
var parsed = this.parsed;
var pos = this.position();
var re = /^[-\[({})\]$^`%&;#~=\d\w|,]+/;
var m = this.match(re);
var m = this.match(/^\.+/);
if (!m) return;
var val = m[0];
this.ast.dot = val === '.' && (parsed === '' || parsed.slice(-1) === '/');
return pos({
type: 'dot',
dotfiles: this.ast.dot,
val: val
});
})
.capture('plus', /^\+/)
.capture('qmark', /^\?+/)
.capture('globstar', function() {
var pos = this.position();
var m = this.match(/^\*{2}(?!\*)(?=\/|$)/);
if (!m) return;
while (this.input.slice(0, 4) === '/**/') {
this.input = this.input.slice(4);
}
return pos({
type: 'globstar',
val: '**'
});
})
.capture('star', /^(?:\*(?!\*)|[*]{3,}|[*]{2}(?!\/|$))/)
.capture('slash', /^\//)
.capture('square', function() {
var pos = this.position();
var m = this.match(/^\[(?![\^!])(.)\]/);
if (!m) return;
return pos({
type: 'square',
val: m[1]
});
})
/**
* Brackets: "[...]" (can be overridden by parsers in expand-brackets)
*/
.capture('bracket', function() {
var pos = this.position();
var m = this.match(/^(?:\[([!^]?)([^\]]{2,}|\]\-)(\]|[^*+?]+)|\[)/);
if (!m) return;
var val = m[0];
var prefix = m[1] ? '^' : '';
var inner = m[2] || '';
var close = m[3] || '';
return pos({
type: 'bracket',
val: val,
escaped: close !== ']',
prefix: prefix,
inner: inner,
close: close
});
})
/**
* Dollar: "$"
*/
.capture('dollar', function() {
var pos = this.position();
var m = this.match(/^[$]/);
if (!m) return;
return pos({
type: 'dollar',
val: m[0]
});
})
/**
* Text
*/
.capture('text', function() {
var pos = this.position();
var m = this.match(not);
if (!m || !m[0]) return;
return pos({
type: 'text',
val: m[0]
});
})
});
};
/**
* Create and cache negation regex
*/
function createRegex(str) {
if (cache.hasOwnProperty(str)) {
return cache[str];
}
var opts = {contains: true, strictClose: false};
var re = regex(str, opts);
cache[str] = re;
return re;
}
/**
* Expose negation string
*/
module.exports.not = NOT_REGEX;
'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 = {};
/**
* Create a negation regex from the given string
* @param {String} `str`
* @return {RegExp}
* Utils
*/
utils.not = function(str) {
return '^((?!(?:' + str + ')).)*';
};
exports.define = require('define-property');
exports.diff = require('arr-diff');
exports.extend = require('extend-shallow');
exports.isGlob = require('is-glob');
exports.isObject = require('isobject');
exports.normalize = require('normalize-path');
exports.pick = require('object.pick');
exports.union = require('arr-union');
exports.unique = require('array-unique');
utils.expand = function(str) {
var segs = str.split(',').filter(Boolean);
var arr = segs.slice();
/**
* Cast `val` to an array
* @return {Array}
*/
if (arr.length === 1) {
arr = str.split('..');
if (arr.length > 1) {
segs = utils.fill.apply(null, arr);
}
exports.arrayify = function(val) {
if (!Array.isArray(val)) {
return [val];
}
return segs;
return val;
};
utils.arrayify = function(val) {
return val ? (Array.isArray(val) ? val : [val]) : [];
};
/**

@@ -49,3 +36,3 @@ * Return true if `val` is a non-empty string

utils.isString = function(val) {
exports.isString = function(val) {
return val && typeof val === 'string';

@@ -55,12 +42,6 @@ };

/**
* Get the last element from `array`
* @param {Array} `array`
* @return {*}
* Returns true if the given `str` has special characters
*/
utils.last = function(arr) {
return arr[arr.length - 1];
};
utils.hasSpecialChars = function(str) {
exports.hasSpecialChars = function(str) {
return /(?:(^|\/)[!.]|[*?()\[\]{}]|[+@]\()/.test(str);

@@ -77,3 +58,3 @@ };

utils.matchBasename = function(re) {
exports.matchBasename = function(re) {
return function(filepath) {

@@ -92,6 +73,6 @@ return re.test(filepath) || re.test(path.basename(filepath));

utils.matchPath = function(pattern, options) {
exports.matchPath = function(pattern, options) {
return (options && options.contains)
? utils.containsPath(pattern, options)
: utils.equalsPath(pattern, options);
? exports.containsPath(pattern, options)
: exports.equalsPath(pattern, options);
};

@@ -107,3 +88,3 @@

utils.equalsPath = function(pattern, options) {
exports.equalsPath = function(pattern, options) {
return function(filepath) {

@@ -126,3 +107,3 @@ if (options.nocase === true) {

utils.containsPath = function(pattern) {
exports.containsPath = function(pattern) {
return function(filepath) {

@@ -133,5 +114,17 @@ return pattern.indexOf(filepath) !== -1;

utils.stripPrefix = function(filepath, options) {
var opts = utils.extend({}, options);
if (opts.normalize !== true) {
/**
* Strip backslashes from a pattern
*/
exports.unescape = function(str) {
return str.replace(/\\([^\\*])/g, '$1');
};
/**
* Strip the prefix from a filepath
*/
exports.stripPrefix = function(filepath, options) {
var opts = exports.extend({}, options);
if (path.sep !== '\\' && opts.normalize !== true && opts.strictOpen !== true) {
return filepath;

@@ -141,3 +134,4 @@ }

filepath = String(filepath || '');
if (filepath.slice(0, 2) === './') {
var prefix = filepath.slice(0, 2);
if (prefix === './' || prefix === '.\\') {
return filepath.slice(2);

@@ -153,13 +147,15 @@ }

utils.unixify = function(options) {
var opts = utils.extend({}, options);
exports.unixify = function(options) {
var unixify;
var key = '';
for (var prop in opts) {
if (opts.hasOwnProperty(prop)) {
key += ':' + prop + ':' + String(opts[prop]);
if (options) {
for (var prop in options) {
if (options.hasOwnProperty(prop)) {
key += ':' + prop + ':' + String(options[prop]);
}
}
}
var opts = exports.extend({}, options);
if (unixifyCache.hasOwnProperty(key)) {

@@ -169,5 +165,5 @@ return unixifyCache[key];

if (path.sep !== '/' || opts.unixify === true) {
if (path.sep !== '/' || opts.unixify === true || opts.normalize === true) {
unixify = function(filepath) {
return utils.normalize(utils.stripPrefix(filepath, opts), false);
return exports.normalize(exports.stripPrefix(filepath, opts), false);
};

@@ -177,8 +173,14 @@

unixify = function(filepath) {
return utils.stripPrefix(filepath, opts).replace(/\\([-.\w])/g, '$1');
return exports.stripPrefix(filepath, opts).replace(/\\([-.\w])/g, '$1');
};
} else if (opts.normalize === true) {
unixify = function(filepath) {
return exports.stripPrefix(filepath, opts);
};
} else {
// noop
unixify = function(filepath) {
return utils.stripPrefix(filepath, opts);
return filepath;
};

@@ -185,0 +187,0 @@ }

{
"name": "nanomatch",
"description": "Fast, minimal glob matcher for node.js. ",
"version": "0.1.0",
"description": "Fast, minimal glob matcher for node.js. Complete Bash 4.3 wildcard support (no support for exglobs, brackets or braces)",
"version": "0.1.1",
"homepage": "https://github.com/jonschlinkert/nanomatch",

@@ -14,5 +14,3 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)",

"index.js",
"lib",
"LICENSE",
"README.md"
"lib"
],

@@ -28,2 +26,3 @@ "main": "index.js",

"arr-diff": "^3.0.0",
"arr-union": "^3.1.0",
"array-unique": "^0.3.2",

@@ -33,38 +32,92 @@ "debug": "^2.2.0",

"extend-shallow": "^2.0.1",
"fill-array": "^1.0.0",
"fragment-cache": "^0.1.0",
"is-glob": "^3.0.0",
"is-odd": "^0.1.0",
"isobject": "^2.1.0",
"normalize-path": "^2.0.1",
"repeat-string": "^1.5.4",
"snapdragon": "^0.5.0"
"object.pick": "^1.1.2",
"regex-not": "^1.0.0",
"snapdragon": "^0.7.2",
"to-regex": "^2.1.0"
},
"devDependencies": {
"cross-spawn": "^4.0.0",
"bash-glob": "^0.1.1",
"delete": "^0.3.2",
"gulp-format-md": "^0.1.10",
"mocha": "^3.0.2",
"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",
"helper-changelog": "^0.3.0",
"micromatch": "^2.3.11",
"minimatch": "^3.0.3",
"mkdirp": "^0.5.1",
"mocha": "^3.1.0",
"multimatch": "^2.1.0",
"write": "^0.3.2",
"yargs-parser": "^4.0.2"
},
"keywords": [
"nanomatch"
"bash",
"expand",
"expansion",
"expression",
"file",
"files",
"filter",
"find",
"glob",
"globbing",
"globs",
"globstar",
"match",
"matcher",
"matches",
"matching",
"micromatch",
"minimatch",
"multimatch",
"nanomatch",
"path",
"pattern",
"patterns",
"regex",
"regexp",
"regular",
"shell",
"wildcard"
],
"verb": {
"toc": false,
"layout": "default",
"toc": true,
"layout": "common-minimal",
"tasks": [
"readme"
],
"helpers": [
"helper-changelog"
],
"plugins": [
"gulp-format-md"
],
"lint": {
"reflinks": true
},
"related": {
"list": []
"list": [
"expand-brackets",
"extglob",
"micromatch"
]
},
"reflinks": [
"expand-brackets",
"expand-tilde",
"glob-object",
"micromatch",
"verb",
"verb-generate-readme"
]
],
"lint": {
"reflinks": true
}
}
}
}
# nanomatch [![NPM version](https://img.shields.io/npm/v/nanomatch.svg?style=flat)](https://www.npmjs.com/package/nanomatch) [![NPM downloads](https://img.shields.io/npm/dm/nanomatch.svg?style=flat)](https://npmjs.org/package/nanomatch) [![Build Status](https://img.shields.io/travis/jonschlinkert/nanomatch.svg?style=flat)](https://travis-ci.org/jonschlinkert/nanomatch)
> Fast, minimal glob matcher for node.js.
> Fast, minimal glob matcher for node.js. Complete Bash 4.3 wildcard support (no support for exglobs, brackets or braces)
## Table of Contents
* [Install](#install)
- [nanomatch [![NPM version](https://badge.fury.io/js/nanomatch.svg)](https://npmjs.org/package/nanomatch) [![Build Status](https://travis-ci.org/jonschlinkert/nanomatch.svg?branch=master)](https://travis-ci.org/jonschlinkert/nanomatch)](#nanomatch-npm-versionhttpsbadgefuryiojsnanomatchsvghttpsnpmjsorgpackagenanomatch-build-statushttpstravis-ciorgjonschlinkertnanomatchsvgbranchmasterhttpstravis-ciorgjonschlinkertnanomatch)
* [Installation](#installation)
* [Usage](#usage)
- [What is nanomatch?](#what-is-nanomatch)
- [Getting started](#getting-started)
- [API](#api)
- [Features](#features)
* [Globbing reference](#globbing-reference)
* [Bash pattern matching](#bash-pattern-matching)
- [Benchmarks](#benchmarks)
* [Running benchmarks](#running-benchmarks)
* [Latest results](#latest-results)
- [History](#history)
- [About](#about)
* [Related projects](#related-projects)
* [Contributing](#contributing)
* [Running tests](#running-tests)
* [Author](#author)
* [License](#license)
* [About](#about)
+ [Related projects](#related-projects)
+ [Contributing](#contributing)
+ [Building docs](#building-docs)
+ [Running tests](#running-tests)
+ [Author](#author)
+ [License](#license-1)
_(TOC generated by [verb](https://github.com/verbose/verb) using [markdown-toc](https://github.com/jonschlinkert/markdown-toc))_
## Install
## What is nanomatch?
Install with [npm](https://www.npmjs.com/):
Nanomatch is a fast and accurate glob matcher with full support for standard Bash glob features, including the following "metacharacters": `*`, `**`, `?` and `[...]`.
```sh
$ npm install --save nanomatch
See the [features section](#features) for more info about features.
**How is this different from [micromatch](https://github.com/jonschlinkert/micromatch)?**
Nanomatch only provides wildcard matching, which represents only 1 of the 5 matching "types" offered by micromatch. The others are listed in the [features](#features) section.
Nanomatch will also provide the wildcard matching functionality to micromatch, starting with v3.0.0.
## Getting started
```js
var nanomatch = require('nanomatch');
// the main export is a function that takes an array of strings to match
// and one or more patterns to use for matching
nanomatch(list, patterns[, options]);
```
# nanomatch [![NPM version](https://badge.fury.io/js/nanomatch.svg)](https://npmjs.org/package/nanomatch) [![Build Status](https://travis-ci.org/jonschlinkert/nanomatch.svg?branch=master)](https://travis-ci.org/jonschlinkert/nanomatch)
**Params**
> Fast, minimal glob matcher for node.js.
* `list` **{String|Array}**: One or more strings to match against. This is often a list of files.
* `patterns` **{String|Array}**: One or more [glob paterns](#features) to use for matching.
* `options` **{Object}**: Visit the API to learn about available options.
## Installation
**Example**
```sh
$ npm install --save nanomatch
```js
var nm = require('nanomatch');
console.log(nm(['a', 'b/b', 'c/c/c'], '*'));
//=> ['a']
console.log(nm(['a', 'b/b', 'c/c/c'], '*/*'));
//=> ['b/b']
console.log(nm(['a', 'b/b', 'c/c/c'], '**'));
//=> ['a', 'b/b', 'c/c/c']
```
## Usage
Additional detail provided in the [API documentation](#api).
## API
### [nanomatch](index.js#L29)
The main function takes a list of strings and one or more glob patterns to use for matching.
**Example**
```js
var nanomatch = require('nanomatch');
nanomatch();
console.log(nanomatch(['a.js', 'a.txt'], ['*.js']));
//=> [ 'a.js' ]
```
## License
**Params**
Released under the MIT license. © [Jon Schlinkert](https://github.com/jonschlinkert)
* `list` **{Array}**
* `patterns` **{String|Array}**: Glob patterns
* `options` **{Object}**
* `returns` **{Array}**: Returns an array of matches
## About
### [.match](index.js#L85)
### Contributing
Similar to the main function, but `pattern` must be a string.
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
**Example**
Please read the [contributing guide](.github/contributing.md) for avice on opening issues, pull requests, and coding standards.
```js
var nanomatch = require('nanomatch');
console.log(nanomatch.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a'));
//=> ['a.a', 'a.aa']
```
### Building docs
**Params**
_(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).)_
* `list` **{Array}**: Array of strings to match
* `pattern` **{String}**: Glob pattern
* `options` **{Object}**
* `returns` **{Array}**: Returns an array of matches
To generate the readme and API documentation with [verb](https://github.com/verbose/verb):
### [.matcher](index.js#L156)
```sh
$ npm install -g verb verb-generate-readme && verb
Creates a matcher function from the given glob `pattern` and `options`. The returned function takes a string to match as its only argument.
**Example**
```js
var nanomatch = require('nanomatch');
var isMatch = nanomatch.matcher('*.!(*a)');
console.log(isMatch('a.a'));
//=> false
console.log(isMatch('a.b'));
//=> true
```
**Params**
* `pattern` **{String}**: Glob pattern
* `options` **{String}**
* `returns` **{Function}**: Returns a matcher function.
### [.isMatch](index.js#L215)
Returns true if the specified `string` matches the given glob `pattern`.
**Example**
```js
var nanomatch = require('nanomatch');
console.log(nanomatch.isMatch('a.a', '*.a'));
//=> true
console.log(nanomatch.isMatch('a.b', '*.a'));
//=> false
```
**Params**
* `string` **{String}**: String to match
* `pattern` **{String}**: Glob pattern
* `options` **{String}**
* `returns` **{Boolean}**: Returns true if the string matches the glob pattern.
### [.not](index.js#L250)
Returns a list of strings that do _not_ match any of the given `patterns`.
**Example**
```js
var nanomatch = require('nanomatch');
console.log(nanomatch.not(['a.a', 'b.b', 'c.c'], '*.a'));
//=> ['b.b', 'c.c']
```
**Params**
* `list` **{Array}**: Array of strings to match.
* `pattern` **{String}**: One or more glob patterns.
* `options` **{Object}**
* `returns` **{Array}**: Returns an array of strings that do not match the given patterns.
### [.any](index.js#L280)
Returns true if the given `string` matches any of the given glob `patterns`.
**Example**
```js
var nanomatch = require('nanomatch');
console.log(nanomatch.any('a.a', ['b.*', '*.a']));
//=> true
console.log(nanomatch.any('a.a', 'b.*'));
//=> false
```
**Params**
* `str` **{String}**: The string to test.
* `patterns` **{String|Array}**: Glob patterns to use.
* `options` **{Object}**: Options to pass to the `matcher()` function.
* `returns` **{Boolean}**: Returns true if any patterns match `str`
### [.contains](index.js#L332)
Returns true if the given `string` contains the given pattern. Similar to `.isMatch` but the pattern can match any part of the string.
**Example**
```js
var nanomatch = require('nanomatch');
console.log(nanomatch.contains('aa/bb/cc', '*b'));
//=> true
console.log(nanomatch.contains('aa/bb/cc', '*d'));
//=> false
```
**Params**
* `str` **{String}**: The string to match.
* `pattern` **{String}**: Glob pattern to use for matching.
* `options` **{Object}**
* `returns` **{Boolean}**: Returns true if the patter matches any part of `str`.
### [.matchKeys](index.js#L381)
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
var nanomatch = require('nanomatch');
var obj = { aa: 'a', ab: 'b', ac: 'c' };
console.log(nanomatch.matchKeys(obj, '*b'));
//=> { ab: 'b' }
```
**Params**
* `object` **{Object}**
* `patterns` **{Array|String}**: One or more glob patterns.
* `returns` **{Object}**: Returns an object with only keys that match the given patterns.
### [.makeRe](index.js#L403)
Create a regular expression from the given glob `pattern`.
**Example**
```js
var nanomatch = require('nanomatch');
console.log(nanomatch.makeRe('*.js'));
//=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/
```
**Params**
* `pattern` **{String}**: The pattern to convert to regex.
* `options` **{Object}**
* `returns` **{RegExp}**: Returns a regex created from the given pattern.
### [.create](index.js#L463)
Parses the given glob `pattern` and returns an object with the compiled `output` and optional source `map`.
**Example**
```js
var nanomatch = require('nanomatch');
console.log(nanomatch.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**
* `pattern` **{String}**: Glob pattern
* `options` **{Object}**
* `returns` **{Object}**: Returns an object with the parsed AST, compiled string and optional source map.
## Features
Nanomatch has full support for standard Bash glob features, including the following "metacharacters": `*`, `**`, `?` and `[...]`.
### Globbing reference
Here are some examples of how they work:
**Pattern** | **Description**
--- | ---
`*` | Matches any string except for `/`, leading `.`, or `/.` inside a path
`**` | Matches any string including `/`, but not a leading `.` or `/.` inside a path. More than two stars (e.g. `***` is treated the same as one star, and `**` loses its special meaning when it's not the only thing in a path segment, per Bash specifications)
`foo*` | Matches any string beginning with `foo`
`*bar*` | Matches any string containing `bar` (beginning, middle or end)
`*.min.js` | Matches any string ending with `.min.js`
`[abc]*.js` | Matches any string beginning with `a`, `b`, or `c` and ending with `.js`
`abc?` | Matches `abcd` or `abcz` but not `abcde`
The exceptions noted for `*` apply to all patterns that contain a `*`.
**Not supported**
The following extended-globbing features are not supported:
* [brace expansion](https://github.com/jonschlinkert/braces) (e.g. `{a,b,c}`)
* [extglobs](https://github.com/jonschlinkert/extglob) (e.g. `@(a|!(c|d))`)
* [POSIX brackets](https://github.com/jonschlinkert/expand-brackets) (e.g. `[[:alpha:][:digit:]]`)
If you need any of these features consider using [micromatch](https://github.com/jonschlinkert/micromatch) instead.
### Bash pattern matching
Nanomatch is part of a suite of libraries aimed at bringing the power and expressiveness of [Bash's][] matching and expansion capabilities to JavaScript, _and - as you can see by the [benchmarks](#benchmarks) - without sacrificing speed_.
**Related library** | **Matching Type** | **Example** | **Description**
--- | --- | --- | ---
[micromatch](https://github.com/jonschlinkert/micromatch) | Wildcards | `*` | [Filename expansion](https://www.gnu.org/software/bash/manual/html_node/Filename-Expansion.html#Filename-Expansion), also referred to as globbing and pathname expansion, allows the use of [wildcards](#features) for matching.
[expand-tilde](https://github.com/jonschlinkert/expand-tilde) | Tildes | `~` | [Tilde expansion](https://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html#Tilde-Expansion) converts the leading tilde in a file path to the user home directory.
[braces](https://github.com/jonschlinkert/braces) | Braces | `{a,b,c}` | [Brace expansion](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html)
[expand-brackets](https://github.com/jonschlinkert/expand-brackets) | Brackets | `[[:alpha:]]` | [POSIX character classes](https://www.gnu.org/software/grep/manual/html_node/Character-Classes-and-Bracket-Expressions.html) (also referred to as POSIX brackets, or POSIX character classes)
[extglob](https://github.com/jonschlinkert/extglob) | Parens | `!(a|b)` | [Extglobs](https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html#Pattern-Matching)
[micromatch](https://github.com/jonschlinkert/micromatch) | All | all | Micromatch is built on top of the other libraries.
There are many resources available on the web if you want to dive deeper into how these features work in Bash.
## Benchmarks
### Running benchmarks
Install dev dependencies:
```bash
npm i -d && npm benchmark
```
### Latest results
```bash
Benchmarking: (4 of 4)
· globstar-basic
· negation-basic
· not-glob-basic
· star-basic
# benchmark/fixtures/match/globstar-basic.js (182 bytes)
minimatch x 35,521 ops/sec ±0.99% (82 runs sampled)
multimatch x 29,662 ops/sec ±1.90% (82 runs sampled)
nanomatch x 719,866 ops/sec ±1.53% (84 runs sampled)
fastest is nanomatch
# benchmark/fixtures/match/negation-basic.js (132 bytes)
minimatch x 65,810 ops/sec ±1.11% (85 runs sampled)
multimatch x 24,267 ops/sec ±1.40% (85 runs sampled)
nanomatch x 698,260 ops/sec ±1.42% (84 runs sampled)
fastest is nanomatch
# benchmark/fixtures/match/not-glob-basic.js (93 bytes)
minimatch x 91,445 ops/sec ±1.69% (83 runs sampled)
multimatch x 62,945 ops/sec ±1.20% (84 runs sampled)
nanomatch x 3,077,100 ops/sec ±1.45% (84 runs sampled)
fastest is nanomatch
# benchmark/fixtures/match/star-basic.js (93 bytes)
minimatch x 62,144 ops/sec ±1.67% (85 runs sampled)
multimatch x 46,133 ops/sec ±1.66% (83 runs sampled)
nanomatch x 1,039,345 ops/sec ±1.23% (86 runs sampled)
fastest is nanomatch
```
## History
### key
Changelog entries are classified using the following labels _(from [keep-a-changelog](https://github.com/olivierlacan/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.
### [0.1.0] - 2016-10-08
First release.
## About
### Related projects
* [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.")
* [micromatch](https://www.npmjs.com/package/micromatch): Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch. | [homepage](https://github.com/jonschlinkert/micromatch "Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch.")
### Contributing
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.
### Running tests

@@ -91,2 +439,2 @@

_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.1.30, on September 05, 2016._
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.1.31, on October 08, 2016._
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc