minimatch.js 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. module.exports = minimatch
  2. minimatch.Minimatch = Minimatch
  3. var path = (function () { try { return require('path') } catch (e) {}}()) || {
  4. sep: '/'
  5. }
  6. minimatch.sep = path.sep
  7. var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
  8. var expand = require('brace-expansion')
  9. var plTypes = {
  10. '!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
  11. '?': { open: '(?:', close: ')?' },
  12. '+': { open: '(?:', close: ')+' },
  13. '*': { open: '(?:', close: ')*' },
  14. '@': { open: '(?:', close: ')' }
  15. }
  16. // any single thing other than /
  17. // don't need to escape / when using new RegExp()
  18. var qmark = '[^/]'
  19. // * => any number of characters
  20. var star = qmark + '*?'
  21. // ** when dots are allowed. Anything goes, except .. and .
  22. // not (^ or / followed by one or two dots followed by $ or /),
  23. // followed by anything, any number of times.
  24. var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?'
  25. // not a ^ or / followed by a dot,
  26. // followed by anything, any number of times.
  27. var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?'
  28. // characters that need to be escaped in RegExp.
  29. var reSpecials = charSet('().*{}+?[]^$\\!')
  30. // "abc" -> { a:true, b:true, c:true }
  31. function charSet (s) {
  32. return s.split('').reduce(function (set, c) {
  33. set[c] = true
  34. return set
  35. }, {})
  36. }
  37. // normalizes slashes.
  38. var slashSplit = /\/+/
  39. minimatch.filter = filter
  40. function filter (pattern, options) {
  41. options = options || {}
  42. return function (p, i, list) {
  43. return minimatch(p, pattern, options)
  44. }
  45. }
  46. function ext (a, b) {
  47. b = b || {}
  48. var t = {}
  49. Object.keys(a).forEach(function (k) {
  50. t[k] = a[k]
  51. })
  52. Object.keys(b).forEach(function (k) {
  53. t[k] = b[k]
  54. })
  55. return t
  56. }
  57. minimatch.defaults = function (def) {
  58. if (!def || typeof def !== 'object' || !Object.keys(def).length) {
  59. return minimatch
  60. }
  61. var orig = minimatch
  62. var m = function minimatch (p, pattern, options) {
  63. return orig(p, pattern, ext(def, options))
  64. }
  65. m.Minimatch = function Minimatch (pattern, options) {
  66. return new orig.Minimatch(pattern, ext(def, options))
  67. }
  68. m.Minimatch.defaults = function defaults (options) {
  69. return orig.defaults(ext(def, options)).Minimatch
  70. }
  71. m.filter = function filter (pattern, options) {
  72. return orig.filter(pattern, ext(def, options))
  73. }
  74. m.defaults = function defaults (options) {
  75. return orig.defaults(ext(def, options))
  76. }
  77. m.makeRe = function makeRe (pattern, options) {
  78. return orig.makeRe(pattern, ext(def, options))
  79. }
  80. m.braceExpand = function braceExpand (pattern, options) {
  81. return orig.braceExpand(pattern, ext(def, options))
  82. }
  83. m.match = function (list, pattern, options) {
  84. return orig.match(list, pattern, ext(def, options))
  85. }
  86. return m
  87. }
  88. Minimatch.defaults = function (def) {
  89. return minimatch.defaults(def).Minimatch
  90. }
  91. function minimatch (p, pattern, options) {
  92. assertValidPattern(pattern)
  93. if (!options) options = {}
  94. // shortcut: comments match nothing.
  95. if (!options.nocomment && pattern.charAt(0) === '#') {
  96. return false
  97. }
  98. return new Minimatch(pattern, options).match(p)
  99. }
  100. function Minimatch (pattern, options) {
  101. if (!(this instanceof Minimatch)) {
  102. return new Minimatch(pattern, options)
  103. }
  104. assertValidPattern(pattern)
  105. if (!options) options = {}
  106. pattern = pattern.trim()
  107. // windows support: need to use /, not \
  108. if (!options.allowWindowsEscape && path.sep !== '/') {
  109. pattern = pattern.split(path.sep).join('/')
  110. }
  111. this.options = options
  112. this.maxGlobstarRecursion = options.maxGlobstarRecursion !== undefined
  113. ? options.maxGlobstarRecursion : 200
  114. this.set = []
  115. this.pattern = pattern
  116. this.regexp = null
  117. this.negate = false
  118. this.comment = false
  119. this.empty = false
  120. this.partial = !!options.partial
  121. // make the set of regexps etc.
  122. this.make()
  123. }
  124. Minimatch.prototype.debug = function () {}
  125. Minimatch.prototype.make = make
  126. function make () {
  127. var pattern = this.pattern
  128. var options = this.options
  129. // empty patterns and comments match nothing.
  130. if (!options.nocomment && pattern.charAt(0) === '#') {
  131. this.comment = true
  132. return
  133. }
  134. if (!pattern) {
  135. this.empty = true
  136. return
  137. }
  138. // step 1: figure out negation, etc.
  139. this.parseNegate()
  140. // step 2: expand braces
  141. var set = this.globSet = this.braceExpand()
  142. if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
  143. this.debug(this.pattern, set)
  144. // step 3: now we have a set, so turn each one into a series of path-portion
  145. // matching patterns.
  146. // These will be regexps, except in the case of "**", which is
  147. // set to the GLOBSTAR object for globstar behavior,
  148. // and will not contain any / characters
  149. set = this.globParts = set.map(function (s) {
  150. return s.split(slashSplit)
  151. })
  152. this.debug(this.pattern, set)
  153. // glob --> regexps
  154. set = set.map(function (s, si, set) {
  155. return s.map(this.parse, this)
  156. }, this)
  157. this.debug(this.pattern, set)
  158. // filter out everything that didn't compile properly.
  159. set = set.filter(function (s) {
  160. return s.indexOf(false) === -1
  161. })
  162. this.debug(this.pattern, set)
  163. this.set = set
  164. }
  165. Minimatch.prototype.parseNegate = parseNegate
  166. function parseNegate () {
  167. var pattern = this.pattern
  168. var negate = false
  169. var options = this.options
  170. var negateOffset = 0
  171. if (options.nonegate) return
  172. for (var i = 0, l = pattern.length
  173. ; i < l && pattern.charAt(i) === '!'
  174. ; i++) {
  175. negate = !negate
  176. negateOffset++
  177. }
  178. if (negateOffset) this.pattern = pattern.substr(negateOffset)
  179. this.negate = negate
  180. }
  181. // Brace expansion:
  182. // a{b,c}d -> abd acd
  183. // a{b,}c -> abc ac
  184. // a{0..3}d -> a0d a1d a2d a3d
  185. // a{b,c{d,e}f}g -> abg acdfg acefg
  186. // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
  187. //
  188. // Invalid sets are not expanded.
  189. // a{2..}b -> a{2..}b
  190. // a{b}c -> a{b}c
  191. minimatch.braceExpand = function (pattern, options) {
  192. return braceExpand(pattern, options)
  193. }
  194. Minimatch.prototype.braceExpand = braceExpand
  195. function braceExpand (pattern, options) {
  196. if (!options) {
  197. if (this instanceof Minimatch) {
  198. options = this.options
  199. } else {
  200. options = {}
  201. }
  202. }
  203. pattern = typeof pattern === 'undefined'
  204. ? this.pattern : pattern
  205. assertValidPattern(pattern)
  206. // Thanks to Yeting Li <https://github.com/yetingli> for
  207. // improving this regexp to avoid a ReDOS vulnerability.
  208. if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
  209. // shortcut. no need to expand.
  210. return [pattern]
  211. }
  212. return expand(pattern)
  213. }
  214. var MAX_PATTERN_LENGTH = 1024 * 64
  215. var assertValidPattern = function (pattern) {
  216. if (typeof pattern !== 'string') {
  217. throw new TypeError('invalid pattern')
  218. }
  219. if (pattern.length > MAX_PATTERN_LENGTH) {
  220. throw new TypeError('pattern is too long')
  221. }
  222. }
  223. // parse a component of the expanded set.
  224. // At this point, no pattern may contain "/" in it
  225. // so we're going to return a 2d array, where each entry is the full
  226. // pattern, split on '/', and then turned into a regular expression.
  227. // A regexp is made at the end which joins each array with an
  228. // escaped /, and another full one which joins each regexp with |.
  229. //
  230. // Following the lead of Bash 4.1, note that "**" only has special meaning
  231. // when it is the *only* thing in a path portion. Otherwise, any series
  232. // of * is equivalent to a single *. Globstar behavior is enabled by
  233. // default, and can be disabled by setting options.noglobstar.
  234. Minimatch.prototype.parse = parse
  235. var SUBPARSE = {}
  236. function parse (pattern, isSub) {
  237. assertValidPattern(pattern)
  238. var options = this.options
  239. // shortcuts
  240. if (pattern === '**') {
  241. if (!options.noglobstar)
  242. return GLOBSTAR
  243. else
  244. pattern = '*'
  245. }
  246. if (pattern === '') return ''
  247. var re = ''
  248. var hasMagic = !!options.nocase
  249. var escaping = false
  250. // ? => one single character
  251. var patternListStack = []
  252. var negativeLists = []
  253. var stateChar
  254. var inClass = false
  255. var reClassStart = -1
  256. var classStart = -1
  257. // . and .. never match anything that doesn't start with .,
  258. // even when options.dot is set.
  259. var patternStart = pattern.charAt(0) === '.' ? '' // anything
  260. // not (start or / followed by . or .. followed by / or end)
  261. : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))'
  262. : '(?!\\.)'
  263. var self = this
  264. function clearStateChar () {
  265. if (stateChar) {
  266. // we had some state-tracking character
  267. // that wasn't consumed by this pass.
  268. switch (stateChar) {
  269. case '*':
  270. re += star
  271. hasMagic = true
  272. break
  273. case '?':
  274. re += qmark
  275. hasMagic = true
  276. break
  277. default:
  278. re += '\\' + stateChar
  279. break
  280. }
  281. self.debug('clearStateChar %j %j', stateChar, re)
  282. stateChar = false
  283. }
  284. }
  285. for (var i = 0, len = pattern.length, c
  286. ; (i < len) && (c = pattern.charAt(i))
  287. ; i++) {
  288. this.debug('%s\t%s %s %j', pattern, i, re, c)
  289. // skip over any that are escaped.
  290. if (escaping && reSpecials[c]) {
  291. re += '\\' + c
  292. escaping = false
  293. continue
  294. }
  295. switch (c) {
  296. /* istanbul ignore next */
  297. case '/': {
  298. // completely not allowed, even escaped.
  299. // Should already be path-split by now.
  300. return false
  301. }
  302. case '\\':
  303. clearStateChar()
  304. escaping = true
  305. continue
  306. // the various stateChar values
  307. // for the "extglob" stuff.
  308. case '?':
  309. case '*':
  310. case '+':
  311. case '@':
  312. case '!':
  313. this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c)
  314. // all of those are literals inside a class, except that
  315. // the glob [!a] means [^a] in regexp
  316. if (inClass) {
  317. this.debug(' in class')
  318. if (c === '!' && i === classStart + 1) c = '^'
  319. re += c
  320. continue
  321. }
  322. // coalesce consecutive non-globstar * characters
  323. if (c === '*' && stateChar === '*') continue
  324. // if we already have a stateChar, then it means
  325. // that there was something like ** or +? in there.
  326. // Handle the stateChar, then proceed with this one.
  327. self.debug('call clearStateChar %j', stateChar)
  328. clearStateChar()
  329. stateChar = c
  330. // if extglob is disabled, then +(asdf|foo) isn't a thing.
  331. // just clear the statechar *now*, rather than even diving into
  332. // the patternList stuff.
  333. if (options.noext) clearStateChar()
  334. continue
  335. case '(':
  336. if (inClass) {
  337. re += '('
  338. continue
  339. }
  340. if (!stateChar) {
  341. re += '\\('
  342. continue
  343. }
  344. patternListStack.push({
  345. type: stateChar,
  346. start: i - 1,
  347. reStart: re.length,
  348. open: plTypes[stateChar].open,
  349. close: plTypes[stateChar].close
  350. })
  351. // negation is (?:(?!js)[^/]*)
  352. re += stateChar === '!' ? '(?:(?!(?:' : '(?:'
  353. this.debug('plType %j %j', stateChar, re)
  354. stateChar = false
  355. continue
  356. case ')':
  357. if (inClass || !patternListStack.length) {
  358. re += '\\)'
  359. continue
  360. }
  361. clearStateChar()
  362. hasMagic = true
  363. var pl = patternListStack.pop()
  364. // negation is (?:(?!js)[^/]*)
  365. // The others are (?:<pattern>)<type>
  366. re += pl.close
  367. if (pl.type === '!') {
  368. negativeLists.push(pl)
  369. }
  370. pl.reEnd = re.length
  371. continue
  372. case '|':
  373. if (inClass || !patternListStack.length || escaping) {
  374. re += '\\|'
  375. escaping = false
  376. continue
  377. }
  378. clearStateChar()
  379. re += '|'
  380. continue
  381. // these are mostly the same in regexp and glob
  382. case '[':
  383. // swallow any state-tracking char before the [
  384. clearStateChar()
  385. if (inClass) {
  386. re += '\\' + c
  387. continue
  388. }
  389. inClass = true
  390. classStart = i
  391. reClassStart = re.length
  392. re += c
  393. continue
  394. case ']':
  395. // a right bracket shall lose its special
  396. // meaning and represent itself in
  397. // a bracket expression if it occurs
  398. // first in the list. -- POSIX.2 2.8.3.2
  399. if (i === classStart + 1 || !inClass) {
  400. re += '\\' + c
  401. escaping = false
  402. continue
  403. }
  404. // handle the case where we left a class open.
  405. // "[z-a]" is valid, equivalent to "\[z-a\]"
  406. // split where the last [ was, make sure we don't have
  407. // an invalid re. if so, re-walk the contents of the
  408. // would-be class to re-translate any characters that
  409. // were passed through as-is
  410. // TODO: It would probably be faster to determine this
  411. // without a try/catch and a new RegExp, but it's tricky
  412. // to do safely. For now, this is safe and works.
  413. var cs = pattern.substring(classStart + 1, i)
  414. try {
  415. RegExp('[' + cs + ']')
  416. } catch (er) {
  417. // not a valid class!
  418. var sp = this.parse(cs, SUBPARSE)
  419. re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
  420. hasMagic = hasMagic || sp[1]
  421. inClass = false
  422. continue
  423. }
  424. // finish up the class.
  425. hasMagic = true
  426. inClass = false
  427. re += c
  428. continue
  429. default:
  430. // swallow any state char that wasn't consumed
  431. clearStateChar()
  432. if (escaping) {
  433. // no need
  434. escaping = false
  435. } else if (reSpecials[c]
  436. && !(c === '^' && inClass)) {
  437. re += '\\'
  438. }
  439. re += c
  440. } // switch
  441. } // for
  442. // handle the case where we left a class open.
  443. // "[abc" is valid, equivalent to "\[abc"
  444. if (inClass) {
  445. // split where the last [ was, and escape it
  446. // this is a huge pita. We now have to re-walk
  447. // the contents of the would-be class to re-translate
  448. // any characters that were passed through as-is
  449. cs = pattern.substr(classStart + 1)
  450. sp = this.parse(cs, SUBPARSE)
  451. re = re.substr(0, reClassStart) + '\\[' + sp[0]
  452. hasMagic = hasMagic || sp[1]
  453. }
  454. // handle the case where we had a +( thing at the *end*
  455. // of the pattern.
  456. // each pattern list stack adds 3 chars, and we need to go through
  457. // and escape any | chars that were passed through as-is for the regexp.
  458. // Go through and escape them, taking care not to double-escape any
  459. // | chars that were already escaped.
  460. for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
  461. var tail = re.slice(pl.reStart + pl.open.length)
  462. this.debug('setting tail', re, pl)
  463. // maybe some even number of \, then maybe 1 \, followed by a |
  464. tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) {
  465. if (!$2) {
  466. // the | isn't already escaped, so escape it.
  467. $2 = '\\'
  468. }
  469. // need to escape all those slashes *again*, without escaping the
  470. // one that we need for escaping the | character. As it works out,
  471. // escaping an even number of slashes can be done by simply repeating
  472. // it exactly after itself. That's why this trick works.
  473. //
  474. // I am sorry that you have to see this.
  475. return $1 + $1 + $2 + '|'
  476. })
  477. this.debug('tail=%j\n %s', tail, tail, pl, re)
  478. var t = pl.type === '*' ? star
  479. : pl.type === '?' ? qmark
  480. : '\\' + pl.type
  481. hasMagic = true
  482. re = re.slice(0, pl.reStart) + t + '\\(' + tail
  483. }
  484. // handle trailing things that only matter at the very end.
  485. clearStateChar()
  486. if (escaping) {
  487. // trailing \\
  488. re += '\\\\'
  489. }
  490. // only need to apply the nodot start if the re starts with
  491. // something that could conceivably capture a dot
  492. var addPatternStart = false
  493. switch (re.charAt(0)) {
  494. case '[': case '.': case '(': addPatternStart = true
  495. }
  496. // Hack to work around lack of negative lookbehind in JS
  497. // A pattern like: *.!(x).!(y|z) needs to ensure that a name
  498. // like 'a.xyz.yz' doesn't match. So, the first negative
  499. // lookahead, has to look ALL the way ahead, to the end of
  500. // the pattern.
  501. for (var n = negativeLists.length - 1; n > -1; n--) {
  502. var nl = negativeLists[n]
  503. var nlBefore = re.slice(0, nl.reStart)
  504. var nlFirst = re.slice(nl.reStart, nl.reEnd - 8)
  505. var nlLast = re.slice(nl.reEnd - 8, nl.reEnd)
  506. var nlAfter = re.slice(nl.reEnd)
  507. nlLast += nlAfter
  508. // Handle nested stuff like *(*.js|!(*.json)), where open parens
  509. // mean that we should *not* include the ) in the bit that is considered
  510. // "after" the negated section.
  511. var openParensBefore = nlBefore.split('(').length - 1
  512. var cleanAfter = nlAfter
  513. for (i = 0; i < openParensBefore; i++) {
  514. cleanAfter = cleanAfter.replace(/\)[+*?]?/, '')
  515. }
  516. nlAfter = cleanAfter
  517. var dollar = ''
  518. if (nlAfter === '' && isSub !== SUBPARSE) {
  519. dollar = '$'
  520. }
  521. var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast
  522. re = newRe
  523. }
  524. // if the re is not "" at this point, then we need to make sure
  525. // it doesn't match against an empty path part.
  526. // Otherwise a/* will match a/, which it should not.
  527. if (re !== '' && hasMagic) {
  528. re = '(?=.)' + re
  529. }
  530. if (addPatternStart) {
  531. re = patternStart + re
  532. }
  533. // parsing just a piece of a larger pattern.
  534. if (isSub === SUBPARSE) {
  535. return [re, hasMagic]
  536. }
  537. // skip the regexp for non-magical patterns
  538. // unescape anything in it, though, so that it'll be
  539. // an exact match against a file etc.
  540. if (!hasMagic) {
  541. return globUnescape(pattern)
  542. }
  543. var flags = options.nocase ? 'i' : ''
  544. try {
  545. var regExp = new RegExp('^' + re + '$', flags)
  546. } catch (er) /* istanbul ignore next - should be impossible */ {
  547. // If it was an invalid regular expression, then it can't match
  548. // anything. This trick looks for a character after the end of
  549. // the string, which is of course impossible, except in multi-line
  550. // mode, but it's not a /m regex.
  551. return new RegExp('$.')
  552. }
  553. regExp._glob = pattern
  554. regExp._src = re
  555. return regExp
  556. }
  557. minimatch.makeRe = function (pattern, options) {
  558. return new Minimatch(pattern, options || {}).makeRe()
  559. }
  560. Minimatch.prototype.makeRe = makeRe
  561. function makeRe () {
  562. if (this.regexp || this.regexp === false) return this.regexp
  563. // at this point, this.set is a 2d array of partial
  564. // pattern strings, or "**".
  565. //
  566. // It's better to use .match(). This function shouldn't
  567. // be used, really, but it's pretty convenient sometimes,
  568. // when you just want to work with a regex.
  569. var set = this.set
  570. if (!set.length) {
  571. this.regexp = false
  572. return this.regexp
  573. }
  574. var options = this.options
  575. var twoStar = options.noglobstar ? star
  576. : options.dot ? twoStarDot
  577. : twoStarNoDot
  578. var flags = options.nocase ? 'i' : ''
  579. var re = set.map(function (pattern) {
  580. return pattern.map(function (p) {
  581. return (p === GLOBSTAR) ? twoStar
  582. : (typeof p === 'string') ? regExpEscape(p)
  583. : p._src
  584. }).join('\\\/')
  585. }).join('|')
  586. // must match entire pattern
  587. // ending in a * or ** will make it less strict.
  588. re = '^(?:' + re + ')$'
  589. // can match anything, as long as it's not this.
  590. if (this.negate) re = '^(?!' + re + ').*$'
  591. try {
  592. this.regexp = new RegExp(re, flags)
  593. } catch (ex) /* istanbul ignore next - should be impossible */ {
  594. this.regexp = false
  595. }
  596. return this.regexp
  597. }
  598. minimatch.match = function (list, pattern, options) {
  599. options = options || {}
  600. var mm = new Minimatch(pattern, options)
  601. list = list.filter(function (f) {
  602. return mm.match(f)
  603. })
  604. if (mm.options.nonull && !list.length) {
  605. list.push(pattern)
  606. }
  607. return list
  608. }
  609. Minimatch.prototype.match = function match (f, partial) {
  610. if (typeof partial === 'undefined') partial = this.partial
  611. this.debug('match', f, this.pattern)
  612. // short-circuit in the case of busted things.
  613. // comments, etc.
  614. if (this.comment) return false
  615. if (this.empty) return f === ''
  616. if (f === '/' && partial) return true
  617. var options = this.options
  618. // windows: need to use /, not \
  619. if (path.sep !== '/') {
  620. f = f.split(path.sep).join('/')
  621. }
  622. // treat the test path as a set of pathparts.
  623. f = f.split(slashSplit)
  624. this.debug(this.pattern, 'split', f)
  625. // just ONE of the pattern sets in this.set needs to match
  626. // in order for it to be valid. If negating, then just one
  627. // match means that we have failed.
  628. // Either way, return on the first hit.
  629. var set = this.set
  630. this.debug(this.pattern, 'set', set)
  631. // Find the basename of the path by looking for the last non-empty segment
  632. var filename
  633. var i
  634. for (i = f.length - 1; i >= 0; i--) {
  635. filename = f[i]
  636. if (filename) break
  637. }
  638. for (i = 0; i < set.length; i++) {
  639. var pattern = set[i]
  640. var file = f
  641. if (options.matchBase && pattern.length === 1) {
  642. file = [filename]
  643. }
  644. var hit = this.matchOne(file, pattern, partial)
  645. if (hit) {
  646. if (options.flipNegate) return true
  647. return !this.negate
  648. }
  649. }
  650. // didn't get any hits. this is success if it's a negative
  651. // pattern, failure otherwise.
  652. if (options.flipNegate) return false
  653. return this.negate
  654. }
  655. // set partial to true to test if, for example,
  656. // "/a/b" matches the start of "/*/b/*/d"
  657. // Partial means, if you run out of file before you run
  658. // out of pattern, then that's fine, as long as all
  659. // the parts match.
  660. Minimatch.prototype.matchOne = function (file, pattern, partial) {
  661. if (pattern.indexOf(GLOBSTAR) !== -1) {
  662. return this._matchGlobstar(file, pattern, partial, 0, 0)
  663. }
  664. return this._matchOne(file, pattern, partial, 0, 0)
  665. }
  666. Minimatch.prototype._matchGlobstar = function (file, pattern, partial, fileIndex, patternIndex) {
  667. var i
  668. // find first globstar from patternIndex
  669. var firstgs = -1
  670. for (i = patternIndex; i < pattern.length; i++) {
  671. if (pattern[i] === GLOBSTAR) { firstgs = i; break }
  672. }
  673. // find last globstar
  674. var lastgs = -1
  675. for (i = pattern.length - 1; i >= 0; i--) {
  676. if (pattern[i] === GLOBSTAR) { lastgs = i; break }
  677. }
  678. var head = pattern.slice(patternIndex, firstgs)
  679. var body = partial ? pattern.slice(firstgs + 1) : pattern.slice(firstgs + 1, lastgs)
  680. var tail = partial ? [] : pattern.slice(lastgs + 1)
  681. // check the head
  682. if (head.length) {
  683. var fileHead = file.slice(fileIndex, fileIndex + head.length)
  684. if (!this._matchOne(fileHead, head, partial, 0, 0)) {
  685. return false
  686. }
  687. fileIndex += head.length
  688. }
  689. // check the tail
  690. var fileTailMatch = 0
  691. if (tail.length) {
  692. if (tail.length + fileIndex > file.length) return false
  693. var tailStart = file.length - tail.length
  694. if (this._matchOne(file, tail, partial, tailStart, 0)) {
  695. fileTailMatch = tail.length
  696. } else {
  697. // affordance for stuff like a/**/* matching a/b/
  698. if (file[file.length - 1] !== '' ||
  699. fileIndex + tail.length === file.length) {
  700. return false
  701. }
  702. tailStart--
  703. if (!this._matchOne(file, tail, partial, tailStart, 0)) {
  704. return false
  705. }
  706. fileTailMatch = tail.length + 1
  707. }
  708. }
  709. // if body is empty (single ** between head and tail)
  710. if (!body.length) {
  711. var sawSome = !!fileTailMatch
  712. for (i = fileIndex; i < file.length - fileTailMatch; i++) {
  713. var f = String(file[i])
  714. sawSome = true
  715. if (f === '.' || f === '..' ||
  716. (!this.options.dot && f.charAt(0) === '.')) {
  717. return false
  718. }
  719. }
  720. return partial || sawSome
  721. }
  722. // split body into segments at each GLOBSTAR
  723. var bodySegments = [[[], 0]]
  724. var currentBody = bodySegments[0]
  725. var nonGsParts = 0
  726. var nonGsPartsSums = [0]
  727. for (var bi = 0; bi < body.length; bi++) {
  728. var b = body[bi]
  729. if (b === GLOBSTAR) {
  730. nonGsPartsSums.push(nonGsParts)
  731. currentBody = [[], 0]
  732. bodySegments.push(currentBody)
  733. } else {
  734. currentBody[0].push(b)
  735. nonGsParts++
  736. }
  737. }
  738. var idx = bodySegments.length - 1
  739. var fileLength = file.length - fileTailMatch
  740. for (var si = 0; si < bodySegments.length; si++) {
  741. bodySegments[si][1] = fileLength -
  742. (nonGsPartsSums[idx--] + bodySegments[si][0].length)
  743. }
  744. return !!this._matchGlobStarBodySections(
  745. file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch
  746. )
  747. }
  748. // return false for "nope, not matching"
  749. // return null for "not matching, cannot keep trying"
  750. Minimatch.prototype._matchGlobStarBodySections = function (
  751. file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail
  752. ) {
  753. var bs = bodySegments[bodyIndex]
  754. if (!bs) {
  755. // just make sure there are no bad dots
  756. for (var i = fileIndex; i < file.length; i++) {
  757. sawTail = true
  758. var f = file[i]
  759. if (f === '.' || f === '..' ||
  760. (!this.options.dot && f.charAt(0) === '.')) {
  761. return false
  762. }
  763. }
  764. return sawTail
  765. }
  766. var body = bs[0]
  767. var after = bs[1]
  768. while (fileIndex <= after) {
  769. var m = this._matchOne(
  770. file.slice(0, fileIndex + body.length),
  771. body,
  772. partial,
  773. fileIndex,
  774. 0
  775. )
  776. // if limit exceeded, no match. intentional false negative,
  777. // acceptable break in correctness for security.
  778. if (m && globStarDepth < this.maxGlobstarRecursion) {
  779. var sub = this._matchGlobStarBodySections(
  780. file, bodySegments,
  781. fileIndex + body.length, bodyIndex + 1,
  782. partial, globStarDepth + 1, sawTail
  783. )
  784. if (sub !== false) {
  785. return sub
  786. }
  787. }
  788. var f = file[fileIndex]
  789. if (f === '.' || f === '..' ||
  790. (!this.options.dot && f.charAt(0) === '.')) {
  791. return false
  792. }
  793. fileIndex++
  794. }
  795. return partial || null
  796. }
  797. Minimatch.prototype._matchOne = function (file, pattern, partial, fileIndex, patternIndex) {
  798. var fi, pi, fl, pl
  799. for (
  800. fi = fileIndex, pi = patternIndex, fl = file.length, pl = pattern.length
  801. ; (fi < fl) && (pi < pl)
  802. ; fi++, pi++
  803. ) {
  804. this.debug('matchOne loop')
  805. var p = pattern[pi]
  806. var f = file[fi]
  807. this.debug(pattern, p, f)
  808. // should be impossible.
  809. // some invalid regexp stuff in the set.
  810. /* istanbul ignore if */
  811. if (p === false || p === GLOBSTAR) return false
  812. // something other than **
  813. // non-magic patterns just have to match exactly
  814. // patterns with magic have been turned into regexps.
  815. var hit
  816. if (typeof p === 'string') {
  817. hit = f === p
  818. this.debug('string match', p, f, hit)
  819. } else {
  820. hit = f.match(p)
  821. this.debug('pattern match', p, f, hit)
  822. }
  823. if (!hit) return false
  824. }
  825. // now either we fell off the end of the pattern, or we're done.
  826. if (fi === fl && pi === pl) {
  827. // ran out of pattern and filename at the same time.
  828. // an exact hit!
  829. return true
  830. } else if (fi === fl) {
  831. // ran out of file, but still had pattern left.
  832. // this is ok if we're doing the match as part of
  833. // a glob fs traversal.
  834. return partial
  835. } else /* istanbul ignore else */ if (pi === pl) {
  836. // ran out of pattern, still have file left.
  837. // this is only acceptable if we're on the very last
  838. // empty segment of a file with a trailing slash.
  839. // a/* should match a/b/
  840. return (fi === fl - 1) && (file[fi] === '')
  841. }
  842. // should be unreachable.
  843. /* istanbul ignore next */
  844. throw new Error('wtf?')
  845. }
  846. // replace stuff like \* with *
  847. function globUnescape (s) {
  848. return s.replace(/\\(.)/g, '$1')
  849. }
  850. function regExpEscape (s) {
  851. return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
  852. }