common.js 5.9 KB

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