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