1 var assert = require('assert')
4 fs = require('graceful-fs')
8 var path = require('path')
9 var Readable = require('stream').Readable
10 var util = require('util')
11 var assign = require('./assign')
13 function Walker (dir, options) {
14 assert.strictEqual(typeof dir, 'string', '`dir` parameter should be of type string. Got type: ' + typeof dir)
15 var defaultStreamOptions = { objectMode: true }
16 var defaultOpts = { queueMethod: 'shift', pathSorter: undefined, filter: undefined }
17 options = assign(defaultOpts, options, defaultStreamOptions)
19 Readable.call(this, options)
20 this.root = path.resolve(dir)
21 this.paths = [this.root]
22 this.options = options
23 this.fs = options.fs || fs // mock-fs
25 util.inherits(Walker, Readable)
27 Walker.prototype._read = function () {
28 if (this.paths.length === 0) return this.push(null)
30 var pathItem = this.paths[this.options.queueMethod]()
32 self.fs.lstat(pathItem, function (err, stats) {
33 var item = { path: pathItem, stats: stats }
34 if (err) return self.emit('error', err, item)
35 if (!stats.isDirectory()) return self.push(item)
37 self.fs.readdir(pathItem, function (err, pathItems) {
40 return self.emit('error', err, item)
43 pathItems = pathItems.map(function (part) { return path.join(pathItem, part) })
44 if (self.options.filter) pathItems = pathItems.filter(self.options.filter)
45 if (self.options.pathSorter) pathItems.sort(self.options.pathSorter)
46 pathItems.forEach(function (pi) { self.paths.push(pi) })
53 function walk (root, options) {
54 return new Walker(root, options)