index.js 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. var assert = require('assert')
  2. var path = require('path')
  3. var Readable = require('stream').Readable
  4. var util = require('util')
  5. function Walker (dir, options) {
  6. assert.strictEqual(typeof dir, 'string', '`dir` parameter should be of type string. Got type: ' + typeof dir)
  7. var defaultStreamOptions = { objectMode: true }
  8. var defaultOpts = {
  9. queueMethod: 'shift',
  10. pathSorter: undefined,
  11. filter: undefined,
  12. depthLimit: undefined,
  13. preserveSymlinks: false
  14. }
  15. options = Object.assign(defaultOpts, options, defaultStreamOptions)
  16. Readable.call(this, options)
  17. this.root = path.resolve(dir)
  18. this.paths = [this.root]
  19. this.options = options
  20. if (options.depthLimit > -1) this.rootDepth = this.root.split(path.sep).length + 1
  21. this.fs = options.fs || require('graceful-fs')
  22. }
  23. util.inherits(Walker, Readable)
  24. Walker.prototype._read = function () {
  25. if (this.paths.length === 0) return this.push(null)
  26. var self = this
  27. var pathItem = this.paths[this.options.queueMethod]()
  28. var statFunction = this.options.preserveSymlinks ? self.fs.lstat : self.fs.stat
  29. statFunction(pathItem, function (err, stats) {
  30. var item = { path: pathItem, stats: stats }
  31. if (err) return self.emit('error', err, item)
  32. if (!stats.isDirectory() || (self.rootDepth &&
  33. pathItem.split(path.sep).length - self.rootDepth >= self.options.depthLimit)) {
  34. return self.push(item)
  35. }
  36. self.fs.readdir(pathItem, function (err, pathItems) {
  37. if (err) {
  38. self.push(item)
  39. return self.emit('error', err, item)
  40. }
  41. pathItems = pathItems.map(function (part) { return path.join(pathItem, part) })
  42. if (self.options.filter) pathItems = pathItems.filter(self.options.filter)
  43. if (self.options.pathSorter) pathItems.sort(self.options.pathSorter)
  44. // faster way to do do incremental batch array pushes
  45. self.paths.push.apply(self.paths, pathItems)
  46. self.push(item)
  47. })
  48. })
  49. }
  50. function walk (root, options) {
  51. return new Walker(root, options)
  52. }
  53. module.exports = walk