112 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| module.exports = Walker
 | |
| 
 | |
| var path = require('path')
 | |
|   , fs = require('fs')
 | |
|   , util = require('util')
 | |
|   , EventEmitter = require('events').EventEmitter
 | |
|   , makeError = require('makeerror')
 | |
| 
 | |
| /**
 | |
|  * To walk a directory. It's complicated (but it's async, so it must be fast).
 | |
|  *
 | |
|  * @param root {String} the directory to start with
 | |
|  */
 | |
| function Walker(root) {
 | |
|   if (!(this instanceof Walker)) return new Walker(root)
 | |
|   EventEmitter.call(this)
 | |
|   this._pending = 0
 | |
|   this._filterDir = function() { return true }
 | |
|   this.go(root)
 | |
| }
 | |
| util.inherits(Walker, EventEmitter)
 | |
| 
 | |
| /**
 | |
|  * Errors of this type are thrown when the type of a file could not be
 | |
|  * determined.
 | |
|  */
 | |
| var UnknownFileTypeError = Walker.UnknownFileTypeError = makeError(
 | |
|   'UnknownFileTypeError',
 | |
|   'The type of this file could not be determined.'
 | |
| )
 | |
| 
 | |
| /**
 | |
|  * Setup a function to filter out directory entries.
 | |
|  *
 | |
|  * @param fn {Function} a function that will be given a directory name, which
 | |
|  * if returns true will include the directory and it's children
 | |
|  */
 | |
| Walker.prototype.filterDir = function(fn) {
 | |
|   this._filterDir = fn
 | |
|   return this
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Process a file or directory.
 | |
|  */
 | |
| Walker.prototype.go = function(entry) {
 | |
|   var that = this
 | |
|   this._pending++
 | |
| 
 | |
|   fs.lstat(entry, function(er, stat) {
 | |
|     if (er) {
 | |
|       that.emit('error', er, entry, stat)
 | |
|       that.doneOne()
 | |
|       return
 | |
|     }
 | |
| 
 | |
|     if (stat.isDirectory()) {
 | |
|       if (!that._filterDir(entry, stat)) {
 | |
|         that.doneOne()
 | |
|       } else {
 | |
|         fs.readdir(entry, function(er, files) {
 | |
|           if (er) {
 | |
|             that.emit('error', er, entry, stat)
 | |
|             that.doneOne()
 | |
|             return
 | |
|           }
 | |
| 
 | |
|           that.emit('entry', entry, stat)
 | |
|           that.emit('dir', entry, stat)
 | |
|           files.forEach(function(part) {
 | |
|             that.go(path.join(entry, part))
 | |
|           })
 | |
|           that.doneOne()
 | |
|         })
 | |
|       }
 | |
|     } else if (stat.isSymbolicLink()) {
 | |
|       that.emit('entry', entry, stat)
 | |
|       that.emit('symlink', entry, stat)
 | |
|       that.doneOne()
 | |
|     } else if (stat.isBlockDevice()) {
 | |
|       that.emit('entry', entry, stat)
 | |
|       that.emit('blockDevice', entry, stat)
 | |
|       that.doneOne()
 | |
|     } else if (stat.isCharacterDevice()) {
 | |
|       that.emit('entry', entry, stat)
 | |
|       that.emit('characterDevice', entry, stat)
 | |
|       that.doneOne()
 | |
|     } else if (stat.isFIFO()) {
 | |
|       that.emit('entry', entry, stat)
 | |
|       that.emit('fifo', entry, stat)
 | |
|       that.doneOne()
 | |
|     } else if (stat.isSocket()) {
 | |
|       that.emit('entry', entry, stat)
 | |
|       that.emit('socket', entry, stat)
 | |
|       that.doneOne()
 | |
|     } else if (stat.isFile()) {
 | |
|       that.emit('entry', entry, stat)
 | |
|       that.emit('file', entry, stat)
 | |
|       that.doneOne()
 | |
|     } else {
 | |
|       that.emit('error', UnknownFileTypeError(), entry, stat)
 | |
|       that.doneOne()
 | |
|     }
 | |
|   })
 | |
|   return this
 | |
| }
 | |
| 
 | |
| Walker.prototype.doneOne = function() {
 | |
|   if (--this._pending === 0) this.emit('end')
 | |
|   return this
 | |
| }
 |