121 lines
3.1 KiB
JavaScript
121 lines
3.1 KiB
JavaScript
|
var fs = require('fs'),
|
|||
|
Path = require('path'),
|
|||
|
util = require('util'),
|
|||
|
EE = require('events').EventEmitter;
|
|||
|
|
|||
|
function fsExists(file, cb) {
|
|||
|
if (!fs.access) return fs.exists(file, cb);
|
|||
|
fs.access(file, function(err) {
|
|||
|
cb(err ? false : true);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
function fsExistsSync(file) {
|
|||
|
if (!fs.accessSync) return fs.existsSync(file);
|
|||
|
try {
|
|||
|
fs.accessSync(file);
|
|||
|
} catch(err) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
module.exports = function(dir, iterator, options, callback){
|
|||
|
return FindUp(dir, iterator, options, callback);
|
|||
|
};
|
|||
|
|
|||
|
function FindUp(dir, iterator, options, callback){
|
|||
|
if (!(this instanceof FindUp)) {
|
|||
|
return new FindUp(dir, iterator, options, callback);
|
|||
|
}
|
|||
|
if(typeof options === 'function'){
|
|||
|
callback = options;
|
|||
|
options = {};
|
|||
|
}
|
|||
|
options = options || {};
|
|||
|
|
|||
|
EE.call(this);
|
|||
|
this.found = false;
|
|||
|
this.stopPlease = false;
|
|||
|
var self = this;
|
|||
|
|
|||
|
if(typeof iterator === 'string'){
|
|||
|
var file = iterator;
|
|||
|
iterator = function(dir, cb){
|
|||
|
return fsExists(Path.join(dir, file), cb);
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
if(callback) {
|
|||
|
this.on('found', function(dir){
|
|||
|
if(options.verbose) console.log(('found '+ dir ));
|
|||
|
callback(null, dir);
|
|||
|
self.stop();
|
|||
|
});
|
|||
|
|
|||
|
this.on('end', function(){
|
|||
|
if(options.verbose) console.log('end');
|
|||
|
if(!self.found) callback(new Error('not found'));
|
|||
|
});
|
|||
|
|
|||
|
this.on('error', function(err){
|
|||
|
if(options.verbose) console.log('error', err);
|
|||
|
callback(err);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
this._find(dir, iterator, options, callback);
|
|||
|
}
|
|||
|
util.inherits(FindUp, EE);
|
|||
|
|
|||
|
FindUp.prototype._find = function(dir, iterator, options, callback, currentDepth){
|
|||
|
var self = this;
|
|||
|
if (typeof currentDepth !== 'number') currentDepth = 0;
|
|||
|
|
|||
|
iterator(dir, function(exists){
|
|||
|
if(options.verbose) console.log(('traverse '+ dir));
|
|||
|
if (typeof options.maxdepth === 'number' && options.maxdepth >= 0 && currentDepth > options.maxdepth) {
|
|||
|
return self.emit('end');
|
|||
|
}
|
|||
|
currentDepth++;
|
|||
|
if(exists) {
|
|||
|
self.found = true;
|
|||
|
self.emit('found', dir);
|
|||
|
}
|
|||
|
|
|||
|
var parentDir = Path.join(dir, '..');
|
|||
|
if (self.stopPlease) return self.emit('end');
|
|||
|
if (dir === parentDir) return self.emit('end');
|
|||
|
if(dir.indexOf('../../') !== -1 ) return self.emit('error', new Error(dir + ' is not correct.'));
|
|||
|
self._find(parentDir, iterator, options, callback, currentDepth);
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
FindUp.prototype.stop = function(){
|
|||
|
this.stopPlease = true;
|
|||
|
};
|
|||
|
|
|||
|
module.exports.FindUp = FindUp;
|
|||
|
|
|||
|
module.exports.sync = function(dir, iteratorSync, options){
|
|||
|
if(typeof iteratorSync === 'string'){
|
|||
|
var file = iteratorSync;
|
|||
|
iteratorSync = function(dir){
|
|||
|
return fsExistsSync(Path.join(dir, file));
|
|||
|
};
|
|||
|
}
|
|||
|
options = options || {};
|
|||
|
var initialDir = dir;
|
|||
|
var currentDepth = 0;
|
|||
|
while(dir !== Path.join(dir, '..')){
|
|||
|
if (typeof options.maxdepth === 'number' && options.maxdepth >= 0 && currentDepth > options.maxdepth) {
|
|||
|
break;
|
|||
|
}
|
|||
|
currentDepth++;
|
|||
|
if(dir.indexOf('../../') !== -1 ) throw new Error(initialDir + ' is not correct.');
|
|||
|
if(iteratorSync(dir)) return dir;
|
|||
|
dir = Path.join(dir, '..');
|
|||
|
}
|
|||
|
throw new Error('not found');
|
|||
|
};
|