index.js 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. var fs = require('fs'),
  2. Path = require('path'),
  3. util = require('util'),
  4. colors = require('colors'),
  5. EE = require('events').EventEmitter,
  6. fsExists = fs.exists ? fs.exists : Path.exists,
  7. fsExistsSync = fs.existsSync ? fs.existsSync : Path.existsSync;
  8. module.exports = function(dir, iterator, options, callback){
  9. return FindUp(dir, iterator, options, callback);
  10. };
  11. function FindUp(dir, iterator, options, callback){
  12. if (!(this instanceof FindUp)) {
  13. return new FindUp(dir, iterator, options, callback);
  14. }
  15. if(typeof options === 'function'){
  16. callback = options;
  17. options = {};
  18. }
  19. options = options || {};
  20. EE.call(this);
  21. this.found = false;
  22. this.stopPlease = false;
  23. var self = this;
  24. if(typeof iterator === 'string'){
  25. var file = iterator;
  26. iterator = function(dir, cb){
  27. return fsExists(Path.join(dir, file), cb);
  28. };
  29. }
  30. if(callback) {
  31. this.on('found', function(dir){
  32. if(options.verbose) console.log(('found '+ dir ).green);
  33. callback(null, dir);
  34. self.stop();
  35. });
  36. this.on('end', function(){
  37. if(options.verbose) console.log('end'.grey);
  38. if(!self.found) callback(new Error('not found'));
  39. });
  40. this.on('error', function(err){
  41. if(options.verbose) console.log('error'.red, err);
  42. callback(err);
  43. });
  44. }
  45. this._find(dir, iterator, options, callback);
  46. }
  47. util.inherits(FindUp, EE);
  48. FindUp.prototype._find = function(dir, iterator, options, callback){
  49. var self = this;
  50. iterator(dir, function(exists){
  51. if(options.verbose) console.log(('traverse '+ dir).grey);
  52. if(exists) {
  53. self.found = true;
  54. self.emit('found', dir);
  55. }
  56. var parentDir = Path.join(dir, '..');
  57. if (self.stopPlease) return self.emit('end');
  58. if (dir === parentDir) return self.emit('end');
  59. if(dir.indexOf('../../') !== -1 ) return self.emit('error', new Error(dir + ' is not correct.'));
  60. self._find(parentDir, iterator, options, callback);
  61. });
  62. };
  63. FindUp.prototype.stop = function(){
  64. this.stopPlease = true;
  65. };
  66. module.exports.FindUp = FindUp;
  67. module.exports.sync = function(dir, iteratorSync){
  68. if(typeof iteratorSync === 'string'){
  69. var file = iteratorSync;
  70. iteratorSync = function(dir){
  71. return fsExistsSync(Path.join(dir, file));
  72. };
  73. }
  74. var initialDir = dir;
  75. while(dir !== Path.join(dir, '..')){
  76. if(dir.indexOf('../../') !== -1 ) throw new Error(initialDir + ' is not correct.');
  77. if(iteratorSync(dir)) return dir;
  78. dir = Path.join(dir, '..');
  79. }
  80. throw new Error('not found');
  81. };