module.exports = minimatch
var path = require("path")
, LRU = require("lru-cache")
minimatch.filter = function (pattern, options) {
options = options || {}
return function (p, i, list) {
return minimatch(p, pattern, options)
}
}
minimatch.match = function (list, pattern, options) {
if (!options) options = {}
var ret = list.filter(minimatch.filter(pattern, options))
if (options.debug) console.error("\nmatch: %s %j %j", pattern, list, ret)
if (!options.null && !ret.length) {
return [pattern]
}
return ret
}
function minimatch (p, pattern, options) {
if (typeof pattern !== "string") {
throw new TypeError("glob pattern string required")
}
options = options || {}
var cache = options.cache || minimatch.cache
if (!cache) cache = minimatch.cache = new LRU(1000)
if (!pattern) return p === ""
if (pattern.trim().charAt(0) === "#") return false
var re = cache.get(pattern + "\n" + JSON.stringify(options))
if (!re && re !== false) {
cache.set(pattern, re = minimatch.makeRe(pattern, options))
}
if (options.debug) {
console.error(pattern + "\t" + re, JSON.stringify(p))
}
if (!re) return false
var match =
( ( options.slash ||
p.substr(-1) !== "/" ||
pattern.substr(-1) === "/" )
&& !!p.match(re) )
|| ( p.substr(-1) === "/" &&
!!p.slice(0, -1).match(re) )
|| ( options.matchBase &&
pattern.indexOf("/") === -1 &&
path.basename(p).match(re) )
return match
}
minimatch.makeRe = makeRe
function makeRe (pattern, options) {
options = options || {}
function clearStateChar () {
if (stateChar) {
switch (stateChar) {
case "*":
re += oneStar
break
case "?":
re += "."
break
default:
re += "\\"+stateChar
break
}
stateChar = false
}
}
var braceDepth = 0
, re = ""
, escaping = false
, oneStar = options.dot ? "[^\\/]*?"
: "(?:(?!(?:\\\/|^)\\.)[^\\/])*?"
, twoStar = options.dot ? ".*?"
: "(?:(?!(?:\\\/|^)\\.).)*?"
, reSpecials = "().*{}+?[]^$/\\"
, patternListStack = []
, stateChar
, negate = false
, negating = false
, inClass = false
, reClassStart = -1
, classStart = -1
, classStartPattern = options.dot ? ""
: "(?:(?!(?:\\\/|^)\\.)"
, classEndPattern = options.dot ? "" : ")"
for ( var i = 0, len = pattern.length, c
; (i < len) && (c = pattern.charAt(i))
; i ++ ) {
if (options.debug) {
console.error("%s\t%s %s %j", pattern, i, re, c)
}
switch (c) {
case "\\":
if (stateChar) {
if (stateChar === "*") re += oneStar
else re += "\\" + stateChar
stateChar = false
}
if (escaping) {
re += "\\\\"
escaping = false
} else {
escaping = true
}
continue
case "!":
if (i === 0 || negating) {
negate = !negate
negating = true
break
} else {
negating = false
}
case "+":
case "@":
case "*":
case "?":
if (options.debug) {
console.error("%s\t%s %s %j <-- stateChar", pattern, i, re, c)
}
negating = false
if (escaping) {
re += "\\" + c
escaping = false
} else if (inClass) {
re += c
} else if (c === "*" && stateChar === "*") {
re += twoStar
stateChar = false
} else {
if (stateChar) {
if (stateChar === "*") re += oneStar
else if (stateChar === "?") re += "."
else re += "\\" + stateChar
}
stateChar = c
}
continue
case "(":
if (escaping) {
re += "\\("
escaping = false
} else if (inClass) {
re += "("
} else if (stateChar) {
plType = stateChar
patternListStack.push(plType)
re += stateChar === "!" ? "(?!" : "(?:"
stateChar = false
} else {
re += "\\("
}
continue
case ")":
if (escaping || inClass) {
re += "\\)"
escaping = false
} else if (patternListStack.length) {
re += ")"
plType = patternListStack.pop()
switch (plType) {
case "?":
case "+":
case "*": re += plType
case "!":
case "@": break
}
} else {
re += "\\)"
}
continue
case "|":
if (escaping || inClass) {
re += "\\|"
escaping = false
} else if (patternListStack.length) {
re += "|"
} else {
re += "\\|"
}
continue
case "[":
clearStateChar()
if (escaping || inClass) {
re += "\\" + c
escaping = false
} else {
inClass = true
classStart = i
reClassStart = re.length
re += classStartPattern
re += c
}
continue
case "]":
if (i === classStart + 1) escaping = true
if (escaping || !inClass) {
re += "\\" + c
escaping = false
} else {
inClass = false
re += c + classEndPattern
}
continue
case "{":
if (escaping || inClass) {
re += "\\{"
escaping = false
} else {
re += "(?:"
braceDepth ++
}
continue
case "}":
if (escaping || inClass || braceDepth === 0) {
re += "\\}"
escaping = false
} else {
clearStateChar()
re += ")"
braceDepth --
}
continue
case ",":
if (escaping || inClass || braceDepth === 0) {
re += ","
escaping = false
} else {
clearStateChar()
re += "|"
}
continue
default:
clearStateChar()
if (escaping) {
escaping = false
} else if (reSpecials.indexOf(c) !== -1
&& !(c === "^" && inClass)) {
re += "\\"
}
re += c
}
if (negating && c !== "!") negating = false
}
if (stateChar) {
clearStateChar()
} else if (escaping) {
re += "\\\\"
}
if (inClass) {
var cs = re.substr(reClassStart + classStartPattern.length + 1)
, csOpts = Object.create(options)
csOpts.partial = true
re = re.substr(0, reClassStart) + "\\["
+ makeRe(cs, csOpts)
}
if (options.partial) return re
re = "^" + re + "$"
if (negate) re = "^(?!" + re + ").*$"
var flags = ""
if (options.nocase) flags += "i"
if (options.debug) {
console.error("/%s/%s", re, flags)
}
try {
return new RegExp(re, flags)
} catch(ex) {
return false
}
}