| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  | /*jshint strict:true node:true es5:true onevar:true laxcomma:true laxbreak:true*/ | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  | // Adapted from work by jorge@jorgechamorro.com on 2010-11-25
 | 
					
						
							| 
									
										
										
										
											2011-02-03 23:31:25 -07:00
										 |  |  | (function () { | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |   "use strict"; | 
					
						
							| 
									
										
										
										
											2010-12-02 03:09:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-03 23:31:25 -07:00
										 |  |  |   // Array.prototype.forEachAsync(next, item, i, collection)
 | 
					
						
							| 
									
										
										
										
											2011-11-01 16:02:58 -06:00
										 |  |  |   //require('Array.prototype.forEachAsync');
 | 
					
						
							| 
									
										
										
										
											2010-12-02 03:09:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-03 23:57:11 -07:00
										 |  |  |   function noop() {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-01 16:02:58 -06:00
										 |  |  |   var fs = require('fs') | 
					
						
							|  |  |  |     , forEachAsync = require('forEachAsync') | 
					
						
							|  |  |  |     , EventEmitter = require('events').EventEmitter | 
					
						
							|  |  |  |     , TypeEmitter = require('./node-type-emitter') | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     , util = require('util') | 
					
						
							| 
									
										
										
										
											2011-11-01 16:02:58 -06:00
										 |  |  |     ; | 
					
						
							| 
									
										
										
										
											2011-02-03 23:31:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |   function appendToDirs(stat) { | 
					
						
							|  |  |  |     /*jshint validthis:true*/ | 
					
						
							|  |  |  |     this.push(stat.name); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function wFilesHandlerWrapper(items) { | 
					
						
							|  |  |  |     /*jshint validthis:true*/ | 
					
						
							|  |  |  |     this._wFilesHandler(noop, items); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function Walker(pathname, options, sync) { | 
					
						
							|  |  |  |     EventEmitter.call(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var me = this | 
					
						
							| 
									
										
										
										
											2012-01-15 19:21:11 -07:00
										 |  |  |       ; | 
					
						
							| 
									
										
										
										
											2011-02-03 23:31:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:32:26 -06:00
										 |  |  |     me._wsync = sync; | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     me._wq = []; | 
					
						
							|  |  |  |     me._wqueue = [me._wq]; | 
					
						
							|  |  |  |     me._wcurpath = undefined; | 
					
						
							| 
									
										
										
										
											2013-04-20 16:29:37 -04:00
										 |  |  |     me._wfilters = options.filters; | 
					
						
							| 
									
										
										
										
											2012-06-06 13:32:26 -06:00
										 |  |  |     me._wfirstrun = true; | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     me._wcurpath = pathname; | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     if (me._wsync) { | 
					
						
							|  |  |  |       me._wWalk = me._wWalkSync; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       me._wWalk = me._wWalkAsync; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     // TODO just one little anony won't hurt...
 | 
					
						
							|  |  |  |     process.nextTick(function () { | 
					
						
							|  |  |  |       me._wWalk(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |   // Inherits must come before prototype additions
 | 
					
						
							|  |  |  |   util.inherits(Walker, EventEmitter); | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |   Walker.prototype._wLstatHandler = function (err, stat) { | 
					
						
							|  |  |  |     var me = this | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stat = stat || {}; | 
					
						
							|  |  |  |     stat.name = me._wcurfile; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (err) { | 
					
						
							|  |  |  |       stat.error = err; | 
					
						
							|  |  |  |       //me.emit('error', curpath, stat);
 | 
					
						
							|  |  |  |       me.emit('nodeError', me._wcurpath, stat, noop); | 
					
						
							|  |  |  |       me._wfnodegroups.errors.push(stat); | 
					
						
							|  |  |  |       me._wCurFileCallback(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       TypeEmitter.sortFnodesByType(stat, me._wfnodegroups); | 
					
						
							|  |  |  |       // NOTE: wCurFileCallback doesn't need thisness, so this is okay
 | 
					
						
							|  |  |  |       TypeEmitter.emitNodeType(me, me._wcurpath, stat, me._wCurFileCallback, me); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype._wFilesHandler = function (cont, file) { | 
					
						
							|  |  |  |     var statPath | 
					
						
							|  |  |  |       , me = this | 
					
						
							|  |  |  |       ; | 
					
						
							| 
									
										
										
										
											2012-01-15 19:21:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-15 20:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     me._wcurfile = file; | 
					
						
							|  |  |  |     me._wCurFileCallback = cont; | 
					
						
							|  |  |  |     me.emit('name', me._wcurpath, file, noop); | 
					
						
							| 
									
										
										
										
											2012-01-15 20:47:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     statPath = me._wcurpath + '/' + file; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!me._wsync) { | 
					
						
							|  |  |  |       // TODO how to remove this anony?
 | 
					
						
							|  |  |  |       fs.lstat(statPath, function (err, stat) { | 
					
						
							|  |  |  |         me._wLstatHandler(err, stat); | 
					
						
							| 
									
										
										
										
											2012-01-15 20:47:08 -07:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |       return; | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     try { | 
					
						
							|  |  |  |       me._wLstatHandler(null, fs.lstatSync(statPath)); | 
					
						
							|  |  |  |     } catch(e) { | 
					
						
							|  |  |  |       me._wLstatHandler(e); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype._wOnEmitDone = function () { | 
					
						
							|  |  |  |     var me = this | 
					
						
							|  |  |  |       , dirs = [] | 
					
						
							|  |  |  |       ; | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     me._wfnodegroups.directories.forEach(appendToDirs, dirs); | 
					
						
							|  |  |  |     dirs.forEach(me._wJoinPath, me); | 
					
						
							|  |  |  |     me._wqueue.push(me._wq = dirs); | 
					
						
							|  |  |  |     me._wNext(); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype._wPostFilesHandler = function () { | 
					
						
							|  |  |  |     var me = this | 
					
						
							|  |  |  |       ; | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     if (me._wfnodegroups.errors.length) { | 
					
						
							|  |  |  |       me.emit('errors', me._wcurpath, me._wfnodegroups.errors, noop); | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     // XXX emitNodeTypes still needs refactor
 | 
					
						
							|  |  |  |     TypeEmitter.emitNodeTypeGroups(me, me._wcurpath, me._wfnodegroups, me._wOnEmitDone, me); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype._wReadFiles = function () { | 
					
						
							|  |  |  |     var me = this | 
					
						
							|  |  |  |       ; | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     if (!me._wcurfiles || 0 === me._wcurfiles.length) { | 
					
						
							|  |  |  |       return me._wNext(); | 
					
						
							| 
									
										
										
										
											2010-11-20 22:02:53 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // TODO could allow user to selectively stat
 | 
					
						
							|  |  |  |     // and don't stat if there are no stat listeners
 | 
					
						
							|  |  |  |     me.emit('names', me._wcurpath, me._wcurfiles, noop); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (me._wsync) { | 
					
						
							|  |  |  |       me._wcurfiles.forEach(wFilesHandlerWrapper, me); | 
					
						
							|  |  |  |       me._wPostFilesHandler(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       forEachAsync(me._wcurfiles, me._wFilesHandler, me).then(me._wPostFilesHandler); | 
					
						
							| 
									
										
										
										
											2011-02-03 23:31:25 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype._wReaddirHandler = function (err, files) { | 
					
						
							|  |  |  |     var fnodeGroups = TypeEmitter.createNodeGroups() | 
					
						
							|  |  |  |       , me = this | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     me._wfnodegroups = fnodeGroups; | 
					
						
							|  |  |  |     me._wcurfiles = files; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!err) { | 
					
						
							|  |  |  |       me._wReadFiles(); | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2011-02-03 23:31:25 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:32:26 -06:00
										 |  |  |     if (!me._wfirstrun) { | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |       me.emit('directoryError', me._wcurpath, { error: err }, noop); | 
					
						
							|  |  |  |       me._wReadFiles(); | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:32:26 -06:00
										 |  |  |     me._wfirstrun = false; | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     // TODO how to remove this anony?
 | 
					
						
							|  |  |  |     fs.lstat(me._wcurpath, function (e, stat) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (stat) { | 
					
						
							|  |  |  |         files = [me._wcurpath.replace(/.*\//, '')]; | 
					
						
							|  |  |  |         me._wcurpath = me._wcurpath.replace(files[0], ''); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       me._wReadFiles(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype._wWalkSync = function () { | 
					
						
							|  |  |  |     var err | 
					
						
							|  |  |  |       , files | 
					
						
							|  |  |  |       , me = this | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-20 16:29:37 -04:00
										 |  |  |     // Stop directories that contain filter keywords
 | 
					
						
							|  |  |  |     // from continuing through the walk process
 | 
					
						
							|  |  |  |     if (me._wfilters != undefined) { | 
					
						
							|  |  |  |       var shouldExclude = false; | 
					
						
							|  |  |  |       for (var iFilter=0; iFilter<me._wfilters.length; ++iFilter) { | 
					
						
							|  |  |  |         if (me._wcurpath.indexOf(me._wfilters[iFilter]) != -1 ) { | 
					
						
							|  |  |  |           me._wNext(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-20 16:29:37 -04:00
										 |  |  |     if( !shouldExclude ) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         files = fs.readdirSync(me._wcurpath); | 
					
						
							|  |  |  |       } catch(e) { | 
					
						
							|  |  |  |         err = e; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2013-04-20 16:31:36 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-04-20 16:29:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     me._wReaddirHandler(err, files); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype._wWalkAsync = function () { | 
					
						
							|  |  |  |     var me = this | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-18 23:03:35 -04:00
										 |  |  |     // Stop directories that contain filter keywords
 | 
					
						
							|  |  |  |     // from continuing through the walk process
 | 
					
						
							| 
									
										
										
										
											2013-04-20 16:29:37 -04:00
										 |  |  |     if (me._wfilters != undefined) { | 
					
						
							|  |  |  |       for (var iFilter=0; iFilter<me._wfilters.length; ++iFilter) { | 
					
						
							|  |  |  |         if (me._wcurpath.indexOf(me._wfilters[iFilter]) != -1 ) { | 
					
						
							| 
									
										
										
										
											2013-04-18 23:03:35 -04:00
										 |  |  |           me._wNext(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     // TODO how to remove this anony?
 | 
					
						
							|  |  |  |     fs.readdir(me._wcurpath, function (err, files) { | 
					
						
							|  |  |  |       me._wReaddirHandler(err, files); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype._wNext = function () { | 
					
						
							|  |  |  |     var me = this | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (me._paused) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (me._wq.length) { | 
					
						
							|  |  |  |       me._wcurpath = me._wq.pop(); | 
					
						
							|  |  |  |       me._wWalk(); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     me._wqueue.length -= 1; | 
					
						
							|  |  |  |     if (me._wqueue.length) { | 
					
						
							|  |  |  |       me._wq = me._wqueue[me._wqueue.length - 1]; | 
					
						
							|  |  |  |       return this._wNext(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     me.emit('end'); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype._wJoinPath = function (v, i, o) { | 
					
						
							|  |  |  |     var me = this | 
					
						
							|  |  |  |       ; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     o[i] = [me._wcurpath, '/', v].join(''); | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype.pause = function () { | 
					
						
							|  |  |  |     this._paused = true; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   Walker.prototype.resume = function () { | 
					
						
							|  |  |  |     this._paused = false; | 
					
						
							|  |  |  |     this._wNext(); | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2011-02-03 23:31:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  |   exports.walk = function (path, opts) { | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     return new Walker(path, opts, false); | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   exports.walkSync = function (path, opts) { | 
					
						
							| 
									
										
										
										
											2012-06-06 13:19:44 -06:00
										 |  |  |     return new Walker(path, opts, true); | 
					
						
							| 
									
										
										
										
											2011-05-02 21:11:03 -06:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2010-11-20 22:02:53 -07:00
										 |  |  | }()); |