Comparing version 2.0.0-beta.3 to 2.0.0-beta.4
@@ -20,5 +20,6 @@ /* | ||
const WATCHPACK_POLLING = process.env.WATCHPACK_POLLING; | ||
const FORCE_POLLING = `${+WATCHPACK_POLLING}` === WATCHPACK_POLLING ? | ||
+WATCHPACK_POLLING : | ||
!!WATCHPACK_POLLING && WATCHPACK_POLLING !== "false"; | ||
const FORCE_POLLING = | ||
`${+WATCHPACK_POLLING}` === WATCHPACK_POLLING | ||
? +WATCHPACK_POLLING | ||
: !!WATCHPACK_POLLING && WATCHPACK_POLLING !== "false"; | ||
@@ -39,3 +40,3 @@ function withoutCase(str) { | ||
const startTime = this.startTime; | ||
if(typeof startTime !== "number") return !initial; | ||
if (typeof startTime !== "number") return !initial; | ||
return startTime <= mtime; | ||
@@ -52,3 +53,3 @@ } | ||
super(); | ||
if(FORCE_POLLING) { | ||
if (FORCE_POLLING) { | ||
options.poll = FORCE_POLLING; | ||
@@ -65,5 +66,10 @@ } | ||
this.initialScan = true; | ||
this.ignored = options.ignored; | ||
this.nestedWatching = false; | ||
this.polledWatching = typeof options.poll === "number" ? options.poll : options.poll ? 5007 : false; | ||
this.filesWatchListener = new Map(); | ||
this.polledWatching = | ||
typeof options.poll === "number" | ||
? options.poll | ||
: options.poll | ||
? 5007 | ||
: false; | ||
this.initialScanRemoved = new Set(); | ||
@@ -77,2 +83,3 @@ this.watchers = new Map(); | ||
this.scanAgain = false; | ||
this.scanAgainInitial = false; | ||
@@ -83,24 +90,22 @@ this.createWatcher(); | ||
checkIgnore(path) { | ||
if (!this.ignored) return false; | ||
path = path.replace(/\\/g, "/"); | ||
return this.ignored.test(path); | ||
} | ||
createWatcher() { | ||
try { | ||
// TODO options.ignored | ||
if(this.polledWatching) { | ||
const listener = this.onWatchFileEvent.bind(this); | ||
fs.watchFile(this.path, { persistent: true, interval: this.polledWatching }, listener); | ||
// Fallback to caputure too late attached watchers | ||
const timeout = setTimeout(() => { | ||
fs.stat(this.path, (err, stats) => { | ||
if(!err) { | ||
listener(stats); | ||
} | ||
}) | ||
}, 1000); | ||
if (this.polledWatching) { | ||
// Poll for changes | ||
const interval = setInterval(() => { | ||
this.doScan(false); | ||
}, this.polledWatching); | ||
this.watcher = { | ||
close: () => { | ||
clearTimeout(timeout); | ||
fs.unwatchFile(this.path, listener); | ||
clearInterval(interval); | ||
} | ||
}; | ||
} else { | ||
if(IS_OSX) { | ||
if (IS_OSX) { | ||
this.watchInParentDirectory(); | ||
@@ -112,3 +117,3 @@ } | ||
} | ||
} catch(err) { | ||
} catch (err) { | ||
this.onWatcherError(err); | ||
@@ -120,4 +125,4 @@ } | ||
const watchers = this.watchers.get(withoutCase(path)); | ||
if(watchers !== undefined) { | ||
for(const w of watchers) { | ||
if (watchers !== undefined) { | ||
for (const w of watchers) { | ||
fn(w); | ||
@@ -129,3 +134,3 @@ } | ||
setMissing(itemPath, initial, type) { | ||
if(this.initialScan) { | ||
if (this.initialScan) { | ||
this.initialScanRemoved.add(itemPath); | ||
@@ -135,10 +140,11 @@ } | ||
const oldDirectory = this.directories.get(itemPath); | ||
if(oldDirectory) { | ||
if(this.nestedWatching) | ||
oldDirectory.close(); | ||
if (oldDirectory) { | ||
if (this.nestedWatching) oldDirectory.close(); | ||
this.directories.delete(itemPath); | ||
this.forEachWatcher(itemPath, w => w.emit("remove", type)); | ||
if(!initial) { | ||
this.forEachWatcher(this.path, w => w.emit("change", itemPath, null, type)); | ||
if (!initial) { | ||
this.forEachWatcher(this.path, w => | ||
w.emit("change", itemPath, null, type) | ||
); | ||
} | ||
@@ -148,18 +154,12 @@ } | ||
const oldFile = this.files.get(itemPath); | ||
if(oldFile) { | ||
if (oldFile) { | ||
this.files.delete(itemPath); | ||
this.forEachWatcher(itemPath, w => w.emit("remove", type)); | ||
if(!initial) { | ||
this.forEachWatcher(this.path, w => w.emit("change", itemPath, null, type)); | ||
if (!initial) { | ||
this.forEachWatcher(this.path, w => | ||
w.emit("change", itemPath, null, type) | ||
); | ||
} | ||
} | ||
if(this.polledWatching) { | ||
const oldListener = this.filesWatchListener.get(itemPath); | ||
if(oldListener) { | ||
this.filesWatchListener.delete(itemPath); | ||
fs.unwatchFile(itemPath, oldListener); | ||
} | ||
} | ||
} | ||
@@ -169,6 +169,9 @@ | ||
const now = Date.now(); | ||
if (this.checkIgnore(filePath)) return; | ||
const old = this.files.get(filePath); | ||
let safeTime, accuracy; | ||
if(initial) { | ||
if (initial) { | ||
safeTime = Math.min(now, mtime) + FS_ACCURACY; | ||
@@ -181,3 +184,3 @@ accuracy = FS_ACCURACY; | ||
if(ignoreWhenEqual && old && old.timestamp === mtime) return; | ||
if (ignoreWhenEqual && old && old.timestamp === mtime) return; | ||
@@ -190,17 +193,13 @@ this.files.set(filePath, { | ||
if(this.polledWatching) { | ||
this._ensureFilePolling(filePath); | ||
} | ||
if(!old) { | ||
if (!old) { | ||
this.forEachWatcher(filePath, w => { | ||
if(!initial || w.checkStartTime(safeTime, initial)) { | ||
if (!initial || w.checkStartTime(safeTime, initial)) { | ||
w.emit("change", mtime, type); | ||
} | ||
}); | ||
} else if(!initial) { | ||
} else if (!initial) { | ||
this.forEachWatcher(filePath, w => w.emit("change", mtime, type)); | ||
} | ||
this.forEachWatcher(this.path, w => { | ||
if(!initial || w.checkStartTime(safeTime, initial)) { | ||
if (!initial || w.checkStartTime(safeTime, initial)) { | ||
w.emit("change", filePath, safeTime, type); | ||
@@ -212,16 +211,15 @@ } | ||
setDirectory(directoryPath, mtime, initial, type) { | ||
if(directoryPath === this.path) { | ||
if(!initial) { | ||
this.forEachWatcher(this.path, w => w.emit("change", directoryPath, mtime, type)); | ||
if (this.checkIgnore(directoryPath)) return; | ||
if (directoryPath === this.path) { | ||
if (!initial) { | ||
this.forEachWatcher(this.path, w => | ||
w.emit("change", directoryPath, mtime, type) | ||
); | ||
} | ||
} else { | ||
const old = this.directories.get(directoryPath); | ||
if(!old) { | ||
if (!old) { | ||
const now = Date.now(); | ||
if(this.polledWatching) { | ||
this._ensureFilePolling(directoryPath); | ||
} | ||
if(this.nestedWatching) { | ||
if (this.nestedWatching) { | ||
this.createNestedWatcher(directoryPath); | ||
@@ -233,3 +231,3 @@ } else { | ||
let safeTime; | ||
if(initial) { | ||
if (initial) { | ||
safeTime = Math.min(now, mtime) + FS_ACCURACY; | ||
@@ -241,3 +239,3 @@ } else { | ||
this.forEachWatcher(directoryPath, w => { | ||
if(!initial || w.checkStartTime(safeTime, false)) { | ||
if (!initial || w.checkStartTime(safeTime, false)) { | ||
w.emit("change", mtime, type); | ||
@@ -247,3 +245,3 @@ } | ||
this.forEachWatcher(this.path, w => { | ||
if(!initial || w.checkStartTime(safeTime, initial)) { | ||
if (!initial || w.checkStartTime(safeTime, initial)) { | ||
w.emit("change", directoryPath, safeTime, type); | ||
@@ -257,6 +255,10 @@ } | ||
createNestedWatcher(directoryPath) { | ||
const watcher = watcherManager.watchDirectory(directoryPath, this.options, 1); | ||
const watcher = watcherManager.watchDirectory( | ||
directoryPath, | ||
this.options, | ||
1 | ||
); | ||
watcher.on("change", (filePath, mtime, type) => { | ||
this.forEachWatcher(this.path, w => { | ||
if(w.checkStartTime(mtime, false)) { | ||
if (w.checkStartTime(mtime, false)) { | ||
w.emit("change", filePath, mtime, type); | ||
@@ -269,28 +271,11 @@ } | ||
_ensureFilePolling(path) { | ||
if(!this.filesWatchListener.has(path)) { | ||
const listener = this.onWatchFileChildEvent.bind(this, path); | ||
this.filesWatchListener.set(path, listener); | ||
fs.watchFile(path, { persistent: true, interval: this.polledWatching }, listener); | ||
// It's possible that we miss the first event | ||
// so we have a fallback after 1s | ||
setTimeout(() => { | ||
fs.stat(path, (err, stats) => { | ||
if(!err) { | ||
listener(stats); | ||
} | ||
}) | ||
}, 1000); | ||
} | ||
} | ||
setNestedWatching(flag) { | ||
if(this.nestedWatching !== !!flag) { | ||
if (this.nestedWatching !== !!flag) { | ||
this.nestedWatching = !!flag; | ||
if(this.nestedWatching) { | ||
for(const directory of this.directories.keys()) { | ||
if (this.nestedWatching) { | ||
for (const directory of this.directories.keys()) { | ||
this.createNestedWatcher(directory); | ||
} | ||
} else { | ||
for(const [directory, watcher] of this.directories) { | ||
for (const [directory, watcher] of this.directories) { | ||
watcher.close(); | ||
@@ -306,3 +291,3 @@ this.directories.set(directory, true); | ||
let watchers = this.watchers.get(key); | ||
if(watchers === undefined) { | ||
if (watchers === undefined) { | ||
watchers = new Set(); | ||
@@ -315,23 +300,20 @@ this.watchers.set(key, watchers); | ||
watchers.delete(watcher); | ||
if(watchers.size === 0) { | ||
if (watchers.size === 0) { | ||
this.watchers.delete(key); | ||
if(this.path === filePath) | ||
this.setNestedWatching(false); | ||
if (this.path === filePath) this.setNestedWatching(false); | ||
} | ||
if(--this.refs <= 0) | ||
this.close(); | ||
if (--this.refs <= 0) this.close(); | ||
}); | ||
watchers.add(watcher); | ||
let safeTime; | ||
if(filePath === this.path) { | ||
if (filePath === this.path) { | ||
this.setNestedWatching(true); | ||
safeTime = this.lastWatchEvent; | ||
for(const entry of this.files.values()) { | ||
for (const entry of this.files.values()) { | ||
fixupEntryAccuracy(entry); | ||
safeTime = Math.max(safeTime, entry.safeTime); | ||
} | ||
} else { | ||
const entry = this.files.get(filePath); | ||
if(entry) { | ||
if (entry) { | ||
fixupEntryAccuracy(entry); | ||
@@ -344,7 +326,6 @@ safeTime = entry.safeTime; | ||
process.nextTick(() => { | ||
if(this.closed) return; | ||
if(safeTime) { | ||
if(safeTime >= startTime) | ||
watcher.emit("change", safeTime); | ||
} else if(this.initialScan && this.initialScanRemoved.has(filePath)) { | ||
if (this.closed) return; | ||
if (safeTime) { | ||
if (safeTime >= startTime) watcher.emit("change", safeTime); | ||
} else if (this.initialScan && this.initialScanRemoved.has(filePath)) { | ||
watcher.emit("remove"); | ||
@@ -357,4 +338,4 @@ } | ||
onWatchEvent(eventType, filename) { | ||
if(this.closed) return; | ||
if(!filename) { | ||
if (this.closed) return; | ||
if (!filename) { | ||
// In some cases no filename is provided | ||
@@ -367,11 +348,14 @@ // This seem to happen on windows | ||
} | ||
if(this._activeEvents.get(filename) === undefined) { | ||
const filePath = path.join(this.path, filename); | ||
if (this.checkIgnore(filePath)) return; | ||
if (this._activeEvents.get(filename) === undefined) { | ||
this._activeEvents.set(filename, false); | ||
const checkStats = () => { | ||
if(this.closed) return; | ||
if (this.closed) return; | ||
this._activeEvents.set(filename, false); | ||
const filePath = path.join(this.path, filename); | ||
fs.stat(filePath, (err, stats) => { | ||
if(this.closed) return; | ||
if(this._activeEvents.get(filename) === true) { | ||
if (this.closed) return; | ||
if (this._activeEvents.get(filename) === true) { | ||
process.nextTick(checkStats); | ||
@@ -383,9 +367,13 @@ return; | ||
// EPERM happens when the containing directory doesn't exist | ||
if(err) { | ||
if(err.code !== "ENOENT" && err.code !== "EPERM" && err.code !== "EBUSY") { | ||
if (err) { | ||
if ( | ||
err.code !== "ENOENT" && | ||
err.code !== "EPERM" && | ||
err.code !== "EBUSY" | ||
) { | ||
this.onStatsError(err); | ||
} else { | ||
if(filename === path.basename(this.path)) { | ||
if (filename === path.basename(this.path)) { | ||
// This may indicate that the directory itself was removed | ||
if(!fs.existsSync(this.path)) { | ||
if (!fs.existsSync(this.path)) { | ||
this.onDirectoryRemoved(); | ||
@@ -397,11 +385,22 @@ } | ||
this.lastWatchEvent = Date.now(); | ||
if(!stats) { | ||
if (!stats) { | ||
this.setMissing(filePath, false, eventType); | ||
} else if(stats.isDirectory()) { | ||
this.setDirectory(filePath, +stats.mtime || +stats.ctime || 1, false, eventType); | ||
} else if (stats.isDirectory()) { | ||
this.setDirectory( | ||
filePath, | ||
+stats.mtime || +stats.ctime || 1, | ||
false, | ||
eventType | ||
); | ||
} else { | ||
if(stats.mtime) { | ||
if (stats.mtime) { | ||
ensureFsAccuracy(stats.mtime); | ||
} | ||
this.setFileTime(filePath, +stats.mtime || +stats.ctime || 1, false, false, eventType); | ||
this.setFileTime( | ||
filePath, | ||
+stats.mtime || +stats.ctime || 1, | ||
false, | ||
false, | ||
eventType | ||
); | ||
} | ||
@@ -416,31 +415,6 @@ }); | ||
onWatchFileEvent(current) { | ||
if(this.closed) return; | ||
if(current.isDirectory()) { | ||
this.lastWatchEvent = Date.now(); | ||
this.doScan(false); | ||
} else { | ||
this.onDirectoryRemoved(); | ||
} | ||
} | ||
onWatchFileChildEvent(path, stats) { | ||
if(this.closed) return; | ||
this.lastWatchEvent = Date.now(); | ||
if(stats.isFile()) { | ||
if(stats.mtime) { | ||
ensureFsAccuracy(stats.mtime); | ||
} | ||
this.setFileTime(path, +stats.mtime || +stats.ctime || 1, false, true, "poll"); | ||
} else if(stats.isDirectory()) { | ||
this.setDirectory(path, +stats.mtime || +stats.ctime || 1, false, "poll"); | ||
} else { | ||
this.setMissing(path, false, "poll"); | ||
} | ||
} | ||
onWatcherError(err) { | ||
if(this.closed) return; | ||
if(err) { | ||
if(err.code !== "EPERM" && err.code !== "ENOENT") { | ||
if (this.closed) return; | ||
if (err) { | ||
if (err.code !== "EPERM" && err.code !== "ENOENT") { | ||
console.error("Watchpack Error (watcher): " + err); | ||
@@ -453,3 +427,3 @@ } | ||
onStatsError(err) { | ||
if(err) { | ||
if (err) { | ||
console.error("Watchpack Error (stats): " + err); | ||
@@ -460,3 +434,3 @@ } | ||
onScanError(err) { | ||
if(err) { | ||
if (err) { | ||
console.error("Watchpack Error (initial scan): " + err); | ||
@@ -467,11 +441,10 @@ } | ||
onDirectoryRemoved() { | ||
if(this.watcher) { | ||
this.watcher.close(), | ||
this.watcher = null; | ||
if (this.watcher) { | ||
this.watcher.close(), (this.watcher = null); | ||
} | ||
this.watchInParentDirectory(); | ||
for(const directory of this.directories.keys()) { | ||
for (const directory of this.directories.keys()) { | ||
this.setMissing(directory, null, "directory-removed"); | ||
} | ||
for(const file of this.files.keys()) { | ||
for (const file of this.files.keys()) { | ||
this.setMissing(file, null, "directory-removed"); | ||
@@ -482,15 +455,15 @@ } | ||
watchInParentDirectory() { | ||
if(!this.parentWatcher) { | ||
if (!this.parentWatcher) { | ||
const parentDir = path.dirname(this.path); | ||
// avoid watching in the root directory | ||
// removing directories in the root directory is not supported | ||
if(path.dirname(parentDir) === parentDir) return; | ||
if (path.dirname(parentDir) === parentDir) return; | ||
this.parentWatcher = watcherManager.watchFile(this.path, this.options, 1); | ||
this.parentWatcher.on("change", (mtime, type) => { | ||
if(this.closed) return; | ||
if (this.closed) return; | ||
// On non-osx platforms we don't need this watcher to detect | ||
// directory removal, as a EPERM error indicates that | ||
if(!IS_OSX && this.parentWatcher) { | ||
if ((!IS_OSX || this.polledWatching) && this.parentWatcher) { | ||
this.parentWatcher.close(); | ||
@@ -500,3 +473,3 @@ this.parentWatcher = null; | ||
// Try to create the watcher when parent directory is found | ||
if(!this.watcher) { | ||
if (!this.watcher) { | ||
this.createWatcher(); | ||
@@ -506,3 +479,5 @@ this.doScan(false); | ||
// directory was created so we emit a event | ||
this.forEachWatcher(this.path, w => w.emit("change", this.path, mtime, type)); | ||
this.forEachWatcher(this.path, w => | ||
w.emit("change", this.path, mtime, type) | ||
); | ||
} | ||
@@ -517,4 +492,9 @@ }); | ||
doScan(initial) { | ||
if(this.scanning) { | ||
this.scanAgain = true; | ||
if (this.scanning) { | ||
if (this.scanAgain) { | ||
if (!initial) this.scanAgainInitial = false; | ||
} else { | ||
this.scanAgain = true; | ||
this.scanAgainInitial = initial; | ||
} | ||
return; | ||
@@ -524,6 +504,6 @@ } | ||
fs.readdir(this.path, (err, items) => { | ||
if(this.closed) return; | ||
if(err) { | ||
if(err.code === "ENOENT" || err.code === "EPERM") { | ||
this.watchInParentDirectory(); | ||
if (this.closed) return; | ||
if (err) { | ||
if (err.code === "ENOENT" || err.code === "EPERM") { | ||
this.onDirectoryRemoved(); | ||
} else { | ||
@@ -533,5 +513,5 @@ this.onScanError(err); | ||
this.initialScan = false; | ||
if(this.scanAgain) { | ||
if (this.scanAgain) { | ||
this.scanAgain = false; | ||
this.doScan(false); | ||
this.doScan(this.scanAgainInitial); | ||
} else { | ||
@@ -543,8 +523,13 @@ this.scanning = false; | ||
const itemPaths = new Set(items.map(item => path.join(this.path, item))); | ||
for(const file of this.files) { | ||
if(!itemPaths.has(file)) { | ||
for (const file of this.files.keys()) { | ||
if (!itemPaths.has(file)) { | ||
this.setMissing(file, initial, "scan (missing)"); | ||
} | ||
} | ||
if(this.scanAgain) { | ||
for (const directory of this.directories.keys()) { | ||
if (!itemPaths.has(directory)) { | ||
this.setMissing(directory, initial, "scan (missing)"); | ||
} | ||
} | ||
if (this.scanAgain) { | ||
// Early repeat of scan | ||
@@ -555,36 +540,55 @@ this.scanAgain = false; | ||
} | ||
async.forEach(itemPaths, (itemPath, callback) => { | ||
fs.stat(itemPath, (err2, stats) => { | ||
if(this.closed) return; | ||
if(err2) { | ||
if(err2.code === "ENOENT" || err2.code === "EPERM" || err2.code === "EBUSY") { | ||
this.setMissing(itemPath, initial, "scan (" + err2.code + ")") | ||
} else { | ||
this.onScanError(err2); | ||
async.forEach( | ||
itemPaths, | ||
(itemPath, callback) => { | ||
fs.stat(itemPath, (err2, stats) => { | ||
if (this.closed) return; | ||
if (err2) { | ||
if ( | ||
err2.code === "ENOENT" || | ||
err2.code === "EPERM" || | ||
err2.code === "EBUSY" | ||
) { | ||
this.setMissing(itemPath, initial, "scan (" + err2.code + ")"); | ||
} else { | ||
this.onScanError(err2); | ||
} | ||
callback(); | ||
return; | ||
} | ||
if (stats.isFile()) { | ||
if (stats.mtime) { | ||
ensureFsAccuracy(stats.mtime); | ||
} | ||
this.setFileTime( | ||
itemPath, | ||
+stats.mtime || +stats.ctime || 1, | ||
initial, | ||
true, | ||
"scan (file)" | ||
); | ||
} else if (stats.isDirectory()) { | ||
if (!initial || !this.directories.has(itemPath)) | ||
this.setDirectory( | ||
itemPath, | ||
+stats.mtime || +stats.ctime || 1, | ||
initial, | ||
"scan (dir)" | ||
); | ||
} | ||
callback(); | ||
return; | ||
}); | ||
}, | ||
() => { | ||
if (this.closed) return; | ||
this.initialScan = false; | ||
this.initialScanRemoved = null; | ||
if (this.scanAgain) { | ||
this.scanAgain = false; | ||
this.doScan(this.scanAgainInitial); | ||
} else { | ||
this.scanning = false; | ||
} | ||
if(stats.isFile()) { | ||
if(stats.mtime) { | ||
ensureFsAccuracy(stats.mtime); | ||
} | ||
this.setFileTime(itemPath, +stats.mtime || +stats.ctime || 1, initial, true, "scan (file)"); | ||
} else if(stats.isDirectory()) { | ||
if(!initial || !this.directories.has(itemPath)) | ||
this.setDirectory(itemPath, +stats.mtime || +stats.ctime || 1, initial, "scan (dir)"); | ||
} | ||
callback(); | ||
}); | ||
}, () => { | ||
if(this.closed) return; | ||
this.initialScan = false; | ||
this.initialScanRemoved = null; | ||
if(this.scanAgain) { | ||
this.scanAgain = false; | ||
this.doScan(false); | ||
} else { | ||
this.scanning = false; | ||
} | ||
}); | ||
); | ||
}); | ||
@@ -596,3 +600,3 @@ } | ||
let safeTime = this.lastWatchEvent; | ||
for(const [file, entry] of this.files) { | ||
for (const [file, entry] of this.files) { | ||
fixupEntryAccuracy(entry); | ||
@@ -602,4 +606,4 @@ safeTime = Math.max(safeTime, entry.safeTime); | ||
} | ||
if(this.nestedWatching) { | ||
for(const w of this.directories.values()) { | ||
if (this.nestedWatching) { | ||
for (const w of this.directories.values()) { | ||
const times = w.directoryWatcher.getTimes(); | ||
@@ -614,7 +618,7 @@ Object.keys(times).forEach(function(file) { | ||
} | ||
if(!this.initialScan) { | ||
for(const watchers of this.watchers.values()) { | ||
for(const watcher of watchers) { | ||
if (!this.initialScan) { | ||
for (const watchers of this.watchers.values()) { | ||
for (const watcher of watchers) { | ||
const path = watcher.path; | ||
if(!Object.prototype.hasOwnProperty.call(obj, path)) { | ||
if (!Object.prototype.hasOwnProperty.call(obj, path)) { | ||
obj[path] = null; | ||
@@ -631,3 +635,3 @@ } | ||
let safeTime = this.lastWatchEvent; | ||
for(const [file, entry] of this.files) { | ||
for (const [file, entry] of this.files) { | ||
fixupEntryAccuracy(entry); | ||
@@ -637,7 +641,7 @@ safeTime = Math.max(safeTime, entry.safeTime); | ||
} | ||
if(this.nestedWatching) { | ||
for(const w of this.directories.values()) { | ||
if (this.nestedWatching) { | ||
for (const w of this.directories.values()) { | ||
const timeInfoEntries = w.directoryWatcher.getTimeInfoEntries(); | ||
for(const [file, entry] of timeInfoEntries) { | ||
if(entry) { | ||
for (const [file, entry] of timeInfoEntries) { | ||
if (entry) { | ||
safeTime = Math.max(safeTime, entry.safeTime); | ||
@@ -652,3 +656,3 @@ } | ||
} else { | ||
for(const dir of this.directories.keys()) { | ||
for (const dir of this.directories.keys()) { | ||
// No additional info about this directory | ||
@@ -659,7 +663,7 @@ map.set(dir, EXISTANCE_ONLY_TIME_ENTRY); | ||
} | ||
if(!this.initialScan) { | ||
for(const watchers of this.watchers.values()) { | ||
for(const watcher of watchers) { | ||
if (!this.initialScan) { | ||
for (const watchers of this.watchers.values()) { | ||
for (const watcher of watchers) { | ||
const path = watcher.path; | ||
if(!map.has(path)) { | ||
if (!map.has(path)) { | ||
map.set(path, null); | ||
@@ -676,8 +680,8 @@ } | ||
this.initialScan = false; | ||
if(this.watcher) { | ||
if (this.watcher) { | ||
this.watcher.close(); | ||
this.watcher = null; | ||
} | ||
if(this.nestedWatching) { | ||
for(const w of this.directories.values()) { | ||
if (this.nestedWatching) { | ||
for (const w of this.directories.values()) { | ||
w.close(); | ||
@@ -687,7 +691,3 @@ } | ||
} | ||
for(const [file, listener] of this.filesWatchListener) { | ||
fs.unwatchFile(file, listener); | ||
} | ||
this.filesWatchListener.clear(); | ||
if(this.parentWatcher) { | ||
if (this.parentWatcher) { | ||
this.parentWatcher.close(); | ||
@@ -704,3 +704,3 @@ this.parentWatcher = null; | ||
function fixupEntryAccuracy(entry) { | ||
if(entry.accuracy > FS_ACCURACY) { | ||
if (entry.accuracy > FS_ACCURACY) { | ||
entry.safeTime = entry.safeTime - entry.accuracy + FS_ACCURACY; | ||
@@ -712,9 +712,6 @@ entry.accuracy = FS_ACCURACY; | ||
function ensureFsAccuracy(mtime) { | ||
if(!mtime) return; | ||
if(FS_ACCURACY > 1 && mtime % 1 !== 0) | ||
FS_ACCURACY = 1; | ||
else if(FS_ACCURACY > 10 && mtime % 10 !== 0) | ||
FS_ACCURACY = 10; | ||
else if(FS_ACCURACY > 100 && mtime % 100 !== 0) | ||
FS_ACCURACY = 100; | ||
if (!mtime) return; | ||
if (FS_ACCURACY > 1 && mtime % 1 !== 0) FS_ACCURACY = 1; | ||
else if (FS_ACCURACY > 10 && mtime % 10 !== 0) FS_ACCURACY = 10; | ||
else if (FS_ACCURACY > 100 && mtime % 100 !== 0) FS_ACCURACY = 100; | ||
} |
@@ -17,3 +17,3 @@ /* | ||
getDirectoryWatcher(directory, options) { | ||
if(DirectoryWatcher === undefined) { | ||
if (DirectoryWatcher === undefined) { | ||
DirectoryWatcher = require("./DirectoryWatcher"); | ||
@@ -24,3 +24,3 @@ } | ||
const watcher = this.directoryWatchers.get(key); | ||
if(watcher === undefined) { | ||
if (watcher === undefined) { | ||
const newWatcher = new DirectoryWatcher(directory, options); | ||
@@ -42,3 +42,6 @@ this.directoryWatchers.set(key, newWatcher); | ||
watchDirectory(directory, options, startTime) { | ||
return this.getDirectoryWatcher(directory, options).watch(directory, startTime); | ||
return this.getDirectoryWatcher(directory, options).watch( | ||
directory, | ||
startTime | ||
); | ||
} | ||
@@ -45,0 +48,0 @@ } |
@@ -9,2 +9,3 @@ /* | ||
const EventEmitter = require("events").EventEmitter; | ||
const globToRegExp = require("glob-to-regexp"); | ||
@@ -14,4 +15,4 @@ let EXISTANCE_ONLY_TIME_ENTRY; // lazy required | ||
function addWatchersToSet(watchers, set) { | ||
for(const w of watchers) { | ||
if(w !== true && !set.has(w.directoryWatcher)) { | ||
for (const w of watchers) { | ||
if (w !== true && !set.has(w.directoryWatcher)) { | ||
set.add(w.directoryWatcher); | ||
@@ -23,10 +24,29 @@ addWatchersToSet(w.directoryWatcher.directories.values(), set); | ||
const stringToRegexp = ignored => { | ||
const source = globToRegExp(ignored, { globstar: true, extended: true }) | ||
.source; | ||
const matchingStart = source.slice(0, source.length - 1) + "(?:$|\\/)"; | ||
return matchingStart; | ||
}; | ||
const ignoredToRegexp = ignored => { | ||
if (Array.isArray(ignored)) { | ||
return new RegExp(ignored.map(i => stringToRegexp(i)).join("|")); | ||
} else if (typeof ignored === "string") { | ||
return new RegExp(stringToRegexp(ignored)); | ||
} else if (ignored) { | ||
throw new Error(`Invalid option for 'ignored': ${ignored}`); | ||
} else { | ||
return undefined; | ||
} | ||
}; | ||
class Watchpack extends EventEmitter { | ||
constructor(options) { | ||
super(); | ||
if(!options) options = {}; | ||
if(!options.aggregateTimeout) options.aggregateTimeout = 200; | ||
if (!options) options = {}; | ||
if (!options.aggregateTimeout) options.aggregateTimeout = 200; | ||
this.options = options; | ||
this.watcherOptions = { | ||
ignored: options.ignored, | ||
ignored: ignoredToRegexp(options.ignored), | ||
poll: options.poll | ||
@@ -47,8 +67,21 @@ }; | ||
const oldDirWatchers = this.dirWatchers; | ||
this.fileWatchers = files.map(file => | ||
this._fileWatcher(file, watcherManager.watchFile(file, this.watcherOptions, startTime)) | ||
); | ||
this.dirWatchers = directories.map(dir => | ||
this._dirWatcher(dir, watcherManager.watchDirectory(dir, this.watcherOptions, startTime)) | ||
); | ||
const filter = this.watcherOptions.ignored | ||
? path => !this.watcherOptions.ignored.test(path.replace(/\\/g, "/")) | ||
: () => true; | ||
this.fileWatchers = files | ||
.filter(filter) | ||
.map(file => | ||
this._fileWatcher( | ||
file, | ||
watcherManager.watchFile(file, this.watcherOptions, startTime) | ||
) | ||
); | ||
this.dirWatchers = directories | ||
.filter(filter) | ||
.map(dir => | ||
this._dirWatcher( | ||
dir, | ||
watcherManager.watchDirectory(dir, this.watcherOptions, startTime) | ||
) | ||
); | ||
oldFileWatchers.forEach(w => w.close()); | ||
@@ -60,4 +93,3 @@ oldDirWatchers.forEach(w => w.close()); | ||
this.paused = true; | ||
if(this.aggregateTimeout) | ||
clearTimeout(this.aggregateTimeout); | ||
if (this.aggregateTimeout) clearTimeout(this.aggregateTimeout); | ||
this.fileWatchers.forEach(w => w.close()); | ||
@@ -71,4 +103,3 @@ this.dirWatchers.forEach(w => w.close()); | ||
this.paused = true; | ||
if(this.aggregateTimeout) | ||
clearTimeout(this.aggregateTimeout); | ||
if (this.aggregateTimeout) clearTimeout(this.aggregateTimeout); | ||
} | ||
@@ -81,5 +112,5 @@ | ||
const obj = Object.create(null); | ||
for(const w of directoryWatchers) { | ||
for (const w of directoryWatchers) { | ||
const times = w.getTimes(); | ||
Object.keys(times).forEach(file => obj[file] = times[file]); | ||
Object.keys(times).forEach(file => (obj[file] = times[file])); | ||
} | ||
@@ -90,4 +121,5 @@ return obj; | ||
getTimeInfoEntries() { | ||
if(EXISTANCE_ONLY_TIME_ENTRY === undefined) { | ||
EXISTANCE_ONLY_TIME_ENTRY = require("./DirectoryWatcher").EXISTANCE_ONLY_TIME_ENTRY; | ||
if (EXISTANCE_ONLY_TIME_ENTRY === undefined) { | ||
EXISTANCE_ONLY_TIME_ENTRY = require("./DirectoryWatcher") | ||
.EXISTANCE_ONLY_TIME_ENTRY; | ||
} | ||
@@ -98,10 +130,10 @@ const directoryWatchers = new Set(); | ||
const map = new Map(); | ||
for(const w of directoryWatchers) { | ||
for (const w of directoryWatchers) { | ||
const times = w.getTimeInfoEntries(); | ||
for(const [path, entry] of times) { | ||
if(map.has(path)) { | ||
if(entry === EXISTANCE_ONLY_TIME_ENTRY) continue; | ||
for (const [path, entry] of times) { | ||
if (map.has(path)) { | ||
if (entry === EXISTANCE_ONLY_TIME_ENTRY) continue; | ||
const value = map.get(path); | ||
if(value === entry) continue; | ||
if(value !== EXISTANCE_ONLY_TIME_ENTRY) { | ||
if (value === entry) continue; | ||
if (value !== EXISTANCE_ONLY_TIME_ENTRY) { | ||
map.set(path, Object.assign({}, value, entry)); | ||
@@ -121,3 +153,3 @@ continue; | ||
}); | ||
watcher.on("remove", (type) => { | ||
watcher.on("remove", type => { | ||
this._onRemove(file, file, type); | ||
@@ -137,8 +169,10 @@ }); | ||
file = file || item; | ||
if(this.paused) return; | ||
if (this.paused) return; | ||
this.emit("change", file, mtime, type); | ||
if(this.aggregateTimeout) | ||
clearTimeout(this.aggregateTimeout); | ||
if (this.aggregateTimeout) clearTimeout(this.aggregateTimeout); | ||
this.aggregatedChanges.add(item); | ||
this.aggregateTimeout = setTimeout(this._onTimeout, this.options.aggregateTimeout); | ||
this.aggregateTimeout = setTimeout( | ||
this._onTimeout, | ||
this.options.aggregateTimeout | ||
); | ||
} | ||
@@ -148,8 +182,10 @@ | ||
file = file || item; | ||
if(this.paused) return; | ||
if (this.paused) return; | ||
this.emit("remove", item); | ||
if(this.aggregateTimeout) | ||
clearTimeout(this.aggregateTimeout); | ||
if (this.aggregateTimeout) clearTimeout(this.aggregateTimeout); | ||
this.aggregatedRemovals.add(item); | ||
this.aggregateTimeout = setTimeout(this._onTimeout, this.options.aggregateTimeout); | ||
this.aggregateTimeout = setTimeout( | ||
this._onTimeout, | ||
this.options.aggregateTimeout | ||
); | ||
} | ||
@@ -156,0 +192,0 @@ |
{ | ||
"name": "watchpack", | ||
"version": "2.0.0-beta.3", | ||
"version": "2.0.0-beta.4", | ||
"description": "", | ||
@@ -17,2 +17,3 @@ "main": "./lib/watchpack.js", | ||
"precover": "yarn lint", | ||
"pretty-files": "prettier \"lib/**.*\" \"test/**/*.js\" --write", | ||
"cover": "istanbul cover node_modules/mocha/bin/_mocha" | ||
@@ -33,4 +34,6 @@ }, | ||
"eslint": "^5.11.1", | ||
"eslint-plugin-prettier": "^3.1.0", | ||
"istanbul": "^0.4.3", | ||
"mocha": "^5.0.1", | ||
"prettier": "^1.11.0", | ||
"rimraf": "^2.6.2", | ||
@@ -40,2 +43,4 @@ "should": "^8.3.1" | ||
"dependencies": { | ||
"eslint-config-prettier": "^4.3.0", | ||
"glob-to-regexp": "^0.4.1", | ||
"graceful-fs": "^4.1.2", | ||
@@ -42,0 +47,0 @@ "neo-async": "^2.5.0" |
@@ -36,2 +36,7 @@ # watchpack | ||
// When WATCHPACK_POLLING environment variable is set it will override this option | ||
ignored: "**/.git", | ||
// ignored: "string" - a glob pattern for files or folders that should not be watched | ||
// ignored: ["string", "string"] - multiple glob patterns that should be ignored | ||
// All subdirectories are ignored too | ||
}); | ||
@@ -38,0 +43,0 @@ |
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
29176
830
86
4
8
+ Addedglob-to-regexp@^0.4.1
+ Added@eslint-community/eslint-utils@4.4.1(transitive)
+ Added@eslint-community/regexpp@4.12.1(transitive)
+ Added@eslint/config-array@0.18.0(transitive)
+ Added@eslint/core@0.7.0(transitive)
+ Added@eslint/eslintrc@3.1.0(transitive)
+ Added@eslint/js@9.14.0(transitive)
+ Added@eslint/object-schema@2.1.4(transitive)
+ Added@eslint/plugin-kit@0.2.2(transitive)
+ Added@humanfs/core@0.19.1(transitive)
+ Added@humanfs/node@0.16.6(transitive)
+ Added@humanwhocodes/module-importer@1.0.1(transitive)
+ Added@humanwhocodes/retry@0.3.10.4.1(transitive)
+ Added@types/estree@1.0.6(transitive)
+ Added@types/json-schema@7.0.15(transitive)
+ Addedacorn@8.14.0(transitive)
+ Addedacorn-jsx@5.3.2(transitive)
+ Addedajv@6.12.6(transitive)
+ Addedansi-styles@4.3.0(transitive)
+ Addedargparse@2.0.1(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedcallsites@3.1.0(transitive)
+ Addedchalk@4.1.2(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcolor-name@1.1.4(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedcross-spawn@7.0.5(transitive)
+ Addeddebug@4.3.7(transitive)
+ Addeddeep-is@0.1.4(transitive)
+ Addedescape-string-regexp@4.0.0(transitive)
+ Addedeslint@9.14.0(transitive)
+ Addedeslint-config-prettier@4.3.0(transitive)
+ Addedeslint-scope@8.2.0(transitive)
+ Addedeslint-visitor-keys@3.4.34.2.0(transitive)
+ Addedespree@10.3.0(transitive)
+ Addedesquery@1.6.0(transitive)
+ Addedesrecurse@4.3.0(transitive)
+ Addedestraverse@5.3.0(transitive)
+ Addedesutils@2.0.3(transitive)
+ Addedfast-deep-equal@3.1.3(transitive)
+ Addedfast-json-stable-stringify@2.1.0(transitive)
+ Addedfast-levenshtein@2.0.6(transitive)
+ Addedfile-entry-cache@8.0.0(transitive)
+ Addedfind-up@5.0.0(transitive)
+ Addedflat-cache@4.0.1(transitive)
+ Addedflatted@3.3.1(transitive)
+ Addedget-stdin@6.0.0(transitive)
+ Addedglob-parent@6.0.2(transitive)
+ Addedglob-to-regexp@0.4.1(transitive)
+ Addedglobals@14.0.0(transitive)
+ Addedhas-flag@4.0.0(transitive)
+ Addedignore@5.3.2(transitive)
+ Addedimport-fresh@3.3.0(transitive)
+ Addedimurmurhash@0.1.4(transitive)
+ Addedis-extglob@2.1.1(transitive)
+ Addedis-glob@4.0.3(transitive)
+ Addedisexe@2.0.0(transitive)
+ Addedjs-yaml@4.1.0(transitive)
+ Addedjson-buffer@3.0.1(transitive)
+ Addedjson-schema-traverse@0.4.1(transitive)
+ Addedjson-stable-stringify-without-jsonify@1.0.1(transitive)
+ Addedkeyv@4.5.4(transitive)
+ Addedlevn@0.4.1(transitive)
+ Addedlocate-path@6.0.0(transitive)
+ Addedlodash.merge@4.6.2(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedms@2.1.3(transitive)
+ Addednatural-compare@1.4.0(transitive)
+ Addedoptionator@0.9.4(transitive)
+ Addedp-limit@3.1.0(transitive)
+ Addedp-locate@5.0.0(transitive)
+ Addedparent-module@1.0.1(transitive)
+ Addedpath-exists@4.0.0(transitive)
+ Addedpath-key@3.1.1(transitive)
+ Addedprelude-ls@1.2.1(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedresolve-from@4.0.0(transitive)
+ Addedshebang-command@2.0.0(transitive)
+ Addedshebang-regex@3.0.0(transitive)
+ Addedstrip-json-comments@3.1.1(transitive)
+ Addedsupports-color@7.2.0(transitive)
+ Addedtext-table@0.2.0(transitive)
+ Addedtype-check@0.4.0(transitive)
+ Addeduri-js@4.4.1(transitive)
+ Addedwhich@2.0.2(transitive)
+ Addedword-wrap@1.2.5(transitive)
+ Addedyocto-queue@0.1.0(transitive)