Skip to main content
Module

x/minimatch/index.js

A deno port of minimatch
Latest
File
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194
import * as path from 'https://deno.land/std/path/mod.ts';
var concatMap = function (xs, fn) { var res = []; for (var i = 0; i < xs.length; i++) { var x = fn(xs[i], i); if (isArray(x)) res.push.apply(res, x); else res.push(x); } return res;};
var isArray = Array.isArray || function (xs) { return Object.prototype.toString.call(xs) === '[object Array]';};
var balancedMatch = balanced;function balanced(a, b, str) { if (a instanceof RegExp) a = maybeMatch(a, str); if (b instanceof RegExp) b = maybeMatch(b, str);
var r = range(a, b, str);
return r && { start: r[0], end: r[1], pre: str.slice(0, r[0]), body: str.slice(r[0] + a.length, r[1]), post: str.slice(r[1] + b.length) };}
function maybeMatch(reg, str) { var m = str.match(reg); return m ? m[0] : null;}
balanced.range = range;function range(a, b, str) { var begs, beg, left, right, result; var ai = str.indexOf(a); var bi = str.indexOf(b, ai + 1); var i = ai;
if (ai >= 0 && bi > 0) { begs = []; left = str.length;
while (i >= 0 && !result) { if (i == ai) { begs.push(i); ai = str.indexOf(a, i + 1); } else if (begs.length == 1) { result = [ begs.pop(), bi ]; } else { beg = begs.pop(); if (beg < left) { left = beg; right = bi; }
bi = str.indexOf(b, i + 1); }
i = ai < bi && ai >= 0 ? ai : bi; }
if (begs.length) { result = [ left, right ]; } }
return result;}
var braceExpansion = expandTop;
var escSlash = '\0SLASH'+Math.random()+'\0';var escOpen = '\0OPEN'+Math.random()+'\0';var escClose = '\0CLOSE'+Math.random()+'\0';var escComma = '\0COMMA'+Math.random()+'\0';var escPeriod = '\0PERIOD'+Math.random()+'\0';
function numeric(str) { return parseInt(str, 10) == str ? parseInt(str, 10) : str.charCodeAt(0);}
function escapeBraces(str) { return str.split('\\\\').join(escSlash) .split('\\{').join(escOpen) .split('\\}').join(escClose) .split('\\,').join(escComma) .split('\\.').join(escPeriod);}
function unescapeBraces(str) { return str.split(escSlash).join('\\') .split(escOpen).join('{') .split(escClose).join('}') .split(escComma).join(',') .split(escPeriod).join('.');}

// Basically just str.split(","), but handling cases// where we have nested braced sections, which should be// treated as individual members, like {a,{b,c},d}function parseCommaParts(str) { if (!str) return [''];
var parts = []; var m = balancedMatch('{', '}', str);
if (!m) return str.split(',');
var pre = m.pre; var body = m.body; var post = m.post; var p = pre.split(',');
p[p.length-1] += '{' + body + '}'; var postParts = parseCommaParts(post); if (post.length) { p[p.length-1] += postParts.shift(); p.push.apply(p, postParts); }
parts.push.apply(parts, p);
return parts;}
function expandTop(str) { if (!str) return [];
// I don't know why Bash 4.3 does this, but it does. // Anything starting with {} will have the first two bytes preserved // but *only* at the top level, so {},a}b will not expand to anything, // but a{},b}c will be expanded to [a}c,abc]. // One could argue that this is a bug in Bash, but since the goal of // this module is to match Bash's rules, we escape a leading {} if (str.substr(0, 2) === '{}') { str = '\\{\\}' + str.substr(2); }
return expand(escapeBraces(str), true).map(unescapeBraces);}
function embrace(str) { return '{' + str + '}';}function isPadded(el) { return /^-?0\d/.test(el);}
function lte(i, y) { return i <= y;}function gte(i, y) { return i >= y;}
function expand(str, isTop) { var expansions = [];
var m = balancedMatch('{', '}', str); if (!m || /\$$/.test(m.pre)) return [str];
var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); var isSequence = isNumericSequence || isAlphaSequence; var isOptions = m.body.indexOf(',') >= 0; if (!isSequence && !isOptions) { // {a},b} if (m.post.match(/,.*\}/)) { str = m.pre + '{' + m.body + escClose + m.post; return expand(str); } return [str]; }
var n; if (isSequence) { n = m.body.split(/\.\./); } else { n = parseCommaParts(m.body); if (n.length === 1) { // x{{a,b}}y ==> x{a}y x{b}y n = expand(n[0], false).map(embrace); if (n.length === 1) { var post = m.post.length ? expand(m.post, false) : ['']; return post.map(function(p) { return m.pre + n[0] + p; }); } } }
// at this point, n is the parts, and we know it's not a comma set // with a single entry.
// no need to expand pre, since it is guaranteed to be free of brace-sets var pre = m.pre; var post = m.post.length ? expand(m.post, false) : [''];
var N;
if (isSequence) { var x = numeric(n[0]); var y = numeric(n[1]); var width = Math.max(n[0].length, n[1].length); var incr = n.length == 3 ? Math.abs(numeric(n[2])) : 1; var test = lte; var reverse = y < x; if (reverse) { incr *= -1; test = gte; } var pad = n.some(isPadded);
N = [];
for (var i = x; test(i, y); i += incr) { var c; if (isAlphaSequence) { c = String.fromCharCode(i); if (c === '\\') c = ''; } else { c = String(i); if (pad) { var need = width - c.length; if (need > 0) { var z = new Array(need + 1).join('0'); if (i < 0) c = '-' + z + c.slice(1); else c = z + c; } } } N.push(c); } } else { N = concatMap(n, function(el) { return expand(el, false) }); }
for (var j = 0; j < N.length; j++) { for (var k = 0; k < post.length; k++) { var expansion = pre + N[j] + post[k]; if (!isTop || isSequence || expansion) expansions.push(expansion); } }
return expansions;}
var minimatch_1 = minimatch;minimatch.Minimatch = Minimatch;
var path$1 = { sep: '/' };try { path$1 = path;} catch (er) {}
var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {};

var plTypes = { '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, '?': { open: '(?:', close: ')?' }, '+': { open: '(?:', close: ')+' }, '*': { open: '(?:', close: ')*' }, '@': { open: '(?:', close: ')' }};
// any single thing other than /// don't need to escape / when using new RegExp()var qmark = '[^/]';
// * => any number of charactersvar star = qmark + '*?';
// ** when dots are allowed. Anything goes, except .. and .// not (^ or / followed by one or two dots followed by $ or /),// followed by anything, any number of times.var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?';
// not a ^ or / followed by a dot,// followed by anything, any number of times.var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?';
// characters that need to be escaped in RegExp.var reSpecials = charSet('().*{}+?[]^$\\!');
// "abc" -> { a:true, b:true, c:true }function charSet (s) { return s.split('').reduce(function (set, c) { set[c] = true; return set }, {})}
// normalizes slashes.var slashSplit = /\/+/;
minimatch.filter = filter;function filter (pattern, options) { options = options || {}; return function (p, i, list) { return minimatch(p, pattern, options) }}
function ext (a, b) { a = a || {}; b = b || {}; var t = {}; Object.keys(b).forEach(function (k) { t[k] = b[k]; }); Object.keys(a).forEach(function (k) { t[k] = a[k]; }); return t}
minimatch.defaults = function (def) { if (!def || !Object.keys(def).length) return minimatch
var orig = minimatch;
var m = function minimatch (p, pattern, options) { return orig.minimatch(p, pattern, ext(def, options)) };
m.Minimatch = function Minimatch (pattern, options) { return new orig.Minimatch(pattern, ext(def, options)) };
return m};
Minimatch.defaults = function (def) { if (!def || !Object.keys(def).length) return Minimatch return minimatch.defaults(def).Minimatch};
function minimatch (p, pattern, options) { if (typeof pattern !== 'string') { throw new TypeError('glob pattern string required') }
if (!options) options = {};
// shortcut: comments match nothing. if (!options.nocomment && pattern.charAt(0) === '#') { return false }
// "" only matches "" if (pattern.trim() === '') return p === ''
return new Minimatch(pattern, options).match(p)}
function Minimatch (pattern, options) { if (!(this instanceof Minimatch)) { return new Minimatch(pattern, options) }
if (typeof pattern !== 'string') { throw new TypeError('glob pattern string required') }
if (!options) options = {}; pattern = pattern.trim();
// windows support: need to use /, not \ if (path$1.sep !== '/') { pattern = pattern.split(path$1.sep).join('/'); }
this.options = options; this.set = []; this.pattern = pattern; this.regexp = null; this.negate = false; this.comment = false; this.empty = false;
// make the set of regexps etc. this.make();}
Minimatch.prototype.debug = function () {};
Minimatch.prototype.make = make;function make () { // don't do it more than once. if (this._made) return
var pattern = this.pattern; var options = this.options;
// empty patterns and comments match nothing. if (!options.nocomment && pattern.charAt(0) === '#') { this.comment = true; return } if (!pattern) { this.empty = true; return }
// step 1: figure out negation, etc. this.parseNegate();
// step 2: expand braces var set = this.globSet = this.braceExpand();
if (options.debug) this.debug = console.error;
this.debug(this.pattern, set);
// step 3: now we have a set, so turn each one into a series of path-portion // matching patterns. // These will be regexps, except in the case of "**", which is // set to the GLOBSTAR object for globstar behavior, // and will not contain any / characters set = this.globParts = set.map(function (s) { return s.split(slashSplit) });
this.debug(this.pattern, set);
// glob --> regexps set = set.map(function (s, si, set) { return s.map(this.parse, this) }, this);
this.debug(this.pattern, set);
// filter out everything that didn't compile properly. set = set.filter(function (s) { return s.indexOf(false) === -1 });
this.debug(this.pattern, set);
this.set = set;}
Minimatch.prototype.parseNegate = parseNegate;function parseNegate () { var pattern = this.pattern; var negate = false; var options = this.options; var negateOffset = 0;
if (options.nonegate) return
for (var i = 0, l = pattern.length ; i < l && pattern.charAt(i) === '!' ; i++) { negate = !negate; negateOffset++; }
if (negateOffset) this.pattern = pattern.substr(negateOffset); this.negate = negate;}
// Brace expansion:// a{b,c}d -> abd acd// a{b,}c -> abc ac// a{0..3}d -> a0d a1d a2d a3d// a{b,c{d,e}f}g -> abg acdfg acefg// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg//// Invalid sets are not expanded.// a{2..}b -> a{2..}b// a{b}c -> a{b}cminimatch.braceExpand = function (pattern, options) { return braceExpand(pattern, options)};
Minimatch.prototype.braceExpand = braceExpand;
function braceExpand (pattern, options) { if (!options) { if (this instanceof Minimatch) { options = this.options; } else { options = {}; } }
pattern = typeof pattern === 'undefined' ? this.pattern : pattern;
if (typeof pattern === 'undefined') { throw new TypeError('undefined pattern') }
if (options.nobrace || !pattern.match(/\{.*\}/)) { // shortcut. no need to expand. return [pattern] }
return braceExpansion(pattern)}
// parse a component of the expanded set.// At this point, no pattern may contain "/" in it// so we're going to return a 2d array, where each entry is the full// pattern, split on '/', and then turned into a regular expression.// A regexp is made at the end which joins each array with an// escaped /, and another full one which joins each regexp with |.//// Following the lead of Bash 4.1, note that "**" only has special meaning// when it is the *only* thing in a path portion. Otherwise, any series// of * is equivalent to a single *. Globstar behavior is enabled by// default, and can be disabled by setting options.noglobstar.Minimatch.prototype.parse = parse;var SUBPARSE = {};function parse (pattern, isSub) { if (pattern.length > 1024 * 64) { throw new TypeError('pattern is too long') }
var options = this.options;
// shortcuts if (!options.noglobstar && pattern === '**') return GLOBSTAR if (pattern === '') return ''
var re = ''; var hasMagic = !!options.nocase; var escaping = false; // ? => one single character var patternListStack = []; var negativeLists = []; var stateChar; var inClass = false; var reClassStart = -1; var classStart = -1; // . and .. never match anything that doesn't start with ., // even when options.dot is set. var patternStart = pattern.charAt(0) === '.' ? '' // anything // not (start or / followed by . or .. followed by / or end) : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))' : '(?!\\.)'; var self = this;
function clearStateChar () { if (stateChar) { // we had some state-tracking character // that wasn't consumed by this pass. switch (stateChar) { case '*': re += star; hasMagic = true; break case '?': re += qmark; hasMagic = true; break default: re += '\\' + stateChar; break } self.debug('clearStateChar %j %j', stateChar, re); stateChar = false; } }
for (var i = 0, len = pattern.length, c ; (i < len) && (c = pattern.charAt(i)) ; i++) { this.debug('%s\t%s %s %j', pattern, i, re, c);
// skip over any that are escaped. if (escaping && reSpecials[c]) { re += '\\' + c; escaping = false; continue }
switch (c) { case '/': // completely not allowed, even escaped. // Should already be path-split by now. return false
case '\\': clearStateChar(); escaping = true; continue
// the various stateChar values // for the "extglob" stuff. case '?': case '*': case '+': case '@': case '!': this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c);
// all of those are literals inside a class, except that // the glob [!a] means [^a] in regexp if (inClass) { this.debug(' in class'); if (c === '!' && i === classStart + 1) c = '^'; re += c; continue }
// if we already have a stateChar, then it means // that there was something like ** or +? in there. // Handle the stateChar, then proceed with this one. self.debug('call clearStateChar %j', stateChar); clearStateChar(); stateChar = c; // if extglob is disabled, then +(asdf|foo) isn't a thing. // just clear the statechar *now*, rather than even diving into // the patternList stuff. if (options.noext) clearStateChar(); continue
case '(': if (inClass) { re += '('; continue }
if (!stateChar) { re += '\\('; continue }
patternListStack.push({ type: stateChar, start: i - 1, reStart: re.length, open: plTypes[stateChar].open, close: plTypes[stateChar].close }); // negation is (?:(?!js)[^/]*) re += stateChar === '!' ? '(?:(?!(?:' : '(?:'; this.debug('plType %j %j', stateChar, re); stateChar = false; continue
case ')': if (inClass || !patternListStack.length) { re += '\\)'; continue }
clearStateChar(); hasMagic = true; var pl = patternListStack.pop(); // negation is (?:(?!js)[^/]*) // The others are (?:<pattern>)<type> re += pl.close; if (pl.type === '!') { negativeLists.push(pl); } pl.reEnd = re.length; continue
case '|': if (inClass || !patternListStack.length || escaping) { re += '\\|'; escaping = false; continue }
clearStateChar(); re += '|'; continue
// these are mostly the same in regexp and glob case '[': // swallow any state-tracking char before the [ clearStateChar();
if (inClass) { re += '\\' + c; continue }
inClass = true; classStart = i; reClassStart = re.length; re += c; continue
case ']': // 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 if (i === classStart + 1 || !inClass) { re += '\\' + c; escaping = false; continue }
// handle the case where we left a class open. // "[z-a]" is valid, equivalent to "\[z-a\]" if (inClass) { // split where the last [ was, make sure we don't have // an invalid re. if so, re-walk the contents of the // would-be class to re-translate any characters that // were passed through as-is // TODO: It would probably be faster to determine this // without a try/catch and a new RegExp, but it's tricky // to do safely. For now, this is safe and works. var cs = pattern.substring(classStart + 1, i); try { } catch (er) { // not a valid class! var sp = this.parse(cs, SUBPARSE); re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'; hasMagic = hasMagic || sp[1]; inClass = false; continue } }
// finish up the class. hasMagic = true; inClass = false; re += c; continue
default: // swallow any state char that wasn't consumed clearStateChar();
if (escaping) { // no need escaping = false; } else if (reSpecials[c] && !(c === '^' && inClass)) { re += '\\'; }
re += c;
} // switch } // for
// handle the case where we left a class open. // "[abc" is valid, equivalent to "\[abc" if (inClass) { // split where the last [ was, and escape it // this is a huge pita. We now have to re-walk // the contents of the would-be class to re-translate // any characters that were passed through as-is cs = pattern.substr(classStart + 1); sp = this.parse(cs, SUBPARSE); re = re.substr(0, reClassStart) + '\\[' + sp[0]; hasMagic = hasMagic || sp[1]; }
// handle the case where we had a +( thing at the *end* // of the pattern. // each pattern list stack adds 3 chars, and we need to go through // and escape any | chars that were passed through as-is for the regexp. // Go through and escape them, taking care not to double-escape any // | chars that were already escaped. for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { var tail = re.slice(pl.reStart + pl.open.length); this.debug('setting tail', re, pl); // maybe some even number of \, then maybe 1 \, followed by a | tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) { if (!$2) { // the | isn't already escaped, so escape it. $2 = '\\'; }
// need to escape all those slashes *again*, without escaping the // one that we need for escaping the | character. As it works out, // escaping an even number of slashes can be done by simply repeating // it exactly after itself. That's why this trick works. // // I am sorry that you have to see this. return $1 + $1 + $2 + '|' });
this.debug('tail=%j\n %s', tail, tail, pl, re); var t = pl.type === '*' ? star : pl.type === '?' ? qmark : '\\' + pl.type;
hasMagic = true; re = re.slice(0, pl.reStart) + t + '\\(' + tail; }
// handle trailing things that only matter at the very end. clearStateChar(); if (escaping) { // trailing \\ re += '\\\\'; }
// only need to apply the nodot start if the re starts with // something that could conceivably capture a dot var addPatternStart = false; switch (re.charAt(0)) { case '.': case '[': case '(': addPatternStart = true; }
// Hack to work around lack of negative lookbehind in JS // A pattern like: *.!(x).!(y|z) needs to ensure that a name // like 'a.xyz.yz' doesn't match. So, the first negative // lookahead, has to look ALL the way ahead, to the end of // the pattern. for (var n = negativeLists.length - 1; n > -1; n--) { var nl = negativeLists[n];
var nlBefore = re.slice(0, nl.reStart); var nlFirst = re.slice(nl.reStart, nl.reEnd - 8); var nlLast = re.slice(nl.reEnd - 8, nl.reEnd); var nlAfter = re.slice(nl.reEnd);
nlLast += nlAfter;
// Handle nested stuff like *(*.js|!(*.json)), where open parens // mean that we should *not* include the ) in the bit that is considered // "after" the negated section. var openParensBefore = nlBefore.split('(').length - 1; var cleanAfter = nlAfter; for (i = 0; i < openParensBefore; i++) { cleanAfter = cleanAfter.replace(/\)[+*?]?/, ''); } nlAfter = cleanAfter;
var dollar = ''; if (nlAfter === '' && isSub !== SUBPARSE) { dollar = '$'; } var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast; re = newRe; }
// if the re is not "" at this point, then we need to make sure // it doesn't match against an empty path part. // Otherwise a/* will match a/, which it should not. if (re !== '' && hasMagic) { re = '(?=.)' + re; }
if (addPatternStart) { re = patternStart + re; }
// parsing just a piece of a larger pattern. if (isSub === SUBPARSE) { return [re, hasMagic] }
// skip the regexp for non-magical patterns // unescape anything in it, though, so that it'll be // an exact match against a file etc. if (!hasMagic) { return globUnescape(pattern) }
var flags = options.nocase ? 'i' : ''; try { var regExp = new RegExp('^' + re + '$', flags); } catch (er) { // If it was an invalid regular expression, then it can't match // anything. This trick looks for a character after the end of // the string, which is of course impossible, except in multi-line // mode, but it's not a /m regex. return new RegExp('$.') }
regExp._glob = pattern; regExp._src = re;
return regExp}
minimatch.makeRe = function (pattern, options) { return new Minimatch(pattern, options || {}).makeRe()};
Minimatch.prototype.makeRe = makeRe;function makeRe () { if (this.regexp || this.regexp === false) return this.regexp
// at this point, this.set is a 2d array of partial // pattern strings, or "**". // // It's better to use .match(). This function shouldn't // be used, really, but it's pretty convenient sometimes, // when you just want to work with a regex. var set = this.set;
if (!set.length) { this.regexp = false; return this.regexp } var options = this.options;
var twoStar = options.noglobstar ? star : options.dot ? twoStarDot : twoStarNoDot; var flags = options.nocase ? 'i' : '';
var re = set.map(function (pattern) { return pattern.map(function (p) { return (p === GLOBSTAR) ? twoStar : (typeof p === 'string') ? regExpEscape(p) : p._src }).join('\\\/') }).join('|');
// must match entire pattern // ending in a * or ** will make it less strict. re = '^(?:' + re + ')$';
// can match anything, as long as it's not this. if (this.negate) re = '^(?!' + re + ').*$';
try { this.regexp = new RegExp(re, flags); } catch (ex) { this.regexp = false; } return this.regexp}
minimatch.match = function (list, pattern, options) { options = options || {}; var mm = new Minimatch(pattern, options); list = list.filter(function (f) { return mm.match(f) }); if (mm.options.nonull && !list.length) { list.push(pattern); } return list};
Minimatch.prototype.match = match;function match (f, partial) { this.debug('match', f, this.pattern); // short-circuit in the case of busted things. // comments, etc. if (this.comment) return false if (this.empty) return f === ''
if (f === '/' && partial) return true
var options = this.options;
// windows: need to use /, not \ if (path$1.sep !== '/') { f = f.split(path$1.sep).join('/'); }
// treat the test path as a set of pathparts. f = f.split(slashSplit); this.debug(this.pattern, 'split', f);
// just ONE of the pattern sets in this.set needs to match // in order for it to be valid. If negating, then just one // match means that we have failed. // Either way, return on the first hit.
var set = this.set; this.debug(this.pattern, 'set', set);
// Find the basename of the path by looking for the last non-empty segment var filename; var i; for (i = f.length - 1; i >= 0; i--) { filename = f[i]; if (filename) break }
for (i = 0; i < set.length; i++) { var pattern = set[i]; var file = f; if (options.matchBase && pattern.length === 1) { file = [filename]; } var hit = this.matchOne(file, pattern, partial); if (hit) { if (options.flipNegate) return true return !this.negate } }
// didn't get any hits. this is success if it's a negative // pattern, failure otherwise. if (options.flipNegate) return false return this.negate}
// set partial to true to test if, for example,// "/a/b" matches the start of "/*/b/*/d"// Partial means, if you run out of file before you run// out of pattern, then that's fine, as long as all// the parts match.Minimatch.prototype.matchOne = function (file, pattern, partial) { var options = this.options;
this.debug('matchOne', { 'this': this, file: file, pattern: pattern });
this.debug('matchOne', file.length, pattern.length);
for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length ; (fi < fl) && (pi < pl) ; fi++, pi++) { this.debug('matchOne loop'); var p = pattern[pi]; var f = file[fi];
this.debug(pattern, p, f);
// should be impossible. // some invalid regexp stuff in the set. if (p === false) return false
if (p === GLOBSTAR) { this.debug('GLOBSTAR', [pattern, p, f]);
// "**" // a/**/b/**/c would match the following: // a/b/x/y/z/c // a/x/y/z/b/c // a/b/x/b/x/c // a/b/c // To do this, take the rest of the pattern after // the **, and see if it would match the file remainder. // If so, return success. // If not, the ** "swallows" a segment, and try again. // This is recursively awful. // // a/**/b/**/c matching a/b/x/y/z/c // - a matches a // - doublestar // - matchOne(b/x/y/z/c, b/**/c) // - b matches b // - doublestar // - matchOne(x/y/z/c, c) -> no // - matchOne(y/z/c, c) -> no // - matchOne(z/c, c) -> no // - matchOne(c, c) yes, hit var fr = fi; var pr = pi + 1; if (pr === pl) { this.debug('** at the end'); // a ** at the end will just swallow the rest. // We have found a match. // however, it will not swallow /.x, unless // options.dot is set. // . and .. are *never* matched by **, for explosively // exponential reasons. for (; fi < fl; fi++) { if (file[fi] === '.' || file[fi] === '..' || (!options.dot && file[fi].charAt(0) === '.')) return false } return true }
// ok, let's see if we can swallow whatever we can. while (fr < fl) { var swallowee = file[fr];
this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
// XXX remove this slice. Just pass the start index. if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { this.debug('globstar found match!', fr, fl, swallowee); // found a match. return true } else { // can't swallow "." or ".." ever. // can only swallow ".foo" when explicitly asked. if (swallowee === '.' || swallowee === '..' || (!options.dot && swallowee.charAt(0) === '.')) { this.debug('dot detected!', file, fr, pattern, pr); break }
// ** swallows a segment, and continue. this.debug('globstar swallow a segment, and continue'); fr++; } }
// no match was found. // However, in partial mode, we can't say this is necessarily over. // If there's more *pattern* left, then if (partial) { // ran out of file this.debug('\n>>> no match, partial?', file, fr, pattern, pr); if (fr === fl) return true } return false }
// something other than ** // non-magic patterns just have to match exactly // patterns with magic have been turned into regexps. var hit; if (typeof p === 'string') { if (options.nocase) { hit = f.toLowerCase() === p.toLowerCase(); } else { hit = f === p; } this.debug('string match', p, f, hit); } else { hit = f.match(p); this.debug('pattern match', p, f, hit); }
if (!hit) return false }
// Note: ending in / means that we'll get a final "" // at the end of the pattern. This can only match a // corresponding "" at the end of the file. // If the file ends in /, then it can only match a // a pattern that ends in /, unless the pattern just // doesn't have any more for it. But, a/b/ should *not* // match "a/b/*", even though "" matches against the // [^/]*? pattern, except in partial mode, where it might // simply not be reached yet. // However, a/b/ should still satisfy a/*
// now either we fell off the end of the pattern, or we're done. if (fi === fl && pi === pl) { // ran out of pattern and filename at the same time. // an exact hit! return true } else if (fi === fl) { // ran out of file, but still had pattern left. // this is ok if we're doing the match as part of // a glob fs traversal. return partial } else if (pi === pl) { // ran out of pattern, still have file left. // this is only acceptable if we're on the very last // empty segment of a file with a trailing slash. // a/* should match a/b/ var emptyFileEnd = (fi === fl - 1) && (file[fi] === ''); return emptyFileEnd }
// should be unreachable. throw new Error('wtf?')};
// replace stuff like \* with *function globUnescape (s) { return s.replace(/\\(.)/g, '$1')}
function regExpEscape (s) { return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}
export default minimatch_1;