Socket
Socket
Sign inDemoInstall

watchr

Package Overview
Dependencies
Maintainers
1
Versions
122
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

watchr - npm Package Compare versions

Comparing version 2.3.3 to 2.3.4

Cakefile

10

History.md
## History
- v2.3.4 January 8, 2013
- Better handling and detection of failed watching operations
- Better handling of duplicated events
- Watching is now an atomic operation
- If watching fails for a descendant, we will close everything related to that watch operation of the eve
- We now prefer the `watch` method over the `watchFile` method
- This offers great reliability and way less CPU and memory foot print
- If you still wish to prefer `watchFile`, then set the new configuration option `preferredMethod` to `watchFile`
- Closes [issue #30](https://github.com/bevry/watchr/issues/30) thanks to [Howard Tyson](https://github.com/tizzo)
- v2.3.3 January 8, 2013

@@ -4,0 +14,0 @@ - Added `outputLog` option

1176

out/lib/watchr.js
// Generated by CoffeeScript 1.4.0
var EventEmitter, Watcher, balUtil, createWatcher, fsUtil, pathUtil, watch, watchers,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__slice = [].slice,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
(function() {
var EventEmitter, Watcher, balUtil, createWatcher, domain, fsUtil, pathUtil, safeExecute, watch, watchers, watchersTotal,
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__slice = [].slice,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
pathUtil = require('path');
pathUtil = require('path');
fsUtil = require('fs');
fsUtil = require('fs');
balUtil = require('bal-util');
balUtil = require('bal-util');
EventEmitter = require('events').EventEmitter;
EventEmitter = require('events').EventEmitter;
/*
Now to make watching files more convient and managed, we'll create a class which we can use to attach to each file.
It'll provide us with the API and abstraction we need to accomplish difficult things like recursion.
We'll also store a global store of all the watchers and their paths so we don't have multiple watchers going at the same time
for the same file - as that would be quite ineffecient.
Events:
- `log` for debugging, receives the arguments `logLevel ,args...`
- `error` for gracefully listening to error events, receives the arguments `err`
- `watching` for when watching of the path has completed, receives the arguments `err, watcherInstance, isWatching`
- `change` for listening to change events, receives the arguments `changeType, fullPath, currentStat, previousStat`
*/
try {
domain = require('domain');
} catch (err) {
domain = false;
}
safeExecute = function(next, method) {
var d;
if (domain) {
d = domain.create();
d.on('error', function(err) {
return next(err, false);
});
return d.run(method);
} else {
try {
return method();
} catch (err) {
return next(err, false);
}
}
};
watchers = {};
/*
Now to make watching files more convient and managed, we'll create a class which we can use to attach to each file.
It'll provide us with the API and abstraction we need to accomplish difficult things like recursion.
We'll also store a global store of all the watchers and their paths so we don't have multiple watchers going at the same time
for the same file - as that would be quite ineffecient.
Events:
- `log` for debugging, receives the arguments `logLevel ,args...`
- `error` for gracefully listening to error events, receives the arguments `err`
- `watching` for when watching of the path has completed, receives the arguments `err, watcherInstance, isWatching`
- `change` for listening to change events, receives the arguments `changeType, fullPath, currentStat, previousStat`
*/
Watcher = (function(_super) {
__extends(_Class, _super);
watchersTotal = 0;
_Class.prototype.path = null;
watchers = {};
_Class.prototype.isDirectory = null;
Watcher = (function(_super) {
_Class.prototype.stat = null;
__extends(_Class, _super);
_Class.prototype.fswatcher = null;
_Class.prototype.path = null;
_Class.prototype.children = null;
_Class.prototype.isDirectory = null;
_Class.prototype.state = 'pending';
_Class.prototype.stat = null;
_Class.prototype.method = null;
_Class.prototype.fswatcher = null;
_Class.prototype.config = {
path: null,
outputLog: false,
listener: null,
listeners: null,
stat: null,
ignorePaths: false,
ignoreHiddenFiles: false,
ignoreCommonPatterns: true,
ignoreCustomPatterns: null,
interval: 100,
persistent: true
};
_Class.prototype.children = null;
function _Class(config, next) {
this.isIgnoredPath = __bind(this.isIgnoredPath, this);
_Class.prototype.state = 'pending';
this.bubbler = __bind(this.bubbler, this);
_Class.prototype.method = null;
this.bubble = __bind(this.bubble, this);
_Class.prototype.config = {
path: null,
listener: null,
listeners: null,
stat: null,
outputLog: false,
interval: 100,
persistent: true,
duplicateDelay: 1 * 1000,
preferredMethod: 'watch',
ignorePaths: false,
ignoreHiddenFiles: false,
ignoreCommonPatterns: true,
ignoreCustomPatterns: null
};
this.log = __bind(this.log, this);
this.children = {};
this.config = balUtil.extend({}, this.config);
if (config.next != null) {
if (next == null) {
next = config.next;
function _Class(config, next) {
this.isIgnoredPath = __bind(this.isIgnoredPath, this);
this.bubbler = __bind(this.bubbler, this);
this.bubble = __bind(this.bubble, this);
this.log = __bind(this.log, this);
this.children = {};
this.config = balUtil.extend({}, this.config);
if (config.next != null) {
if (next == null) {
next = config.next;
}
delete config.next;
}
delete config.next;
if (config) {
this.setup(config);
}
if (next) {
this.watch(next);
}
this;
}
if (config) {
this.setup(config);
}
if (next) {
this.watch(next);
}
this;
}
_Class.prototype.log = function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (this.config.outputLog) {
console.log.apply(console, args);
}
this.emit.apply(this, ['log'].concat(__slice.call(args)));
return this;
};
_Class.prototype.log = function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (this.config.outputLog) {
console.log.apply(console, args);
}
this.emit.apply(this, ['log'].concat(__slice.call(args)));
return this;
};
/*
Setup our Instance
*/
/*
Setup our Instance
*/
_Class.prototype.setup = function(config) {
this.path = config.path;
balUtil.extend(this.config, config);
if (this.config.stat) {
this.stat = this.config.stat;
this.isDirectory = this.stat.isDirectory();
delete this.config.stat;
}
if (this.config.listener || this.config.listeners) {
this.removeAllListeners();
if (this.config.listener) {
this.listen(this.config.listener);
delete this.config.listener;
_Class.prototype.setup = function(config) {
this.path = config.path;
balUtil.extend(this.config, config);
if (this.config.stat) {
this.stat = this.config.stat;
this.isDirectory = this.stat.isDirectory();
delete this.config.stat;
}
if (this.config.listeners) {
this.listen(this.config.listeners);
delete this.config.listeners;
if (this.config.listener || this.config.listeners) {
this.removeAllListeners();
if (this.config.listener) {
this.listen(this.config.listener);
delete this.config.listener;
}
if (this.config.listeners) {
this.listen(this.config.listeners);
delete this.config.listeners;
}
}
}
return this;
};
return this;
};
_Class.prototype.bubble = function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
this.log('debug', "bubble on " + this.path + " with the args:", args);
this.emit.apply(this, args);
return this;
};
_Class.prototype.bubbler = function(eventName) {
var _this = this;
return function() {
_Class.prototype.bubble = function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return _this.bubble.apply(_this, args);
this.emit.apply(this, args);
return this;
};
};
/*
Listen
Add listeners to our watcher instance.
Overloaded to also accept the following:
- `changeListener` a single change listener
- `[changeListener]` an array of change listeners
- `{eventName:eventListener}` an object keyed with the event names and valued with a single event listener
- `{eventName:[eventListener]}` an object keyed with the event names and valued with an array of event listeners
*/
_Class.prototype.bubbler = function(eventName) {
var _this = this;
return function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return _this.bubble.apply(_this, args);
};
};
/*
Listen
Add listeners to our watcher instance.
Overloaded to also accept the following:
- `changeListener` a single change listener
- `[changeListener]` an array of change listeners
- `{eventName:eventListener}` an object keyed with the event names and valued with a single event listener
- `{eventName:[eventListener]}` an object keyed with the event names and valued with an array of event listeners
*/
_Class.prototype.listen = function(eventName, listener) {
var listenerArray, listeners, _i, _j, _len, _len1;
if (listener == null) {
listeners = eventName;
if (balUtil.isArray(listeners)) {
for (_i = 0, _len = listeners.length; _i < _len; _i++) {
listener = listeners[_i];
this.listen('change', listener);
}
} else if (balUtil.isPlainObject(listeners)) {
for (eventName in listeners) {
if (!__hasProp.call(listeners, eventName)) continue;
listenerArray = listeners[eventName];
if (balUtil.isArray(listenerArray)) {
for (_j = 0, _len1 = listenerArray.length; _j < _len1; _j++) {
listener = listenerArray[_j];
this.listen(eventName, listener);
_Class.prototype.listen = function(eventName, listener) {
var listenerArray, listeners, _i, _j, _len, _len1;
if (listener == null) {
listeners = eventName;
if (balUtil.isArray(listeners)) {
for (_i = 0, _len = listeners.length; _i < _len; _i++) {
listener = listeners[_i];
this.listen('change', listener);
}
} else if (balUtil.isPlainObject(listeners)) {
for (eventName in listeners) {
if (!__hasProp.call(listeners, eventName)) continue;
listenerArray = listeners[eventName];
if (balUtil.isArray(listenerArray)) {
for (_j = 0, _len1 = listenerArray.length; _j < _len1; _j++) {
listener = listenerArray[_j];
this.listen(eventName, listener);
}
} else {
this.listen(eventName, listenerArray);
}
} else {
this.listen(eventName, listenerArray);
}
} else {
this.listen('change', listeners);
}
} else {
this.listen('change', listeners);
this.removeListener(eventName, listener);
this.on(eventName, listener);
this.log('debug', "added a listener: on " + this.path + " for event " + eventName);
}
} else {
this.removeListener(eventName, listener);
this.on(eventName, listener);
this.log('debug', "added a listener: on " + this.path + " for event " + eventName);
}
return this;
};
return this;
};
/*
Listener
A change event has fired
Things to note:
- watchFile:
- currentStat still exists even for deleted/renamed files
- for deleted and updated files, it will fire on the file
- for created files, it will fire on the directory
- fsWatcher:
- eventName is always 'change'
- 'rename' is not yet implemented by node
- currentStat still exists even for deleted/renamed files
- previousStat is accurate, however we already have this
- for deleted and changed files, it will fire on the file
- for new files, it will fire on the directory
Arguments for our change listener will be:
- for updated files the arguments will be: `'update', fullPath, currentStat, previousStat`
- for created files the arguments will be: `'create', fullPath, currentStat, null`
- for deleted files the arguments will be: `'delete', fullPath, null, previousStat`
In the future we will add:
- for renamed files: 'rename', fullPath, currentStat, previousStat, newFullPath
- rename is possible as the stat.ino is the same for the delete and create
*/
/*
Emit Safe
Sometimes events can fire incredibly quickly in which case we'll determine multiple events
This alias for emit('change',...) will check to see if the event has already been fired recently
and if it has, then ignore it
*/
_Class.prototype.listener = function() {
var args, currentStat, determineTheChange, fileExists, fileFullPath, isTheSame, me, previousStat,
_this = this;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
me = this;
fileFullPath = this.path;
currentStat = null;
previousStat = this.stat;
fileExists = null;
this.log('debug', "watch event triggered on " + this.path + "\n", args);
isTheSame = function() {
if ((currentStat != null) && (previousStat != null)) {
if (currentStat.size === previousStat.size && currentStat.mtime.toString() === previousStat.mtime.toString()) {
return true;
}
_Class.prototype.cacheTimeout = null;
_Class.prototype.cachedEvents = null;
_Class.prototype.emitSafe = function() {
var args, config, me, thisEvent, _ref;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
me = this;
config = this.config;
if (this.cacheTimeout != null) {
clearTimeout(this.cacheTimeout);
}
return false;
this.cacheTimeout = setTimeout(function() {
me.cachedEvents = [];
return me.cacheTimeout = null;
}, config.duplicateDelay);
if ((_ref = this.cachedEvents) == null) {
this.cachedEvents = [];
}
thisEvent = args.toString();
if (__indexOf.call(this.cachedEvents, thisEvent) >= 0) {
this.log('debug', "event ignored on " + this.path + " due to duplicate:", args);
return this;
}
this.cachedEvents.push(thisEvent);
this.emit.apply(this, args);
return this;
};
determineTheChange = function() {
if (!fileExists) {
_this.log('debug', 'determined delete:', fileFullPath);
return _this.close('deleted');
} else {
if (isTheSame()) {
return _this.log('debug', "determined same:", fileFullPath);
/*
Listener
A change event has fired
Things to note:
- watchFile:
- currentStat still exists even for deleted/renamed files
- for deleted and updated files, it will fire on the file
- for created files, it will fire on the directory
- fsWatcher:
- eventName is either 'change' or 'rename', this value cannot be trusted
- currentStat still exists even for deleted/renamed files
- previousStat is accurate, however we already have this
- for deleted and changed files, it will fire on the file
- for new files, it will fire on the directory
Arguments for our change listener will be:
- for updated files the arguments will be: `'update', fullPath, currentStat, previousStat`
- for created files the arguments will be: `'create', fullPath, currentStat, null`
- for deleted files the arguments will be: `'delete', fullPath, null, previousStat`
In the future we will add:
- for renamed files: 'rename', fullPath, currentStat, previousStat, newFullPath
- rename is possible as the stat.ino is the same for the delete and create
*/
_Class.prototype.listener = function() {
var args, currentStat, determineTheChange, fileExists, fileFullPath, isTheSame, me, previousStat,
_this = this;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
me = this;
fileFullPath = this.path;
currentStat = null;
previousStat = this.stat;
fileExists = null;
this.log('debug', "watch event triggered on " + this.path + "\n", args);
isTheSame = function() {
if ((currentStat != null) && (previousStat != null)) {
if (currentStat.size === previousStat.size && currentStat.mtime.toString() === previousStat.mtime.toString()) {
return true;
}
}
return false;
};
determineTheChange = function() {
if (!fileExists) {
_this.log('debug', 'determined delete:', fileFullPath);
return _this.close('deleted');
} else {
if (_this.isDirectory) {
if (isTheSame() === false) {
return balUtil.readdir(fileFullPath, function(err, newFileRelativePaths) {
if (err) {
return _this.emit('error', err);
}
balUtil.each(newFileRelativePaths, function(childFileRelativePath) {
var childFileFullPath;
if (_this.children[childFileRelativePath] != null) {
return;
if (isTheSame()) {
return _this.log('debug', "determined same:", fileFullPath);
} else {
if (_this.isDirectory) {
if (isTheSame() === false) {
return balUtil.readdir(fileFullPath, function(err, newFileRelativePaths) {
if (err) {
return _this.emit('error', err);
}
childFileFullPath = pathUtil.join(fileFullPath, childFileRelativePath);
if (_this.isIgnoredPath(childFileFullPath)) {
return;
}
return balUtil.stat(childFileFullPath, function(err, childFileStat) {
if (err) {
return _this.emit('error', err);
balUtil.each(_this.children, function(childFileWatcher, childFileRelativePath) {
var childFileFullPath;
if (__indexOf.call(newFileRelativePaths, childFileRelativePath) >= 0) {
return;
}
_this.log('debug', 'determined create:', childFileFullPath, 'via:', fileFullPath);
_this.emit('change', 'create', childFileFullPath, childFileStat, null);
return _this.watchChild(childFileFullPath, childFileRelativePath, childFileStat);
childFileFullPath = pathUtil.join(fileFullPath, childFileRelativePath);
if (_this.isIgnoredPath(childFileFullPath)) {
return;
}
_this.log('debug', 'determined delete:', childFileFullPath, 'via:', fileFullPath);
return _this.closeChild(childFileRelativePath, 'deleted');
});
return balUtil.each(newFileRelativePaths, function(childFileRelativePath) {
var childFileFullPath;
if (_this.children[childFileRelativePath] != null) {
return;
}
_this.children[childFileRelativePath] = false;
childFileFullPath = pathUtil.join(fileFullPath, childFileRelativePath);
if (_this.isIgnoredPath(childFileFullPath)) {
return;
}
return balUtil.stat(childFileFullPath, function(err, childFileStat) {
if (err) {
return _this.emit('error', err);
}
_this.log('debug', 'determined create:', childFileFullPath, 'via:', fileFullPath);
_this.emitSafe('change', 'create', childFileFullPath, childFileStat, null);
return _this.watchChild(childFileFullPath, childFileRelativePath, childFileStat);
});
});
});
return balUtil.each(_this.children, function(childFileWatcher, childFileRelativePath) {
var childFileFullPath;
if (__indexOf.call(newFileRelativePaths, childFileRelativePath) >= 0) {
return;
}
childFileFullPath = pathUtil.join(fileFullPath, childFileRelativePath);
if (_this.isIgnoredPath(childFileFullPath)) {
return;
}
_this.log('debug', 'determined delete:', childFileFullPath, 'via:', fileFullPath);
return _this.closeChild(childFileRelativePath, 'deleted');
});
});
}
} else {
_this.log('debug', 'determined update:', fileFullPath);
return _this.emitSafe('change', 'update', fileFullPath, currentStat, previousStat);
}
} else {
_this.log('debug', 'determined update:', fileFullPath);
return _this.emit('change', 'update', fileFullPath, currentStat, previousStat);
}
}
}
};
balUtil.exists(fileFullPath, function(exists) {
fileExists = exists;
if (fileExists) {
return balUtil.stat(fileFullPath, function(err, stat) {
if (err) {
return this.emit('error', err);
}
currentStat = stat;
me.stat = currentStat;
return determineTheChange();
});
} else {
return determineTheChange();
}
});
return this;
};
balUtil.exists(fileFullPath, function(exists) {
fileExists = exists;
if (fileExists) {
return balUtil.stat(fileFullPath, function(err, stat) {
if (err) {
return this.emit('error', err);
}
currentStat = stat;
me.stat = currentStat;
return determineTheChange();
});
} else {
return determineTheChange();
}
});
return this;
};
/*
Close
We will need something to close our listener for removed or renamed files
As renamed files are a bit difficult we will want to close and delete all the watchers for all our children too
Essentially it is a self-destruct
*/
/*
Close
We will need something to close our listener for removed or renamed files
As renamed files are a bit difficult we will want to close and delete all the watchers for all our children too
Essentially it is a self-destruct
*/
_Class.prototype.close = function(reason) {
var childRelativePath, _ref;
if (this.state !== 'active') {
_Class.prototype.close = function(reason) {
var childRelativePath, _ref;
if (this.state !== 'active') {
return this;
}
this.log('debug', "close: " + this.path);
_ref = this.children;
for (childRelativePath in _ref) {
if (!__hasProp.call(_ref, childRelativePath)) continue;
this.closeChild(childRelativePath, reason);
}
if (this.method === 'watchFile') {
fsUtil.unwatchFile(this.path);
}
if (this.fswatcher != null) {
this.fswatcher.close();
this.fswatcher = null;
}
if (reason === 'deleted') {
this.state = 'deleted';
this.emitSafe('change', 'delete', this.path, null, this.stat);
} else if (reason === 'failure') {
this.state = 'closed';
this.log('warn', "Failed to watch the path " + this.path);
} else {
this.state = 'closed';
}
if (watchers[this.path] != null) {
delete watchers[this.path];
watchersTotal--;
}
return this;
}
this.log('debug', "close: " + this.path);
_ref = this.children;
for (childRelativePath in _ref) {
if (!__hasProp.call(_ref, childRelativePath)) continue;
this.closeChild(childRelativePath, reason);
}
if (this.method === 'watchFile') {
fsUtil.unwatchFile(this.path);
} else if (this.method === 'watch' && this.fswatcher) {
this.fswatcher.close();
this.fswatcher = null;
}
if (reason === 'deleted') {
this.state = 'deleted';
this.emit('change', 'delete', this.path, null, this.stat);
} else {
this.state = 'closed';
}
if (watchers[this.path] != null) {
delete watchers[this.path];
}
return this;
};
};
_Class.prototype.closeChild = function(fileRelativePath, reason) {
var watcher;
watcher = this.children[fileRelativePath];
if (watcher) {
delete this.children[fileRelativePath];
watcher.close(reason);
}
return this;
};
_Class.prototype.closeChild = function(fileRelativePath, reason) {
var watcher;
if (this.children[fileRelativePath] != null) {
watcher = this.children[fileRelativePath];
if (watcher) {
watcher.close(reason);
}
delete this.children[fileRelativePath];
}
return this;
};
/*
Watch Child
Setup watching for a child
Bubble events of the child into our instance
Also instantiate the child with our instance's configuration where applicable
*/
/*
Watch Child
Setup watching for a child
Bubble events of the child into our instance
Also instantiate the child with our instance's configuration where applicable
*/
_Class.prototype.watchChild = function(fileFullPath, fileRelativePath, fileStat, next) {
var config, me, watcher,
_this = this;
me = this;
config = this.config;
watcher = watch({
path: fileFullPath,
stat: fileStat,
ignorePaths: config.ignorePaths,
ignoreHiddenFiles: config.ignoreHiddenFiles,
ignoreCommonPatterns: config.ignoreCommonPatterns,
ignoreCustomPatterns: config.ignoreCustomPatterns,
listeners: {
'change': function() {
var args, changeType, path;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
changeType = args[0], path = args[1];
if (changeType === 'delete' && path === fileFullPath) {
_this.closeChild(fileRelativePath, 'deleted');
}
return me.bubble.apply(me, ['change'].concat(__slice.call(args)));
_Class.prototype.watchChild = function(fileFullPath, fileRelativePath, fileStat, next) {
var config, me, _base;
me = this;
config = this.config;
(_base = me.children)[fileRelativePath] || (_base[fileRelativePath] = watch({
path: fileFullPath,
stat: fileStat,
listeners: {
'log': me.bubbler('log'),
'change': function() {
var args, changeType, path;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
changeType = args[0], path = args[1];
if (changeType === 'delete' && path === fileFullPath) {
me.closeChild(fileRelativePath, 'deleted');
}
return me.bubble.apply(me, ['change'].concat(__slice.call(args)));
},
'error': me.bubbler('error')
},
'error': me.bubbler('error')
},
next: function() {
var args, err;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
err = args[0];
if (err) {
return typeof next === "function" ? next(err) : void 0;
}
me.children[fileRelativePath] = watcher;
return typeof next === "function" ? next.apply(null, args) : void 0;
next: next,
outputLog: config.outputLog,
interval: config.interval,
persistent: config.persistent,
duplicateDelay: config.duplicateDelay,
preferredMethod: config.preferredMethod,
ignorePaths: config.ignorePaths,
ignoreHiddenFiles: config.ignoreHiddenFiles,
ignoreCommonPatterns: config.ignoreCommonPatterns,
ignoreCustomPatterns: config.ignoreCustomPatterns
}));
return me.children[fileRelativePath];
};
_Class.prototype.isIgnoredPath = function(path, opts) {
var ignore, _ref, _ref1, _ref2, _ref3;
if (opts == null) {
opts = {};
}
});
return watcher;
};
ignore = balUtil.isIgnoredPath(path, {
ignorePaths: (_ref = opts.ignorePaths) != null ? _ref : this.config.ignorePaths,
ignoreHiddenFiles: (_ref1 = opts.ignoreHiddenFiles) != null ? _ref1 : this.config.ignoreHiddenFiles,
ignoreCommonPatterns: (_ref2 = opts.ignoreCommonPatterns) != null ? _ref2 : this.config.ignoreCommonPatterns,
ignoreCustomPatterns: (_ref3 = opts.ignoreCustomPatterns) != null ? _ref3 : this.config.ignoreCustomPatterns
});
this.log('debug', "ignore: " + path + " " + (ignore ? 'yes' : 'no'));
return ignore;
};
_Class.prototype.isIgnoredPath = function(path, opts) {
var ignore, _ref, _ref1, _ref2, _ref3;
if (opts == null) {
opts = {};
}
ignore = balUtil.isIgnoredPath(path, {
ignorePaths: (_ref = opts.ignorePaths) != null ? _ref : this.config.ignorePaths,
ignoreHiddenFiles: (_ref1 = opts.ignoreHiddenFiles) != null ? _ref1 : this.config.ignoreHiddenFiles,
ignoreCommonPatterns: (_ref2 = opts.ignoreCommonPatterns) != null ? _ref2 : this.config.ignoreCommonPatterns,
ignoreCustomPatterns: (_ref3 = opts.ignoreCustomPatterns) != null ? _ref3 : this.config.ignoreCustomPatterns
});
this.log('debug', "ignore: " + path + " " + (ignore ? 'yes' : 'no'));
return ignore;
};
/*
Watch Children
next(err,result)
*/
/*
Watch
Setup the native watching handlers for our path so we can receive updates on when things happen
If the next argument has been received, then add it is a once listener for the watching event
If we are already watching this path then let's start again (call close)
If we are a directory, let's recurse
If we are deleted, then don't error but return the isWatching argument of our completion callback as false
Once watching has completed for this directory and all children, then emit the watching event
*/
_Class.prototype.watch = function(next) {
var config, me, startWatching,
_this = this;
me = this;
config = this.config;
if ((this.stat != null) === false) {
balUtil.stat(config.path, function(err, stat) {
if (err) {
return _this.emit('error', err);
}
_this.stat = stat;
_this.isDirectory = stat.isDirectory();
return _this.watch(next);
});
return this;
}
if (next != null) {
this.listen('watching', next);
}
this.close();
this.log('debug', "watch: " + this.path);
startWatching = function() {
var tasks, watchFileOpts;
tasks = new balUtil.Group(function(err) {
if (err) {
return _this.emit('watching', err, _this, false);
}
return _this.emit('watching', err, _this, true);
});
tasks.total = 2;
if (_this.isDirectory) {
_Class.prototype.watchChildren = function(next) {
var config, me;
me = this;
config = this.config;
if (this.isDirectory) {
balUtil.scandir({
path: _this.path,
path: this.path,
ignorePaths: config.ignorePaths,

@@ -463,5 +499,8 @@ ignoreHiddenFiles: config.ignoreHiddenFiles,

next: function(err) {
return tasks.complete(err);
return next(err, (err != null) === false);
},
action: function(fileFullPath, fileRelativePath, nextFile, fileStat) {
if (me.state !== 'active') {
return nextFile(null, true);
}
return me.watchChild(fileFullPath, fileRelativePath, fileStat, function(err) {

@@ -473,141 +512,270 @@ return nextFile(err);

} else {
tasks.complete();
next(null, true);
}
try {
watchFileOpts = {
persistent: config.persistent,
interval: config.interval
};
fsUtil.watchFile(_this.path, watchFileOpts, function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return me.listener.apply(me, args);
return this;
};
/*
Watch Self
*/
_Class.prototype.watchSelf = function(next) {
var complete, config, me, methods;
me = this;
config = this.config;
this.method = null;
methods = {
watch: function(next) {
if (fsUtil.watch == null) {
return next(null, false);
}
return safeExecute(next, function() {
me.fswatcher = fsUtil.watch(me.path, function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return me.listener.apply(me, args);
});
me.method = 'watch';
return next(null, true);
});
},
watchFile: function(next) {
if (fsUtil.watchFile == null) {
return next(null, false);
}
return safeExecute(next, function() {
var watchFileOpts;
watchFileOpts = {
persistent: config.persistent,
interval: config.interval
};
fsUtil.watchFile(me.path, watchFileOpts, function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return me.listener.apply(me, args);
});
me.method = 'watchFile';
return next(null, true);
});
}
};
complete = function(success) {
if (success == null) {
success = true;
}
if (success) {
me.state = 'active';
return next(null, true);
} else {
me.close('failure');
return next(null, false);
}
};
if (config.preferredMethod === 'watch') {
methods.watch(function(err, success) {
if (err) {
me.emit('error', err);
}
if (success) {
return complete(success);
}
return methods.watchFile(function(err, success) {
if (err) {
me.emit('error', err);
}
return complete(success);
});
});
_this.method = 'watchFile';
} catch (err) {
_this.fswatcher = fsUtil.watch(_this.path, function() {
var args;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return me.listener.apply(me, args);
} else {
methods.watchFile(function(err, success) {
if (err) {
me.emit('error', err);
}
if (success) {
return complete(success);
}
return methods.watchFile(function(err, success) {
if (err) {
me.emit('error', err);
}
return complete(success);
});
});
_this.method = 'watch';
}
_this.state = 'active';
return tasks.complete();
return this;
};
balUtil.exists(this.path, function(exists) {
if (!exists) {
return _this.emit('watching', null, _this, false);
/*
Watch
Setup the native watching handlers for our path so we can receive updates on when things happen
If the next argument has been received, then add it is a once listener for the watching event
If we are already watching this path then let's start again (call close)
If we are a directory, let's recurse
If we are deleted, then don't error but return the isWatching argument of our completion callback as false
Once watching has completed for this directory and all children, then emit the watching event
next(err,watcherInstance,success)
*/
_Class.prototype.watch = function(next) {
var complete, config, me,
_this = this;
me = this;
config = this.config;
if ((this.stat != null) === false) {
balUtil.stat(config.path, function(err, stat) {
if (err) {
return _this.emit('error', err);
}
_this.stat = stat;
_this.isDirectory = stat.isDirectory();
return _this.watch(next);
});
return this;
}
return startWatching();
});
return this;
};
if (next != null) {
this.listen('watching', next);
}
this.close();
this.log('debug', "watch: " + this.path);
complete = function(err, result) {
if (err == null) {
err = null;
}
if (result == null) {
result = true;
}
if (err || !result) {
me.close();
return me.emit('watching', err, me, false);
} else {
return me.emit('watching', null, me, true);
}
};
balUtil.exists(this.path, function(exists) {
if (!exists) {
return complete(null, false);
}
return me.watchSelf(function(err, result) {
if (err || !result) {
return complete(err, result);
}
return me.watchChildren(function(err, result) {
return complete(err, result);
});
});
});
return this;
};
return _Class;
return _Class;
})(EventEmitter);
})(EventEmitter);
/*
Create Watcher
Checks to see if the path actually exists, if it doesn't then exit gracefully
If it does exist, then lets check our cache for an already existing watcher instance
If we have an already existing watching instance, then just add our listeners to that
If we don't, then create a watching instance
Fire the next callback once done
next(err,watcherInstance)
*/
/*
Create Watcher
Checks to see if the path actually exists, if it doesn't then exit gracefully
If it does exist, then lets check our cache for an already existing watcher instance
If we have an already existing watching instance, then just add our listeners to that
If we don't, then create a watching instance
Fire the next callback once done
next(err,watcherInstance)
*/
createWatcher = function(opts, next) {
var listener, listeners, path, watcher;
path = opts.path, listener = opts.listener, listeners = opts.listeners;
if (opts.next != null) {
if (next == null) {
next = opts.next;
createWatcher = function(opts, next) {
var listener, listeners, path, watcher;
path = opts.path, listener = opts.listener, listeners = opts.listeners;
if (opts.next != null) {
if (next == null) {
next = opts.next;
}
delete opts.next;
}
delete opts.next;
}
if (!balUtil.existsSync(path)) {
if (typeof next === "function") {
next(null, null);
if (!balUtil.existsSync(path)) {
if (typeof next === "function") {
next(null, null);
}
return;
}
return;
}
if (watchers[path] != null) {
watcher = watchers[path];
if (listener) {
watcher.listen(listener);
if (watchers[path] != null) {
watcher = watchers[path];
if (listener) {
watcher.listen(listener);
}
if (listeners) {
watcher.listen(listeners);
}
if (typeof next === "function") {
next(null, watcher);
}
} else {
watcher = new Watcher(opts, function(err) {
return typeof next === "function" ? next(err, watcher) : void 0;
});
watchers[path] = watcher;
++watchersTotal;
}
if (listeners) {
watcher.listen(listeners);
}
if (typeof next === "function") {
next(null, watcher);
}
} else {
watcher = new Watcher(opts, function(err) {
return typeof next === "function" ? next(err, watcher) : void 0;
});
watchers[path] = watcher;
}
return watcher;
};
return watcher;
};
/*
Watch
Provides an abstracted API that supports multiple paths
If you are passing in multiple paths then do not rely on the return result containing all of the watchers
you must rely on the result inside the completion callback instead
If you used the paths option, then your results will be an array of watcher instances, otherwise they will be a single watcher instance
next(err,results)
*/
/*
Watch
Provides an abstracted API that supports multiple paths
If you are passing in multiple paths then do not rely on the return result containing all of the watchers
you must rely on the result inside the completion callback instead
If you used the paths option, then your results will be an array of watcher instances, otherwise they will be a single watcher instance
next(err,results)
*/
watch = function(opts, next) {
var path, paths, result, tasks, _i, _len;
result = [];
if (opts.next != null) {
if (next == null) {
next = opts.next;
watch = function(opts, next) {
var path, paths, result, tasks, _i, _len;
result = [];
if (opts.next != null) {
if (next == null) {
next = opts.next;
}
delete opts.next;
}
delete opts.next;
}
if (opts.paths) {
paths = opts.paths;
delete opts.paths;
if (balUtil.isArray(paths)) {
tasks = new balUtil.Group(function(err) {
return typeof next === "function" ? next(err, result) : void 0;
});
for (_i = 0, _len = paths.length; _i < _len; _i++) {
path = paths[_i];
tasks.push({
path: path
}, function(complete) {
var localOpts, watcher;
localOpts = balUtil.extend({}, opts);
localOpts.path = this.path;
watcher = createWatcher(localOpts, complete);
if (watcher) {
return result.push(watcher);
}
if (opts.paths) {
paths = opts.paths;
delete opts.paths;
if (balUtil.isArray(paths)) {
tasks = new balUtil.Group(function(err) {
return typeof next === "function" ? next(err, result) : void 0;
});
for (_i = 0, _len = paths.length; _i < _len; _i++) {
path = paths[_i];
tasks.push({
path: path
}, function(complete) {
var localOpts, watcher;
localOpts = balUtil.extend({}, opts);
localOpts.path = this.path;
watcher = createWatcher(localOpts, complete);
if (watcher) {
return result.push(watcher);
}
});
}
tasks.async();
} else {
opts.path = paths;
result.push(createWatcher(opts, function(err) {
return typeof next === "function" ? next(err, result) : void 0;
}));
}
tasks.async();
} else {
opts.path = paths;
result.push(createWatcher(opts, function(err) {
return typeof next === "function" ? next(err, result) : void 0;
}));
result = createWatcher(opts, next);
}
} else {
result = createWatcher(opts, next);
}
return result;
};
return result;
};
module.exports = {
watch: watch,
Watcher: Watcher
};
module.exports = {
watch: watch,
Watcher: Watcher
};
}).call(this);
{
"name": "watchr",
"version": "2.3.3",
"version": "2.3.4",
"description": "Better file system watching for Node.js",

@@ -33,3 +33,3 @@ "homepage": "https://github.com/bevry/watchr",

"dependencies": {
"bal-util": "~1.15.4"
"bal-util": "~1.16.3"
},

@@ -36,0 +36,0 @@ "devDependencies": {

@@ -19,2 +19,6 @@ ## Watchr: better file system watching for Node.js

- `stat` (optional, defaults to `null`) a file stat object to use for the path, instead of fetching a new one
- `interval` (optional, defaults to `100`) for systems that poll to detect file changes, how often should it poll in millseconds
- `persistent` (optional, defaults to `true`) whether or not we should keep the node process alive for as long as files are still being watched
- `duplicateDelay` (optional, defaults to `1000`) sometimes events will fire really fast, this delay is set in place so we don't fire the same event within the timespan
- `preferredMethod` (optional, defaults to `watch`) which watching method should try first? `watch` or `watchFile`
- `ignorePaths` (optional, defaults to `false`) an array of full paths to ignore

@@ -24,6 +28,3 @@ - `ignoreHiddenFiles` (optional, defaults to `false`) whether or not to ignored files which filename starts with a `.`

- `ignoreCustomPatterns` (optional, defaults to `null`) any custom ignore patterns that you would also like to ignore along with the common patterns
- `interval` (optional, defaults to `100`) for systems that poll to detect file changes, how often should it poll in millseconds
- `persistent` (optional, defaults to `true`) whether or not we should keep the node process alive for as long as files are still being watched
The following events are available to your via the listeners:

@@ -44,3 +45,3 @@

// Require
var watchr = require('watchr')
var watchr = require('watchr');

@@ -59,3 +60,7 @@ // Watch a directory or file

watching: function(err,watcherInstance,isWatching){
console.log('a new watcher instance finished setting up', arguments);
if (err) {
console.log("watching the path " + watcherInstance.path + " failed with error", err);
} else {
console.log("watching the path " + watcherInstance.path + " completed");
}
},

@@ -67,4 +72,7 @@ change: function(changeType,filePath,fileCurrentStat,filePreviousStat){

next: function(err,watchers){
// Watching all setup
console.log('Now watching our paths', arguments);
if (err) {
return console.log("watching everything failed with error", err);
} else {
console.log('watching everything completed', watchers);
}

@@ -83,5 +91,10 @@ // Close watchers after 10 seconds

You can test the above code snippet by installing watchr globally by running `npm install -g watchr` to install watchr, then `watchr <pathToWatch>` to watchr a particular path, and performing some file system modifications on that path.
You can test the above code snippet by running the following:
```
npm install watchr
./node_modules/.bin/watchr
```
## Support

@@ -88,0 +101,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc