source: imaps-frontend/node_modules/minimatch/minimatch.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

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