fs-walk.js/lib/walk.js

151 lines
3.5 KiB
JavaScript
Raw Normal View History

2011-05-03 03:11:03 +00:00
// Adapted from work by jorge@jorgechamorro.com on 2010-11-25
2011-02-04 06:31:25 +00:00
(function () {
"use strict"
2011-02-04 06:31:25 +00:00
// Array.prototype.forEachAsync(next, item, i, collection)
//require('Array.prototype.forEachAsync');
2011-02-04 06:57:11 +00:00
function noop() {}
var fs = require('fs')
, forEachAsync = require('forEachAsync')
, EventEmitter = require('events').EventEmitter
, TypeEmitter = require('./node-type-emitter')
;
2011-02-04 06:31:25 +00:00
2011-05-03 03:11:03 +00:00
function create(pathname, options, sync) {
var emitter = new EventEmitter()
, q = []
, queue = [q]
, curpath;
2011-02-04 06:31:25 +00:00
2011-05-03 03:11:03 +00:00
function readdirHandler(err, files) {
var fnodeGroups = TypeEmitter.createNodeGroups();
function filesHandler(cont, file) {
var statPath;
emitter.emit('name', curpath, file, noop);
function lstatHandler(err, stat) {
stat = stat || {};
stat.name = file;
if (err) {
stat.error = err;
//emitter.emit('error', curpath, stat);
emitter.emit('nodeError', curpath, stat, noop);
fnodeGroups.errors.push(stat);
cont();
} else {
TypeEmitter.sortFnodesByType(stat, fnodeGroups);
TypeEmitter.emitNodeType(emitter, curpath, stat, cont);
}
2011-02-04 06:31:25 +00:00
}
2011-02-04 06:57:11 +00:00
2011-05-03 03:11:03 +00:00
statPath = curpath + '/' + file;
if (sync) {
try {
lstatHandler(null, fs.lstatSync(statPath));
} catch(e) {
lstatHandler(e);
2011-02-04 06:57:11 +00:00
}
2011-05-03 03:11:03 +00:00
} else {
fs.lstat(statPath, lstatHandler);
}
}
function postFilesHandler() {
if (fnodeGroups.errors.length) {
emitter.emit('errors', curpath, fnodeGroups.errors, noop);
}
TypeEmitter.emitNodeTypeGroups(emitter, curpath, fnodeGroups, function () {
var dirs = [];
fnodeGroups.directories.forEach(function (stat) {
dirs.push(stat.name);
2010-11-21 05:02:53 +00:00
});
2011-05-03 03:11:03 +00:00
dirs.forEach(fullPath);
queue.push(q = dirs);
next();
});
}
if (err) {
emitter.emit('directoryError', curpath, { error: err }, noop);
//emitter.emit('error', curpath, { error: err });
}
if (!files || 0 == files.length) {
return next();
}
// TODO could allow user to selectively stat
// and don't stat if there are no stat listeners
emitter.emit('names', curpath, files, noop);
if (sync) {
files.forEach(function (items) {
filesHandler(noop, items);
});
2011-05-03 03:11:03 +00:00
postFilesHandler();
} else {
forEachAsync(files, filesHandler).then(postFilesHandler);
2011-05-03 03:11:03 +00:00
}
}
function walkSync() {
var err, files;
try {
files = fs.readdirSync(curpath);
} catch(e) {
err = e;
}
readdirHandler(err, files);
}
function walk() {
if (sync) {
walkSync();
return;
}
fs.readdir(curpath, readdirHandler);
2010-11-21 05:02:53 +00:00
}
2011-02-04 06:31:25 +00:00
function next() {
if (q.length) {
curpath = q.pop();
return walk();
}
if (queue.length -= 1) {
2011-05-03 03:11:03 +00:00
q = queue[queue.length - 1];
2011-02-04 06:31:25 +00:00
return next();
}
emitter.emit('end');
2011-02-04 06:31:25 +00:00
}
2011-05-03 03:11:03 +00:00
function fullPath(v, i, o) {
o[i] = [curpath, '/', v].join('');
2011-02-04 06:31:25 +00:00
}
curpath = pathname;
2011-05-03 03:11:03 +00:00
if (sync) {
process.nextTick(walk);
} else {
walk();
}
return emitter;
2010-11-21 05:02:53 +00:00
}
2011-02-04 06:31:25 +00:00
2011-05-03 03:11:03 +00:00
exports.walk = function (path, opts) {
return create(path, opts, false);
};
exports.walkSync = function (path, opts) {
return create(path, opts, true);
};
2010-11-21 05:02:53 +00:00
}());