UNPKG

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