simple-watcher
Advanced tools
Comparing version 3.0.0 to 4.0.0
116
index.js
@@ -6,16 +6,14 @@ 'use strict' | ||
const TOLERANCE = 200 | ||
const TOLERANCE = 200 // For ReadDirectoryChangesW() double reporting. | ||
const PLATFORMS = ['win32', 'darwin'] | ||
// OS watcher. | ||
let watchFolder = (workingDir, recursive, tolerance, callback) => { | ||
let options = { persistent: true, recursive: recursive } | ||
let last = { filePath: null, timestamp: 0 } | ||
let w = fs.watch(workingDir, options, (event, fileName) => { | ||
// OS directory watcher. | ||
function watchDir (dirToWatch, options, callback) { | ||
const last = {filePath: null, timestamp: 0} | ||
const w = fs.watch(dirToWatch, {persistent: true, recursive: !options.shallow}, (event, fileName) => { | ||
// On Windows fileName may actually be empty. | ||
// In such case assume this is the working dir change. | ||
let filePath = fileName ? path.join(workingDir, fileName) : workingDir | ||
const filePath = fileName ? path.join(dirToWatch, fileName) : dirToWatch | ||
if (!tolerance) { | ||
if (options.shallow) { | ||
return callback(filePath) | ||
@@ -26,5 +24,5 @@ } | ||
// If error, the file was likely deleted. | ||
let timestamp = err ? 0 : (new Date(stat.mtime)).getTime() | ||
let ready = err || timestamp - last.timestamp >= tolerance | ||
let fileMatches = filePath === last.filePath | ||
const timestamp = err ? 0 : (new Date(stat.mtime)).getTime() | ||
const ready = err || timestamp - last.timestamp >= options.tolerance | ||
const fileMatches = filePath === last.filePath | ||
last.filePath = filePath | ||
@@ -46,53 +44,65 @@ last.timestamp = timestamp | ||
let watchFolderFallback = (parent, tolerance, callback) => { | ||
// This code is synchronous to be able to tell when it actually finishes. | ||
try { | ||
// Skip if not a directory. | ||
if (!fs.statSync(parent).isDirectory()) { | ||
return | ||
// Fallback deep watcher. | ||
function watchDirFallback (dirToWatch, options, callback) { | ||
const dirs = [dirToWatch] | ||
options.ledger = options.ledger || new Set() | ||
for (let ii = 0; ii < dirs.length; ++ii) { | ||
const dir = dirs[ii] | ||
// Append dirs with descendants. | ||
if (!options.shallow) { | ||
for (const entityName of fs.readdirSync(dir)) { | ||
const entityPath = path.resolve(dir, entityName) | ||
fs.statSync(entityPath).isDirectory() && dirs.push(entityPath) | ||
} | ||
} | ||
watchFolder(parent, false, tolerance, callback) | ||
options.ledger.add(dir) | ||
watchDir(dir, {shallow: true}, (entityPath) => { | ||
fs.stat(entityPath, (err, stat) => { | ||
if (err) { // Entity was deleted. | ||
options.ledger.delete(entityPath) | ||
} else if (stat.isDirectory() && !options.ledger.has(entityPath) && !options.shallow) { // New directory added. | ||
watchDirFallback(entityPath, options, callback) | ||
} | ||
// Iterate over list of children. | ||
fs.readdirSync(parent).forEach((child) => { | ||
child = path.resolve(parent, child) | ||
watchFolderFallback(child, tolerance, callback) | ||
callback(entityPath) | ||
}) | ||
}) | ||
} catch (err) { | ||
console.error(err) | ||
} | ||
} | ||
let watch = (workingDir, callback, tolerance) => { | ||
workingDir = path.resolve(workingDir) | ||
function watchFile (filePath, options, callback) { | ||
options = options.interval ? {interval: options.interval} : {} | ||
fs.watchFile(filePath, options, (curr, prev) => { | ||
curr.mtime === 0 && fs.unwatchFile(filePath) // Unwatch if deleted. | ||
callback(filePath) | ||
}) | ||
} | ||
// Set the default tolerance value. | ||
tolerance = tolerance === undefined ? TOLERANCE : tolerance | ||
// Enable tolerance only for Windows. | ||
tolerance = process.platform === 'win32' ? tolerance : 0 | ||
function watch (entitiesToWatch, arg1, arg2) { | ||
const callback = arg2 || arg1 | ||
const options = arg2 ? arg1 : {toleance: TOLERANCE} | ||
options.tolerance = process.platform === 'win32' ? (options.tolerance || TOLERANCE) : 0 // Disable tolerance if not on Windows. | ||
options.fallback = options.fallback || !PLATFORMS.includes(process.platform) | ||
// Use recursive flag if natively available. | ||
if (PLATFORMS.indexOf(process.platform) !== -1) { | ||
return watchFolder(workingDir, true, tolerance, callback) | ||
entitiesToWatch = entitiesToWatch.constructor === Array ? entitiesToWatch : [entitiesToWatch] // Normalize to array. | ||
entitiesToWatch = entitiesToWatch.map(entityToWatch => path.resolve(entityToWatch)) // Resolve directory paths. | ||
for (const entityToWatch of entitiesToWatch) { | ||
if (!fs.statSync(entityToWatch).isDirectory()) { | ||
watchFile(entityToWatch, options, callback) | ||
} else { | ||
options.fallback ? watchDirFallback(entityToWatch, options, callback) : watchDir(entityToWatch, options, callback) | ||
} | ||
} | ||
} | ||
// Attach handlers for each folder recursively. | ||
let cache = {} | ||
watchFolderFallback(workingDir, tolerance, (localPath) => { | ||
fs.stat(localPath, (err, stat) => { | ||
// Delete cache entry. | ||
if (err) { | ||
delete cache[localPath] | ||
return | ||
} | ||
watch.main = function () { | ||
const args = process.argv.slice(2) | ||
const entitiesToWatch = args.filter(a => !a.startsWith('--')) | ||
const options = {shallow: args.includes('--shallow'), fallback: args.includes('--fallback')} | ||
// Add new handler for new directory and save in cache. | ||
if (stat.isDirectory() && !cache[localPath]) { | ||
cache[localPath] = true | ||
watchFolder(localPath, false, tolerance, callback) | ||
} | ||
}) | ||
callback(localPath) | ||
watch(entitiesToWatch, options, fileName => { | ||
console.log(`${fileName}`) | ||
}) | ||
@@ -102,7 +112,5 @@ } | ||
if (require.main === module) { | ||
watch(process.argv[2], (fileName) => { | ||
console.log(`${fileName}`) | ||
}) | ||
watch.main() | ||
} | ||
module.exports = watch |
{ | ||
"name": "simple-watcher", | ||
"version": "3.0.0", | ||
"description": "\"A simple recursive directory watcher.\"", | ||
"version": "4.0.0", | ||
"description": "\"A simple directory watcher.\"", | ||
"main": "index.js", | ||
"bin": { | ||
"simple-watcher": "./bin/simple-watcher" | ||
}, | ||
"repository": { | ||
@@ -7,0 +10,0 @@ "type": "git", |
7118
9
104
43