1exports.setopts = setopts 2exports.ownProp = ownProp 3exports.makeAbs = makeAbs 4exports.finish = finish 5exports.mark = mark 6exports.isIgnored = isIgnored 7exports.childrenIgnored = childrenIgnored 8 9function ownProp (obj, field) { 10 return Object.prototype.hasOwnProperty.call(obj, field) 11} 12 13var fs = require("fs") 14var path = require("path") 15var minimatch = require("minimatch") 16var isAbsolute = require("path").isAbsolute 17var Minimatch = minimatch.Minimatch 18 19function alphasort (a, b) { 20 return a.localeCompare(b, 'en') 21} 22 23function setupIgnores (self, options) { 24 self.ignore = options.ignore || [] 25 26 if (!Array.isArray(self.ignore)) 27 self.ignore = [self.ignore] 28 29 if (self.ignore.length) { 30 self.ignore = self.ignore.map(ignoreMap) 31 } 32} 33 34// ignore patterns are always in dot:true mode. 35function ignoreMap (pattern) { 36 var gmatcher = null 37 if (pattern.slice(-3) === '/**') { 38 var gpattern = pattern.replace(/(\/\*\*)+$/, '') 39 gmatcher = new Minimatch(gpattern, { dot: true }) 40 } 41 42 return { 43 matcher: new Minimatch(pattern, { dot: true }), 44 gmatcher: gmatcher 45 } 46} 47 48function setopts (self, pattern, options) { 49 if (!options) 50 options = {} 51 52 // base-matching: just use globstar for that. 53 if (options.matchBase && -1 === pattern.indexOf("/")) { 54 if (options.noglobstar) { 55 throw new Error("base matching requires globstar") 56 } 57 pattern = "**/" + pattern 58 } 59 60 self.windowsPathsNoEscape = !!options.windowsPathsNoEscape || 61 options.allowWindowsEscape === false 62 if (self.windowsPathsNoEscape) { 63 pattern = pattern.replace(/\\/g, '/') 64 } 65 66 self.silent = !!options.silent 67 self.pattern = pattern 68 self.strict = options.strict !== false 69 self.realpath = !!options.realpath 70 self.realpathCache = options.realpathCache || Object.create(null) 71 self.follow = !!options.follow 72 self.dot = !!options.dot 73 self.mark = !!options.mark 74 self.nodir = !!options.nodir 75 if (self.nodir) 76 self.mark = true 77 self.sync = !!options.sync 78 self.nounique = !!options.nounique 79 self.nonull = !!options.nonull 80 self.nosort = !!options.nosort 81 self.nocase = !!options.nocase 82 self.stat = !!options.stat 83 self.noprocess = !!options.noprocess 84 self.absolute = !!options.absolute 85 self.fs = options.fs || fs 86 87 self.maxLength = options.maxLength || Infinity 88 self.cache = options.cache || Object.create(null) 89 self.statCache = options.statCache || Object.create(null) 90 self.symlinks = options.symlinks || Object.create(null) 91 92 setupIgnores(self, options) 93 94 self.changedCwd = false 95 var cwd = process.cwd() 96 if (!ownProp(options, "cwd")) 97 self.cwd = path.resolve(cwd) 98 else { 99 self.cwd = path.resolve(options.cwd) 100 self.changedCwd = self.cwd !== cwd 101 } 102 103 self.root = options.root || path.resolve(self.cwd, "/") 104 self.root = path.resolve(self.root) 105 106 // TODO: is an absolute `cwd` supposed to be resolved against `root`? 107 // e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test') 108 self.cwdAbs = isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd) 109 self.nomount = !!options.nomount 110 111 if (process.platform === "win32") { 112 self.root = self.root.replace(/\\/g, "/") 113 self.cwd = self.cwd.replace(/\\/g, "/") 114 self.cwdAbs = self.cwdAbs.replace(/\\/g, "/") 115 } 116 117 // disable comments and negation in Minimatch. 118 // Note that they are not supported in Glob itself anyway. 119 options.nonegate = true 120 options.nocomment = true 121 122 self.minimatch = new Minimatch(pattern, options) 123 self.options = self.minimatch.options 124} 125 126function finish (self) { 127 var nou = self.nounique 128 var all = nou ? [] : Object.create(null) 129 130 for (var i = 0, l = self.matches.length; i < l; i ++) { 131 var matches = self.matches[i] 132 if (!matches || Object.keys(matches).length === 0) { 133 if (self.nonull) { 134 // do like the shell, and spit out the literal glob 135 var literal = self.minimatch.globSet[i] 136 if (nou) 137 all.push(literal) 138 else 139 all[literal] = true 140 } 141 } else { 142 // had matches 143 var m = Object.keys(matches) 144 if (nou) 145 all.push.apply(all, m) 146 else 147 m.forEach(function (m) { 148 all[m] = true 149 }) 150 } 151 } 152 153 if (!nou) 154 all = Object.keys(all) 155 156 if (!self.nosort) 157 all = all.sort(alphasort) 158 159 // at *some* point we statted all of these 160 if (self.mark) { 161 for (var i = 0; i < all.length; i++) { 162 all[i] = self._mark(all[i]) 163 } 164 if (self.nodir) { 165 all = all.filter(function (e) { 166 var notDir = !(/\/$/.test(e)) 167 var c = self.cache[e] || self.cache[makeAbs(self, e)] 168 if (notDir && c) 169 notDir = c !== 'DIR' && !Array.isArray(c) 170 return notDir 171 }) 172 } 173 } 174 175 if (self.ignore.length) 176 all = all.filter(function(m) { 177 return !isIgnored(self, m) 178 }) 179 180 self.found = all 181} 182 183function mark (self, p) { 184 var abs = makeAbs(self, p) 185 var c = self.cache[abs] 186 var m = p 187 if (c) { 188 var isDir = c === 'DIR' || Array.isArray(c) 189 var slash = p.slice(-1) === '/' 190 191 if (isDir && !slash) 192 m += '/' 193 else if (!isDir && slash) 194 m = m.slice(0, -1) 195 196 if (m !== p) { 197 var mabs = makeAbs(self, m) 198 self.statCache[mabs] = self.statCache[abs] 199 self.cache[mabs] = self.cache[abs] 200 } 201 } 202 203 return m 204} 205 206// lotta situps... 207function makeAbs (self, f) { 208 var abs = f 209 if (f.charAt(0) === '/') { 210 abs = path.join(self.root, f) 211 } else if (isAbsolute(f) || f === '') { 212 abs = f 213 } else if (self.changedCwd) { 214 abs = path.resolve(self.cwd, f) 215 } else { 216 abs = path.resolve(f) 217 } 218 219 if (process.platform === 'win32') 220 abs = abs.replace(/\\/g, '/') 221 222 return abs 223} 224 225 226// Return true, if pattern ends with globstar '**', for the accompanying parent directory. 227// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents 228function isIgnored (self, path) { 229 if (!self.ignore.length) 230 return false 231 232 return self.ignore.some(function(item) { 233 return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) 234 }) 235} 236 237function childrenIgnored (self, path) { 238 if (!self.ignore.length) 239 return false 240 241 return self.ignore.some(function(item) { 242 return !!(item.gmatcher && item.gmatcher.match(path)) 243 }) 244} 245