Comparing version 3.1.1 to 3.2.0
134
index.js
'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 @@ }); |
@@ -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 @@ } |
@@ -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 |
{ | ||
"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": { |
@@ -284,3 +284,4 @@ # Chokidar [![Weekly downloads](https://img.shields.io/npm/dw/chokidar.svg)](https://github.com/paulmillr/chokidar) [![Yearly downloads](https://img.shields.io/npm/dy/chokidar.svg)](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. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
84523
1967
294
+ Addedfsevents@2.1.3(transitive)
+ Addedreaddirp@3.1.3(transitive)
- Removedfsevents@2.3.3(transitive)
- Removedreaddirp@3.6.0(transitive)
Updatedanymatch@~3.1.1
Updatedbraces@~3.0.2
Updatedglob-parent@~5.1.0
Updatedis-binary-path@~2.1.0
Updatedis-glob@~4.0.1
Updatednormalize-path@~3.0.0
Updatedreaddirp@~3.1.3