Comparing version 0.10.1 to 0.10.2
136
index.js
@@ -6,2 +6,3 @@ 'use strict'; | ||
var sysPath = require('path'); | ||
var each = require('async-each'); | ||
@@ -150,18 +151,12 @@ var fsevents, readdirp; | ||
var dir = sysPath.resolve(directory); | ||
if (!(dir in this.watched)) this.watched[dir] = []; | ||
if (!(dir in this.watched)) this.watched[dir] = { | ||
_items: Object.create(null), | ||
add: function(item) {this._items[item] = true;}, | ||
remove: function(item) {delete this._items[item];}, | ||
has: function(item) {return item in this._items;}, | ||
children: function() {return Object.keys(this._items);} | ||
}; | ||
return this.watched[dir]; | ||
}; | ||
FSWatcher.prototype._addToWatchedDir = function(directory, basename) { | ||
var watchedFiles = this._getWatchedDir(directory); | ||
watchedFiles.push(basename); | ||
}; | ||
FSWatcher.prototype._removeFromWatchedDir = function(directory, file) { | ||
var watchedFiles = this._getWatchedDir(directory); | ||
watchedFiles.some(function(watchedFile, index) { | ||
if (watchedFile === file) return watchedFiles.splice(index, 1); | ||
}); | ||
}; | ||
// File helpers | ||
@@ -198,11 +193,14 @@ // ------------ | ||
// via multiple paths (such as _handleFile and _handleDir) | ||
if (!this._throttle('remove', fullPath, 5)) return; | ||
if (!this._throttle('remove', fullPath, 10)) return; | ||
// if the only watched file is removed, watch for its return | ||
var watchedDirs = Object.keys(this.watched); | ||
if (!isDirectory && !this.options.useFsEvents && watchedDirs.length === 1) { | ||
this.add(directory, item); | ||
} | ||
// This will create a new entry in the watched object in either case | ||
// so we got to do the directory check beforehand | ||
var nestedDirectoryChildren = this._getWatchedDir(fullPath).slice(); | ||
var nestedDirectoryChildren = this._getWatchedDir(fullPath).children(); | ||
// Remove directory / file from watched list. | ||
this._removeFromWatchedDir(directory, item); | ||
// Recursively remove children directories / files. | ||
@@ -213,2 +211,5 @@ nestedDirectoryChildren.forEach(function(nestedItem) { | ||
// Remove directory / file from watched list. | ||
this._getWatchedDir(directory).remove(item); | ||
// The Entry will either be a directory that just got removed | ||
@@ -240,6 +241,6 @@ // or a bogus entry to a file, in either case we have to remove it | ||
if (event === 'add') { | ||
this._addToWatchedDir(parent, item); | ||
this._getWatchedDir(parent).add(item); | ||
} else if (event === 'unlink') { | ||
// suppress unlink events on never before seen files (from atomic write) | ||
if (info.type === 'directory' || watchedDir.indexOf(item) !== -1) { | ||
if (info.type === 'directory' || watchedDir.has(item)) { | ||
this._remove(parent, item); | ||
@@ -255,5 +256,5 @@ } | ||
function addOrChange() { | ||
handleEvent(watchedDir.indexOf(item) !== -1 ? 'change' : 'add'); | ||
handleEvent(watchedDir.has(item) ? 'change' : 'add'); | ||
} | ||
var wrongEventFlags = [69888, 70400, 71424, 72704, 131328, 131840]; | ||
var wrongEventFlags = [69888, 70400, 71424, 72704, 73472, 131328, 131840]; | ||
if (wrongEventFlags.indexOf(flags) !== -1) { | ||
@@ -300,6 +301,6 @@ if (info.event === 'deleted' || info.event === 'moved') { | ||
var parent = this._getWatchedDir(directory); | ||
if (parent.indexOf(basename) !== -1) return; | ||
if (parent.has(basename)) return; | ||
parent.add(basename); | ||
var absolutePath = sysPath.resolve(item); | ||
var options = {persistent: this.options.persistent}; | ||
this._addToWatchedDir(directory, basename); | ||
if (!callback) callback = Function.prototype; // empty function | ||
@@ -345,9 +346,14 @@ | ||
FSWatcher.prototype._handleFile = function(file, stats, initialAdd) { | ||
var dirname = sysPath.dirname(file); | ||
var basename = sysPath.basename(file); | ||
var parent = this._getWatchedDir(dirname); | ||
// if the file is already being watched, do nothing | ||
if (parent.has(basename)) return; | ||
this._watch(file, function(file, newStats) { | ||
if (!this._throttle('watch', file, 5)) return; | ||
if (newStats && newStats.mtime.getTime() === 0) { | ||
fs.exists(file, function(exists) { | ||
if (!newStats || newStats && newStats.mtime.getTime() === 0) { | ||
fs.stat(file, function(error, newStats) { | ||
// Fix issues where mtime is null but file is still present | ||
if (!exists) { | ||
this._remove(sysPath.dirname(file), sysPath.basename(file)); | ||
if (error) { | ||
this._remove(dirname, basename); | ||
} else { | ||
@@ -357,3 +363,4 @@ this._emit('change', file, newStats); | ||
}.bind(this)); | ||
} else { | ||
// add is about to be emitted if file not already tracked in parent | ||
} else if (parent.has(basename)) { | ||
this._emit('change', file, newStats); | ||
@@ -371,9 +378,10 @@ } | ||
// * directory - string, fs path. | ||
// * dir - string, fs path. | ||
// * stats - object, result of fs.stat | ||
// * initialAdd - boolean, was the file added at watch instantiation? | ||
// * target - child path actually targeted for watch | ||
// Returns nothing. | ||
FSWatcher.prototype._handleDir = function(directory, stats, initialAdd) { | ||
var read = function read(directory, initialAdd) { | ||
FSWatcher.prototype._handleDir = function(dir, stats, initialAdd, target) { | ||
var read = function read(directory, initialAdd, target) { | ||
var throttler = this._throttle('readdir', directory, 1000); | ||
@@ -391,3 +399,3 @@ if (!throttler) return; | ||
// and are removed from @watched[directory]. | ||
previous.filter(function(file) { | ||
previous.children().filter(function(file) { | ||
return file !== directory && current.indexOf(file) === -1; | ||
@@ -402,17 +410,17 @@ }).forEach(function(file) { | ||
current.filter(function(file) { | ||
return previous.indexOf(file) === -1; | ||
return file === target || !target && !previous.has(file); | ||
}).forEach(function(file) { | ||
this._handle(sysPath.join(directory, file), initialAdd); | ||
this._handle(sysPath.join(directory, file), initialAdd, target); | ||
}, this); | ||
}.bind(this)); | ||
}.bind(this); | ||
read(directory, initialAdd); | ||
this._watch(directory, function(dir, stats) { | ||
if (!target) read(dir, initialAdd); | ||
this._watch(dir, function(dirPath, stats) { | ||
// Current directory is removed, do nothing | ||
if (stats && stats.mtime.getTime() === 0) return; | ||
read(dir, false); | ||
read(dirPath, false, target); | ||
}); | ||
if (!(initialAdd && this.options.ignoreInitial)) { | ||
this._emit('addDir', directory, stats); | ||
if (!(initialAdd && this.options.ignoreInitial) && !target) { | ||
this._emit('addDir', dir, stats); | ||
} | ||
@@ -424,13 +432,16 @@ }; | ||
// * item - string, path to file or directory. | ||
// * item - string, path to file or directory. | ||
// * initialAdd - boolean, was the file added at watch instantiation? | ||
// * target - child path actually targeted for watch | ||
// * callback - indicates whether the item was found or not | ||
// Returns nothing. | ||
FSWatcher.prototype._handle = function(item, initialAdd) { | ||
if (this._isIgnored(item) || this.closed) return; | ||
FSWatcher.prototype._handle = function(item, initialAdd, target, callback) { | ||
if (!callback) callback = Function.prototype; | ||
if (this._isIgnored(item) || this.closed) return callback(null, item); | ||
fs.realpath(item, function(error, path) { | ||
if (this._handleError(error)) return; | ||
if (this._handleError(error)) return callback(null, item); | ||
fs.stat(path, function(error, stats) { | ||
if (this._handleError(error)) return; | ||
if (this._handleError(error)) return callback(null, item); | ||
if (( | ||
@@ -442,8 +453,9 @@ this.options.ignorePermissionErrors && | ||
this._isIgnored(item, stats) | ||
)) return; | ||
)) return callback(null, false); | ||
if (stats.isFile() || stats.isCharacterDevice()) { | ||
this._handleFile(item, stats, initialAdd); | ||
} else if (stats.isDirectory()) { | ||
this._handleDir(item, stats, initialAdd); | ||
this._handleDir(item, stats, initialAdd, target); | ||
} | ||
callback(null, false); | ||
}.bind(this)); | ||
@@ -455,3 +467,3 @@ }.bind(this)); | ||
var emitAdd = function(path, stats) { | ||
this._addToWatchedDir(sysPath.dirname(path), sysPath.basename(path)); | ||
this._getWatchedDir(sysPath.dirname(path)).add(sysPath.basename(path)); | ||
this._emit(stats.isDirectory() ? 'addDir' : 'add', path, stats); | ||
@@ -475,3 +487,3 @@ }.bind(this); | ||
} | ||
this._watchWithFsEvents(file); | ||
if (this.options.persistent) this._watchWithFsEvents(file); | ||
return this; | ||
@@ -482,16 +494,22 @@ }; | ||
// * files - array of strings (file or directory paths). | ||
// * files - array of strings (file or directory paths). | ||
// * _origAdd - private argument for handling non-existent paths to be watched | ||
// Returns an instance of FSWatcher for chaining. | ||
FSWatcher.prototype.add = function(files) { | ||
FSWatcher.prototype.add = function(files, _origAdd) { | ||
if (!('_initialAdd' in this)) this._initialAdd = true; | ||
if (!Array.isArray(files)) files = [files]; | ||
files.forEach(function(file) { | ||
if (this.options.useFsEvents) { | ||
this._addToFsEvents(file); | ||
} else { | ||
this._handle(file, this._initialAdd); | ||
} | ||
}, this); | ||
if (this.options.useFsEvents) { | ||
files.forEach(this._addToFsEvents, this); | ||
} else if (!this.closed) { | ||
each(files, function(file, next) { | ||
this._handle(file, this._initialAdd, _origAdd, next); | ||
}.bind(this), function(error, results) { | ||
results.forEach(function(item){ | ||
if (!item) return; | ||
this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item)); | ||
}, this); | ||
}.bind(this)); | ||
} | ||
@@ -517,3 +535,3 @@ this._initialAdd = false; | ||
Object.keys(watched).forEach(function(directory) { | ||
watched[directory].forEach(function(file) { | ||
watched[directory].children().forEach(function(file) { | ||
var absolutePath = sysPath.resolve(directory, file); | ||
@@ -520,0 +538,0 @@ fs.unwatchFile(absolutePath, listeners[absolutePath]); |
{ | ||
"name": "chokidar", | ||
"description": "A neat wrapper around node.js fs.watch / fs.watchFile / fsevents.", | ||
"version": "0.10.1", | ||
"version": "0.10.2", | ||
"keywords": [ | ||
@@ -32,10 +32,10 @@ "fs", | ||
}, | ||
"files": ["index.js"], | ||
"files": [ | ||
"index.js" | ||
], | ||
"devDependencies": { | ||
"mocha": "~1.7.3", | ||
"chai": "~1.4.0", | ||
"sinon": "~1.5.2", | ||
"sinon-chai": "2.2.0", | ||
"coffee-script": "~1.6.0", | ||
"rimraf": "~2.2.2" | ||
"mocha": "~2.0.0", | ||
"chai": "~1.9.2", | ||
"sinon": "~1.10.3", | ||
"sinon-chai": "~2.6.0" | ||
}, | ||
@@ -45,3 +45,6 @@ "optionalDependencies": { | ||
"readdirp": "~1.1.0" | ||
}, | ||
"dependencies": { | ||
"async-each": "~0.1.5" | ||
} | ||
} |
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
24649
4
470
3
+ Addedasync-each@~0.1.5
+ Addedasync-each@0.1.6(transitive)