249 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			249 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | 'use strict'; | ||
|  | 
 | ||
|  | function _fs() { | ||
|  |   const data = _interopRequireDefault(require('fs')); | ||
|  | 
 | ||
|  |   _fs = function _fs() { | ||
|  |     return data; | ||
|  |   }; | ||
|  | 
 | ||
|  |   return data; | ||
|  | } | ||
|  | 
 | ||
|  | function _path() { | ||
|  |   const data = _interopRequireDefault(require('path')); | ||
|  | 
 | ||
|  |   _path = function _path() { | ||
|  |     return data; | ||
|  |   }; | ||
|  | 
 | ||
|  |   return data; | ||
|  | } | ||
|  | 
 | ||
|  | function _events() { | ||
|  |   const data = require('events'); | ||
|  | 
 | ||
|  |   _events = function _events() { | ||
|  |     return data; | ||
|  |   }; | ||
|  | 
 | ||
|  |   return data; | ||
|  | } | ||
|  | 
 | ||
|  | function _anymatch() { | ||
|  |   const data = _interopRequireDefault(require('anymatch')); | ||
|  | 
 | ||
|  |   _anymatch = function _anymatch() { | ||
|  |     return data; | ||
|  |   }; | ||
|  | 
 | ||
|  |   return data; | ||
|  | } | ||
|  | 
 | ||
|  | function _micromatch() { | ||
|  |   const data = _interopRequireDefault(require('micromatch')); | ||
|  | 
 | ||
|  |   _micromatch = function _micromatch() { | ||
|  |     return data; | ||
|  |   }; | ||
|  | 
 | ||
|  |   return data; | ||
|  | } | ||
|  | 
 | ||
|  | function _walker() { | ||
|  |   const data = _interopRequireDefault(require('walker')); | ||
|  | 
 | ||
|  |   _walker = function _walker() { | ||
|  |     return data; | ||
|  |   }; | ||
|  | 
 | ||
|  |   return data; | ||
|  | } | ||
|  | 
 | ||
|  | function _interopRequireDefault(obj) { | ||
|  |   return obj && obj.__esModule ? obj : {default: obj}; | ||
|  | } | ||
|  | 
 | ||
|  | function _defineProperty(obj, key, value) { | ||
|  |   if (key in obj) { | ||
|  |     Object.defineProperty(obj, key, { | ||
|  |       value: value, | ||
|  |       enumerable: true, | ||
|  |       configurable: true, | ||
|  |       writable: true | ||
|  |     }); | ||
|  |   } else { | ||
|  |     obj[key] = value; | ||
|  |   } | ||
|  |   return obj; | ||
|  | } | ||
|  | 
 | ||
|  | let fsevents; | ||
|  | 
 | ||
|  | try { | ||
|  |   fsevents = require('fsevents'); | ||
|  | } catch (e) { | ||
|  |   // Optional dependency, only supported on Darwin.
 | ||
|  | } | ||
|  | 
 | ||
|  | const CHANGE_EVENT = 'change'; | ||
|  | const DELETE_EVENT = 'delete'; | ||
|  | const ADD_EVENT = 'add'; | ||
|  | const ALL_EVENT = 'all'; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Export `FSEventsWatcher` class. | ||
|  |  * Watches `dir`. | ||
|  |  */ | ||
|  | class FSEventsWatcher extends _events().EventEmitter { | ||
|  |   static isSupported() { | ||
|  |     return fsevents !== undefined; | ||
|  |   } | ||
|  | 
 | ||
|  |   static normalizeProxy(callback) { | ||
|  |     return (filepath, stats) => | ||
|  |       callback(_path().default.normalize(filepath), stats); | ||
|  |   } | ||
|  | 
 | ||
|  |   static recReaddir( | ||
|  |     dir, | ||
|  |     dirCallback, | ||
|  |     fileCallback, | ||
|  |     endCallback, | ||
|  |     errorCallback, | ||
|  |     ignored | ||
|  |   ) { | ||
|  |     (0, _walker().default)(dir) | ||
|  |       .filterDir( | ||
|  |         currentDir => !ignored || !(0, _anymatch().default)(ignored, currentDir) | ||
|  |       ) | ||
|  |       .on('dir', FSEventsWatcher.normalizeProxy(dirCallback)) | ||
|  |       .on('file', FSEventsWatcher.normalizeProxy(fileCallback)) | ||
|  |       .on('error', errorCallback) | ||
|  |       .on('end', () => { | ||
|  |         endCallback(); | ||
|  |       }); | ||
|  |   } | ||
|  | 
 | ||
|  |   constructor(dir, opts) { | ||
|  |     if (!fsevents) { | ||
|  |       throw new Error( | ||
|  |         '`fsevents` unavailable (this watcher can only be used on Darwin)' | ||
|  |       ); | ||
|  |     } | ||
|  | 
 | ||
|  |     super(); | ||
|  | 
 | ||
|  |     _defineProperty(this, 'root', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, 'ignored', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, 'glob', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, 'dot', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, 'hasIgnore', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, 'doIgnore', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, 'watcher', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, '_tracked', void 0); | ||
|  | 
 | ||
|  |     this.dot = opts.dot || false; | ||
|  |     this.ignored = opts.ignored; | ||
|  |     this.glob = Array.isArray(opts.glob) ? opts.glob : [opts.glob]; | ||
|  |     this.hasIgnore = | ||
|  |       Boolean(opts.ignored) && !(Array.isArray(opts) && opts.length > 0); | ||
|  |     this.doIgnore = opts.ignored | ||
|  |       ? (0, _anymatch().default)(opts.ignored) | ||
|  |       : () => false; | ||
|  |     this.root = _path().default.resolve(dir); | ||
|  |     this.watcher = fsevents(this.root); | ||
|  |     this.watcher.start().on('change', this.handleEvent.bind(this)); | ||
|  |     this._tracked = new Set(); | ||
|  |     FSEventsWatcher.recReaddir( | ||
|  |       this.root, | ||
|  |       filepath => { | ||
|  |         this._tracked.add(filepath); | ||
|  |       }, | ||
|  |       filepath => { | ||
|  |         this._tracked.add(filepath); | ||
|  |       }, | ||
|  |       this.emit.bind(this, 'ready'), | ||
|  |       this.emit.bind(this, 'error'), | ||
|  |       this.ignored | ||
|  |     ); | ||
|  |   } | ||
|  |   /** | ||
|  |    * End watching. | ||
|  |    */ | ||
|  | 
 | ||
|  |   close(callback) { | ||
|  |     this.watcher.stop(); | ||
|  |     this.removeAllListeners(); | ||
|  | 
 | ||
|  |     if (typeof callback === 'function') { | ||
|  |       process.nextTick(callback.bind(null, null, true)); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   isFileIncluded(relativePath) { | ||
|  |     if (this.doIgnore(relativePath)) { | ||
|  |       return false; | ||
|  |     } | ||
|  | 
 | ||
|  |     return this.glob.length | ||
|  |       ? _micromatch().default.some(relativePath, this.glob, { | ||
|  |           dot: this.dot | ||
|  |         }) | ||
|  |       : this.dot || _micromatch().default.some(relativePath, '**/*'); | ||
|  |   } | ||
|  | 
 | ||
|  |   handleEvent(filepath) { | ||
|  |     const relativePath = _path().default.relative(this.root, filepath); | ||
|  | 
 | ||
|  |     if (!this.isFileIncluded(relativePath)) { | ||
|  |       return; | ||
|  |     } | ||
|  | 
 | ||
|  |     _fs().default.lstat(filepath, (error, stat) => { | ||
|  |       if (error && error.code !== 'ENOENT') { | ||
|  |         this.emit('error', error); | ||
|  |         return; | ||
|  |       } | ||
|  | 
 | ||
|  |       if (error) { | ||
|  |         // Ignore files that aren't tracked and don't exist.
 | ||
|  |         if (!this._tracked.has(filepath)) { | ||
|  |           return; | ||
|  |         } | ||
|  | 
 | ||
|  |         this._emit(DELETE_EVENT, relativePath); | ||
|  | 
 | ||
|  |         this._tracked.delete(filepath); | ||
|  | 
 | ||
|  |         return; | ||
|  |       } | ||
|  | 
 | ||
|  |       if (this._tracked.has(filepath)) { | ||
|  |         this._emit(CHANGE_EVENT, relativePath, stat); | ||
|  |       } else { | ||
|  |         this._tracked.add(filepath); | ||
|  | 
 | ||
|  |         this._emit(ADD_EVENT, relativePath, stat); | ||
|  |       } | ||
|  |     }); | ||
|  |   } | ||
|  |   /** | ||
|  |    * Emit events. | ||
|  |    */ | ||
|  | 
 | ||
|  |   _emit(type, file, stat) { | ||
|  |     this.emit(type, file, this.root, stat); | ||
|  |     this.emit(ALL_EVENT, type, file, this.root, stat); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = FSEventsWatcher; |