+73
-61
| 'use strict'; | ||
| const EventEmitter = require('events').EventEmitter; | ||
| const { EventEmitter } = require('events'); | ||
| const fs = require('fs'); | ||
@@ -39,20 +39,4 @@ const sysPath = require('path'); | ||
| /** | ||
| * @param {String|Array<String>} value | ||
| */ | ||
| const arrify = (value = []) => Array.isArray(value) ? value : [value]; | ||
| const flatten = (list, result = []) => { | ||
| list.forEach(item => { | ||
| if (Array.isArray(item)) { | ||
| flatten(item, result); | ||
| } else { | ||
| result.push(item); | ||
| } | ||
| }); | ||
| return result; | ||
| }; | ||
| // Optimize RAM usage. | ||
| const BACK_SLASH = /\\/g; | ||
| const BACK_SLASH_RE = /\\/g; | ||
| const SLASH = '/'; | ||
@@ -71,6 +55,41 @@ const DOUBLE_SLASH = /\/\//; | ||
| const STRING_TYPE = 'string'; | ||
| const isWindows = process.platform === 'win32'; | ||
| const EMPTY_FN = () => {}; | ||
| const EV_ALL = 'all'; | ||
| const EV_READY = 'ready'; | ||
| const EV_ADD = 'add'; | ||
| const EV_CHANGE = 'change'; | ||
| const EV_UNLINK = 'unlink'; | ||
| const EV_ADD_DIR = 'addDir'; | ||
| const EV_UNLINK_DIR = 'unlinkDir'; | ||
| const EV_RAW = 'raw'; | ||
| const EV_ERROR = 'error'; | ||
| const arrify = (value = []) => Array.isArray(value) ? value : [value]; | ||
| const flatten = (list, result = []) => { | ||
| list.forEach(item => { | ||
| if (Array.isArray(item)) { | ||
| flatten(item, result); | ||
| } else { | ||
| result.push(item); | ||
| } | ||
| }); | ||
| return result; | ||
| }; | ||
| const unifyPaths = (paths_) => { | ||
| /** | ||
| * @type {Array<String>} | ||
| */ | ||
| let paths = flatten(arrify(paths_)); | ||
| if (!paths.every(p => typeof p === STRING_TYPE)) { | ||
| throw new TypeError('Non-string provided as watch path: ' + paths); | ||
| } | ||
| paths = paths.map(normalizePathToUnix); | ||
| return paths; | ||
| }; | ||
| const toUnix = (string) => { | ||
| let str = string.replace(BACK_SLASH, SLASH); | ||
| let str = string.replace(BACK_SLASH_RE, SLASH); | ||
| while (str.match(DOUBLE_SLASH)) { | ||
@@ -157,3 +176,4 @@ str = str.replace(DOUBLE_SLASH, SLASH); | ||
| /** @type {object|boolean} */ | ||
| this.globSymlink = this.hasGlob && follow ? null : false; | ||
| if (path === '') this.hasGlob = false; | ||
| this.globSymlink = this.hasGlob && follow ? undefined : false; | ||
| this.globFilter = this.hasGlob ? anymatch(path, undefined, ANYMATCH_OPTS) : false; | ||
@@ -171,3 +191,3 @@ this.dirParts = this.getDirParts(path); | ||
| // first entry should always have entry.parentDir === '' | ||
| if (this.globSymlink == null) { | ||
| if (this.globSymlink === undefined) { | ||
| this.globSymlink = entry.fullParentDir === this.fullWatchPath ? | ||
@@ -325,6 +345,6 @@ false : {realPath: entry.fullParentDir, linkPath: this.fullWatchPath}; | ||
| // use process.nextTick to allow time for listener to be bound | ||
| process.nextTick(() => this.emit('ready')); | ||
| process.nextTick(() => this.emit(EV_READY)); | ||
| } | ||
| }; | ||
| this._emitRaw = (...args) => this.emit('raw', ...args); | ||
| this._emitRaw = (...args) => this.emit(EV_RAW, ...args); | ||
| this._readyEmitted = false; | ||
@@ -356,12 +376,3 @@ this.options = opts; | ||
| this.closed = false; | ||
| /** | ||
| * @type {Array<String>} | ||
| */ | ||
| let paths = flatten(arrify(paths_)); | ||
| if (!paths.every(p => typeof p === STRING_TYPE)) { | ||
| throw new TypeError('Non-string provided as watch path: ' + paths); | ||
| } | ||
| paths = paths.map(path => sysPath.normalize(path)); | ||
| let paths = unifyPaths(paths_); | ||
| if (cwd) { | ||
@@ -392,3 +403,3 @@ paths = paths.map((path) => { | ||
| // to make ignoredPaths changes effective | ||
| this._userIgnored = null; | ||
| this._userIgnored = undefined; | ||
@@ -425,8 +436,8 @@ return true; | ||
| * Close watchers or start ignoring events from specified paths. | ||
| * @param {Path|Array<Path>} paths - string or array of strings, file/directory paths and/or globs | ||
| * @param {Path|Array<Path>} paths_ - string or array of strings, file/directory paths and/or globs | ||
| * @returns {FSWatcher} for chaining | ||
| */ | ||
| unwatch(paths) { | ||
| unwatch(paths_) { | ||
| if (this.closed) return this; | ||
| paths = flatten(arrify(paths)); | ||
| let paths = unifyPaths(paths_); | ||
| const cwd = this.options.cwd; | ||
@@ -450,3 +461,3 @@ | ||
| // to make ignoredPaths changes effective | ||
| this._userIgnored = null; | ||
| this._userIgnored = undefined; | ||
| }); | ||
@@ -466,11 +477,11 @@ | ||
| // Memory management. | ||
| this.removeAllListeners(); | ||
| this._closers.forEach(closerList => closerList.forEach(closer => closer())); | ||
| this._closers.clear(); | ||
| this._watched.clear(); | ||
| this._streams.forEach(stream => stream.destroy()); | ||
| this._streams.clear(); | ||
| this._symlinkPaths.clear(); | ||
| this._throttled.clear(); | ||
| this.removeAllListeners(); | ||
| this._userIgnored = undefined; | ||
| this._readyCount = 0; | ||
| this._readyEmitted = false; | ||
| ['closers', 'watched', 'streams', 'symlinkPaths', 'throttled'].forEach(key => { | ||
| this['_' + key].clear(); | ||
| }); | ||
| return this; | ||
@@ -494,3 +505,3 @@ } | ||
| this.emit(...args); | ||
| if (event !== 'error') this.emit(...['all'].concat(args)); | ||
| if (event !== EV_ERROR) this.emit(EV_ALL, ...args); | ||
| } | ||
@@ -515,2 +526,3 @@ | ||
| const opts = this.options; | ||
| if (isWindows) path = sysPath.normalize(path); | ||
| if (opts.cwd) path = sysPath.relative(opts.cwd, path); | ||
@@ -531,3 +543,3 @@ /** @type Array<any> */ | ||
| if (opts.atomic) { | ||
| if (event === 'unlink') { | ||
| if (event === EV_UNLINK) { | ||
| this._pendingUnlinks.set(path, args); | ||
@@ -537,3 +549,3 @@ setTimeout(() => { | ||
| this.emit(...entry); | ||
| this.emit(...['all', ...entry]); | ||
| this.emit(EV_ALL, ...entry); | ||
| this._pendingUnlinks.delete(path); | ||
@@ -543,4 +555,4 @@ }); | ||
| return this; | ||
| } else if (event === 'add' && this._pendingUnlinks.has(path)) { | ||
| event = args[0] = 'change'; | ||
| } else if (event === EV_ADD && this._pendingUnlinks.has(path)) { | ||
| event = args[0] = EV_CHANGE; | ||
| this._pendingUnlinks.delete(path); | ||
@@ -550,6 +562,6 @@ } | ||
| if (awf && (event === 'add' || event === 'change') && this._readyEmitted) { | ||
| if (awf && (event === EV_ADD || event === EV_CHANGE) && this._readyEmitted) { | ||
| const awfEmit = (err, stats) => { | ||
| if (err) { | ||
| event = args[0] = 'error'; | ||
| event = args[0] = EV_ERROR; | ||
| args[1] = err; | ||
@@ -572,4 +584,4 @@ this.emitWithAll(event, args); | ||
| if (event === 'change') { | ||
| const isThrottled = !this._throttle('change', path, 50); | ||
| if (event === EV_CHANGE) { | ||
| const isThrottled = !this._throttle(EV_CHANGE, path, 50); | ||
| if (isThrottled) return this; | ||
@@ -579,3 +591,3 @@ } | ||
| if (opts.alwaysStat && val1 === undefined && | ||
| (event === 'add' || event === 'addDir' || event === 'change') | ||
| (event === EV_ADD || event === EV_ADD_DIR || event === EV_CHANGE) | ||
| ) { | ||
@@ -607,3 +619,3 @@ const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path; | ||
| ) { | ||
| this.emit('error', error); | ||
| this.emit(EV_ERROR, error); | ||
| } | ||
@@ -842,3 +854,3 @@ return error || this.closed; | ||
| const event = this._pendingWrites.get(relPath).cancelWait(); | ||
| if (event === 'add') return; | ||
| if (event === EV_ADD) return; | ||
| } | ||
@@ -850,3 +862,3 @@ | ||
| this._watched.delete(fullPath); | ||
| const eventName = isDirectory ? 'unlinkDir' : 'unlink'; | ||
| const eventName = isDirectory ? EV_UNLINK_DIR : EV_UNLINK; | ||
| if (wasTracked && !this._isIgnored(path)) this._emit(eventName, path); | ||
@@ -890,7 +902,7 @@ | ||
| _readdirp(root, opts) { | ||
| const options = Object.assign({type: 'all', alwaysStat: true, lstat: true}, opts); | ||
| const options = Object.assign({type: EV_ALL, alwaysStat: true, lstat: true}, opts); | ||
| let stream = readdirp(root, options); | ||
| this._streams.add(stream); | ||
| stream.once('close', () => { | ||
| stream = null; | ||
| stream = undefined; | ||
| }); | ||
@@ -900,3 +912,3 @@ stream.once('end', () => { | ||
| this._streams.delete(stream); | ||
| stream = null; | ||
| stream = undefined; | ||
| } | ||
@@ -903,0 +915,0 @@ }); |
+33
-16
@@ -19,3 +19,3 @@ 'use strict'; | ||
| if (maj === 8 && min < 16) { | ||
| fsevents = null; | ||
| fsevents = undefined; | ||
| } | ||
@@ -25,2 +25,5 @@ } | ||
| const EV_ADD = 'add'; | ||
| const EV_CHANGE = 'change'; | ||
| const EV_ADD_DIR = 'addDir'; | ||
| const EMPTY_FN = () => {}; | ||
@@ -84,3 +87,3 @@ | ||
| */ | ||
| function setFSEventsListener(path, realPath, listener, rawEmitter) { | ||
| function setFSEventsListener(path, realPath, listener, rawEmitter, fsw) { | ||
| let watchPath = sysPath.extname(path) ? sysPath.dirname(path) : path; | ||
@@ -128,2 +131,3 @@ const parentPath = sysPath.dirname(watchPath); | ||
| watcher: createFSEventsInstance(watchPath, (fullPath, flags) => { | ||
| if (fsw.closed) return; | ||
| const info = fsevents.getInfo(fullPath, flags); | ||
@@ -143,11 +147,10 @@ cont.listeners.forEach(list => { | ||
| return () => { | ||
| const wl = cont.listeners; | ||
| const lst = cont.listeners; | ||
| wl.delete(filteredListener); | ||
| if (!wl.size) { | ||
| lst.delete(filteredListener); | ||
| if (!lst.size) { | ||
| FSEventsWatchers.delete(watchPath); | ||
| cont.watcher.stop(); | ||
| cont.rawEmitter = cont.watcher = null; | ||
| cont.rawEmitter = cont.watcher = undefined; | ||
| Object.freeze(cont); | ||
| Object.freeze(cont.listeners); | ||
| } | ||
@@ -189,6 +192,6 @@ }; | ||
| /** | ||
| * @param {import('../index').FSWatcher} fsW | ||
| * @param {import('../index').FSWatcher} fsw | ||
| */ | ||
| constructor(fsW) { | ||
| this.fsw = fsW; | ||
| constructor(fsw) { | ||
| this.fsw = fsw; | ||
| } | ||
@@ -210,3 +213,3 @@ checkIgnored(path, stats) { | ||
| addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts) { | ||
| const event = watchedDir.has(item) ? 'change' : 'add'; | ||
| const event = watchedDir.has(item) ? EV_CHANGE : EV_ADD; | ||
| this.handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts); | ||
@@ -218,3 +221,9 @@ } | ||
| const fd = await open(path, 'r'); | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| await close(fd); | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts); | ||
@@ -239,3 +248,3 @@ } catch (error) { | ||
| } else { | ||
| if (event === 'add') { | ||
| if (event === EV_ADD) { | ||
| // track new directories | ||
@@ -260,3 +269,3 @@ if (info.type === 'directory') this.fsw._getWatchedDir(path); | ||
| this.fsw._emit(eventName, path); | ||
| if (eventName === 'addDir') this._addToFsEvents(path, false, true); | ||
| if (eventName === EV_ADD_DIR) this._addToFsEvents(path, false, true); | ||
| } | ||
@@ -274,6 +283,7 @@ } | ||
| _watchWithFsEvents(watchPath, realPath, transform, globFilter) { | ||
| if (this.fsw.closed) return; | ||
| if (this.fsw._isIgnored(watchPath)) return; | ||
| const opts = this.fsw.options; | ||
| const watchCallback = async (fullPath, flags, info) => { | ||
| if (this.fsw.closed) return; | ||
| if ( | ||
@@ -301,2 +311,5 @@ opts.depth !== undefined && | ||
| } catch (error) {} | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| if (this.checkIgnored(path, stats)) return; | ||
@@ -327,3 +340,4 @@ if (stats) { | ||
| watchCallback, | ||
| this.fsw._emitRaw | ||
| this.fsw._emitRaw, | ||
| this.fsw | ||
| ); | ||
@@ -352,2 +366,5 @@ | ||
| const linkTarget = await realpath(linkPath); | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| if (this.fsw._isIgnored(linkTarget)) { | ||
@@ -395,3 +412,3 @@ return this.fsw._emitReady(); | ||
| if (!opts.ignoreInitial || forceAdd === true) { | ||
| this.fsw._emit(isDir ? 'addDir' : 'add', pp, stats); | ||
| this.fsw._emit(isDir ? EV_ADD_DIR : EV_ADD, pp, stats); | ||
| } | ||
@@ -398,0 +415,0 @@ } |
+114
-52
@@ -15,3 +15,50 @@ 'use strict'; | ||
| const statMethods = { lstat, stat }; | ||
| const isWindows = process.platform === 'win32'; | ||
| const emptyFn = () => {}; | ||
| const KEY_LISTENERS = 'listeners'; | ||
| const KEY_ERR = 'errHandlers'; | ||
| const KEY_RAW = 'rawEmitters'; | ||
| const HANDLER_KEYS = [KEY_LISTENERS, KEY_ERR, KEY_RAW]; | ||
| const EV_CHANGE = 'change'; | ||
| const EV_ADD = 'add'; | ||
| const EV_ADD_DIR = 'addDir'; | ||
| // TODO: emit errors properly. Example: EMFILE on Macos. | ||
| const foreach = (val, fn) => { | ||
| if (val instanceof Set) { | ||
| val.forEach(fn); | ||
| } else { | ||
| fn(val); | ||
| } | ||
| }; | ||
| const addAndConvert = (main, prop, item) => { | ||
| let container = main[prop]; | ||
| if (!(container instanceof Set)) { | ||
| main[prop] = container = new Set([container]); | ||
| } | ||
| container.add(item); | ||
| }; | ||
| const clearItem = cont => key => { | ||
| const set = cont[key]; | ||
| if (set instanceof Set) { | ||
| set.clear(); | ||
| } else { | ||
| delete cont[key]; | ||
| } | ||
| }; | ||
| const delFromSet = (main, prop, item) => { | ||
| const container = main[prop]; | ||
| if (!(container instanceof Set)) { | ||
| if (container === item) delete main[prop]; | ||
| } else { | ||
| container.delete(item); | ||
| } | ||
| }; | ||
| const isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val; | ||
| /** | ||
@@ -39,4 +86,2 @@ * @typedef {String} Path | ||
| const FsWatchInstances = new Map(); | ||
| const emptyFn = () => {}; | ||
| const FUNCTIONS = ['listeners', 'errHandlers', 'rawEmitters']; | ||
@@ -61,3 +106,3 @@ /** | ||
| fsWatchBroadcast( | ||
| sysPath.resolve(path, evPath), 'listeners', sysPath.join(path, evPath) | ||
| sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath) | ||
| ); | ||
@@ -84,3 +129,3 @@ } | ||
| if (!cont) return; | ||
| cont[type].forEach((listener) => { | ||
| foreach(cont[type], (listener) => { | ||
| listener(val1, val2, val3); | ||
@@ -99,5 +144,3 @@ }); | ||
| const setFsWatchListener = (path, fullPath, options, handlers) => { | ||
| const listener = handlers.listener; | ||
| const errHandler = handlers.errHandler; | ||
| const rawEmitter = handlers.rawEmitter; | ||
| const {listener, errHandler, rawEmitter} = handlers; | ||
| let cont = FsWatchInstances.get(fullPath); | ||
@@ -114,5 +157,5 @@ | ||
| if (cont) { | ||
| cont.listeners.add(listener); | ||
| cont.errHandlers.add(errHandler); | ||
| cont.rawEmitters.add(rawEmitter); | ||
| addAndConvert(cont, KEY_LISTENERS, listener); | ||
| addAndConvert(cont, KEY_ERR, errHandler); | ||
| addAndConvert(cont, KEY_RAW, rawEmitter); | ||
| } else { | ||
@@ -122,12 +165,12 @@ watcher = createFsWatchInstance( | ||
| options, | ||
| fsWatchBroadcast.bind(null, fullPath, 'listeners'), | ||
| fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), | ||
| errHandler, // no need to use broadcast here | ||
| fsWatchBroadcast.bind(null, fullPath, 'rawEmitters') | ||
| fsWatchBroadcast.bind(null, fullPath, KEY_RAW) | ||
| ); | ||
| if (!watcher) return; | ||
| const broadcastErr = fsWatchBroadcast.bind(null, fullPath, 'errHandlers'); | ||
| watcher.on('error', async (error) => { | ||
| const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR); | ||
| cont.watcherUnusable = true; // documented since Node 10.4.1 | ||
| // Workaround for https://github.com/joyent/node/issues/4337 | ||
| if (process.platform === 'win32' && error.code === 'EPERM') { | ||
| if (isWindows && error.code === 'EPERM') { | ||
| try { | ||
@@ -143,5 +186,5 @@ const fd = await open(path, 'r'); | ||
| cont = { | ||
| listeners: new Set([listener]), | ||
| errHandlers: new Set([errHandler]), | ||
| rawEmitters: new Set([rawEmitter]), | ||
| listeners: listener, | ||
| errHandlers: errHandler, | ||
| rawEmitters: rawEmitter, | ||
| watcher: watcher | ||
@@ -156,6 +199,6 @@ }; | ||
| return () => { | ||
| cont.listeners.delete(listener); | ||
| cont.errHandlers.delete(errHandler); | ||
| cont.rawEmitters.delete(rawEmitter); | ||
| if (!cont.listeners.size) { | ||
| delFromSet(cont, KEY_LISTENERS, listener); | ||
| delFromSet(cont, KEY_ERR, errHandler); | ||
| delFromSet(cont, KEY_RAW, rawEmitter); | ||
| if (isEmptySet(cont.listeners)) { | ||
| // Check to protect against issue gh-730. | ||
@@ -166,8 +209,4 @@ // if (cont.watcherUnusable) { | ||
| FsWatchInstances.delete(fullPath); | ||
| FUNCTIONS.forEach(key => { | ||
| const set = cont[key]; | ||
| set.clear(); | ||
| Object.freeze(set); | ||
| }); | ||
| cont.watcher = null; | ||
| HANDLER_KEYS.forEach(clearItem(cont)); | ||
| cont.watcher = undefined; | ||
| Object.freeze(cont); | ||
@@ -209,22 +248,23 @@ } | ||
| fs.unwatchFile(fullPath); | ||
| cont = null; | ||
| cont = undefined; | ||
| } | ||
| if (cont) { | ||
| cont.listeners.add(listener); | ||
| cont.rawEmitters.add(rawEmitter); | ||
| addAndConvert(cont, KEY_LISTENERS, listener); | ||
| addAndConvert(cont, KEY_RAW, rawEmitter); | ||
| } else { | ||
| listeners.add(listener); | ||
| rawEmitters.add(rawEmitter); | ||
| // TODO | ||
| // listeners.add(listener); | ||
| // rawEmitters.add(rawEmitter); | ||
| cont = { | ||
| listeners: listeners, | ||
| rawEmitters: rawEmitters, | ||
| listeners: listener, | ||
| rawEmitters: rawEmitter, | ||
| options: options, | ||
| watcher: fs.watchFile(fullPath, options, (curr, prev) => { | ||
| cont.rawEmitters.forEach((rawEmitter) => { | ||
| rawEmitter('change', fullPath, {curr: curr, prev: prev}); | ||
| foreach(cont.rawEmitters, (rawEmitter) => { | ||
| rawEmitter(EV_CHANGE, fullPath, {curr, prev}); | ||
| }); | ||
| const currmtime = curr.mtimeMs; | ||
| if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) { | ||
| cont.listeners.forEach((listener) => listener(path, curr)); | ||
| foreach(cont.listeners, (listener) => listener(path, curr)); | ||
| } | ||
@@ -239,11 +279,10 @@ }) | ||
| // instance if there are no more listeners left. | ||
| return () => { | ||
| cont.listeners.delete(listener); | ||
| cont.rawEmitters.delete(rawEmitter); | ||
| if (!cont.listeners.size) { | ||
| return () => { | ||
| delFromSet(cont, KEY_LISTENERS, listener); | ||
| delFromSet(cont, KEY_RAW, rawEmitter); | ||
| if (isEmptySet(cont.listeners)) { | ||
| FsWatchFileInstances.delete(fullPath); | ||
| fs.unwatchFile(fullPath); | ||
| cont.options = cont.watcher = null; | ||
| cont.options = cont.watcher = undefined; | ||
| Object.freeze(cont); | ||
| Object.freeze(cont.listeners); | ||
| } | ||
@@ -333,3 +372,3 @@ }; | ||
| if (!at || at <= mt || mt !== prevStats.mtimeMs) { | ||
| this.fsw._emit('change', file, newStats); | ||
| this.fsw._emit(EV_CHANGE, file, newStats); | ||
| } | ||
@@ -347,3 +386,3 @@ prevStats = newStats; | ||
| if (!at || at <= mt || mt !== prevStats.mtimeMs) { | ||
| this.fsw._emit('change', file, newStats); | ||
| this.fsw._emit(EV_CHANGE, file, newStats); | ||
| } | ||
@@ -356,4 +395,4 @@ prevStats = newStats; | ||
| if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) { | ||
| if (!this.fsw._throttle('add', file, 0)) return; | ||
| this.fsw._emit('add', file, stats); | ||
| if (!this.fsw._throttle(EV_ADD, file, 0)) return; | ||
| this.fsw._emit(EV_ADD, file, stats); | ||
| } | ||
@@ -383,6 +422,9 @@ | ||
| const linkPath = await fsrealpath(path); | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| if (dir.has(item)) { | ||
| if (this.fsw._symlinkPaths.get(full) !== linkPath) { | ||
| this.fsw._symlinkPaths.set(full, linkPath); | ||
| this.fsw._emit('change', path, entry.stats); | ||
| this.fsw._emit(EV_CHANGE, path, entry.stats); | ||
| } | ||
@@ -392,3 +434,3 @@ } else { | ||
| this.fsw._symlinkPaths.set(full, linkPath); | ||
| this.fsw._emit('add', path, entry.stats); | ||
| this.fsw._emit(EV_ADD, path, entry.stats); | ||
| } | ||
@@ -431,5 +473,10 @@ this.fsw._emitReady(); | ||
| if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) | ||
| if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) { | ||
| return; | ||
| } | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| // Files that present in current directory snapshot | ||
@@ -491,3 +538,3 @@ // but absent in previous are added to watch list and | ||
| if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) { | ||
| if (!wh.hasGlob || wh.globFilter(dir)) this.fsw._emit('addDir', dir, stats); | ||
| if (!wh.hasGlob || wh.globFilter(dir)) this.fsw._emit(EV_ADD_DIR, dir, stats); | ||
| } | ||
@@ -507,2 +554,5 @@ | ||
| await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler); | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| } | ||
@@ -560,3 +610,9 @@ | ||
| const targetPath = follow ? await fsrealpath(path) : path; | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath); | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| // preserve this symlink's target path | ||
@@ -568,6 +624,12 @@ if (path !== targetPath && targetPath !== undefined) { | ||
| const targetPath = follow ? await fsrealpath(path) : path; | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
| const parent = sysPath.dirname(wh.watchPath); | ||
| this.fsw._getWatchedDir(parent).add(wh.watchPath); | ||
| this.fsw._emit('add', wh.watchPath, stats); | ||
| this.fsw._emit(EV_ADD, wh.watchPath, stats); | ||
| closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath); | ||
| if (this.fsw.closed) { | ||
| return; | ||
| } | ||
@@ -574,0 +636,0 @@ // preserve this symlink's target path |
+10
-10
| { | ||
| "name": "chokidar", | ||
| "description": "A neat wrapper around node.js fs.watch / fs.watchFile / fsevents.", | ||
| "version": "3.1.1", | ||
| "version": "3.2.0", | ||
| "homepage": "https://github.com/paulmillr/chokidar", | ||
@@ -12,15 +12,15 @@ "author": "Paul Miller (https://paulmillr.com)", | ||
| "engines": { | ||
| "node": ">= 8" | ||
| "node": ">= 8.16" | ||
| }, | ||
| "dependencies": { | ||
| "anymatch": "^3.1.0", | ||
| "braces": "^3.0.2", | ||
| "glob-parent": "^5.0.0", | ||
| "is-binary-path": "^2.1.0", | ||
| "is-glob": "^4.0.1", | ||
| "normalize-path": "^3.0.0", | ||
| "readdirp": "^3.1.1" | ||
| "anymatch": "~3.1.1", | ||
| "braces": "~3.0.2", | ||
| "glob-parent": "~5.1.0", | ||
| "is-binary-path": "~2.1.0", | ||
| "is-glob": "~4.0.1", | ||
| "normalize-path": "~3.0.0", | ||
| "readdirp": "~3.1.3" | ||
| }, | ||
| "optionalDependencies": { | ||
| "fsevents": "^2.0.6" | ||
| "fsevents": "~2.1.0" | ||
| }, | ||
@@ -27,0 +27,0 @@ "devDependencies": { |
+2
-1
@@ -284,3 +284,4 @@ # Chokidar [](https://github.com/paulmillr/chokidar) [](https://github.com/paulmillr/chokidar) | ||
| - **v3.1 (Sep 16, 2019):** dotfiles are no longer filtered out by default. Use `ignored` option if needed. Improve Linux performance by 50%. | ||
| - **v3.2 (Oct 1, 2019):** Improve Linux RAM usage by 50%. Stability optimizations. Windows glob fixes. | ||
| - **v3.1 (Sep 16, 2019):** dotfiles are no longer filtered out by default. Use `ignored` option if needed. Improve initial Linux scan time by 50%. | ||
| - **v3 (Apr 30, 2019):** massive CPU & RAM consumption improvements; reduces deps / package size by a factor of 17x and bumps Node.js requirement to v8.16 and higher. | ||
@@ -287,0 +288,0 @@ - **v2 (Dec 29, 2017):** Globs are now posix-style-only; without windows support. Tons of bugfixes. |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
84523
2.75%1967
4.63%294
0.34%20
11.11%+ Added
+ Added
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated
Updated
Updated