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