Socket
Socket
Sign inDemoInstall

gaze

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gaze - npm Package Compare versions

Comparing version 0.1.6 to 0.2.0

test/add_test.js

141

lib/gaze.js

@@ -29,2 +29,3 @@ /*

fs.existsSync = fs.existsSync || path.existsSync;
path.sep = path.sep || path.normalize('/');

@@ -69,3 +70,5 @@ // CoffeeScript's __extends utility

// Delay for events called in succession for the same file/event
debounceDelay: 500
debounceDelay: 500,
// Use a desired watch method over the other
forceWatchMethod: false
});

@@ -113,13 +116,19 @@

// Actually emit the event and `all` event
var emit = function() {
// If not added/deleted/changed/renamed then just emit the event
if (e.slice(-2) !== 'ed') {
Gaze.__super__.emit.apply(_this, args);
if (e === 'added' || e === 'changed' || e === 'deleted') {
Gaze.__super__.emit.apply(_this, ['all', e].concat([].slice.call(args, 1)));
}
return _this;
};
return this;
}
// If no filepath just emit the event
if (typeof filepath !== 'string') { return emit(); }
// Detect rename event, if added and previous deleted is in the cache
if (e === 'added') {
Object.keys(this._cached).forEach(function(oldFile) {
if (_.indexOf(_this._cached[oldFile], 'deleted') !== -1) {
args[0] = e = 'renamed';
[].push.call(args, oldFile);
delete _this._cached[oldFile];
return false;
}
});
}

@@ -135,3 +144,5 @@ // If cached doesnt exist, create a delay before running the next

}, this.options.debounceDelay);
return emit();
// Emit the event and `all` event
Gaze.__super__.emit.apply(_this, args);
Gaze.__super__.emit.apply(_this, ['all', e].concat([].slice.call(args, 1)));
}

@@ -209,25 +220,59 @@

// Returns `watched` files with relative paths to process.cwd()
Gaze.prototype.relative = function(dir) {
Gaze.prototype.relative = function(dir, unixify) {
var _this = this;
var relative = Object.create(null);
var relDir;
var relDir, relFile, unixRelDir;
var cwd = this.options.cwd || process.cwd();
dir = this._markDir(dir);
unixify = unixify || false;
Object.keys(this._watched).forEach(function(dir) {
relDir = path.relative(cwd, dir);
if (relDir === '') { relDir = '.'; }
relative[relDir] = _this._watched[dir].map(function(file) {
return path.relative(path.join(cwd, relDir), file);
relDir = path.relative(cwd, dir) + path.sep;
if (relDir === path.sep) { relDir = '.'; }
unixRelDir = unixify ? _this._unixifyPathSep(relDir) : relDir;
relative[unixRelDir] = _this._watched[dir].map(function(file) {
relFile = path.relative(path.join(cwd, relDir), file);
if (_this._isDir(file)) {
relFile = _this._markDir(relFile);
}
if (unixify) {
relFile = _this._unixifyPathSep(relFile);
}
return relFile;
});
});
if (dir && unixify) {
dir = this._unixifyPathSep(dir);
}
return dir ? relative[dir] || [] : relative;
};
// Ensures the dir is marked with path.sep
Gaze.prototype._markDir = function(dir) {
if (typeof dir === 'string' && dir.slice(-(path.sep.length)) !== path.sep) {
dir += path.sep;
}
return dir;
};
// Returns boolean whether filepath is dir terminated
Gaze.prototype._isDir = function(dir) {
if (typeof dir !== 'string') { return false; }
return (dir.slice(-(path.sep.length)) === path.sep);
};
// Changes path.sep to unix ones for testing
Gaze.prototype._unixifyPathSep = function(filepath) {
return (process.platform === 'win32') ? String(filepath).replace(/\\/g, '/') : filepath;
};
// Adds files and dirs to watched
Gaze.prototype._addToWatched = function(files) {
var _this = this;
var dir;
var dir, parent;
var cwd = _this.options.cwd || process.cwd();
files.forEach(function(file) {
var filepath = path.resolve(cwd, file);
// if mark false, use stat to figure the isDir
// the '/' mark comes from node-glob but we convert it to path.sep
if (_this.options.mark === false) {

@@ -238,11 +283,14 @@ if (fs.statSync(filepath).isDirectory()) {

}
// is a dir if marked with / at the end from glob
if (file.slice(-1) === '/') {
dir = filepath;
filepath = null;
// is dir, init key and sub folder
filepath = _this._markDir(filepath);
_this._objectPush(_this._watched, filepath);
parent = path.dirname(filepath) + path.sep;
_this._objectPush(_this._watched, parent, filepath);
} else {
dir = path.dirname(filepath);
// is file, add to dir
dir = path.dirname(filepath) + path.sep;
_this._objectPush(_this._watched, dir, filepath);
}
// Create a dir key on `watched` if doesnt exist and init array
_this._objectPush(_this._watched, dir, filepath);
});

@@ -252,3 +300,3 @@ return this;

// Create a `key`:[] if doesnt exist on `obj` then push or concat the `val`
// Create a `key:[]` if doesnt exist on `obj` then push or concat the `val`
Gaze.prototype._objectPush = function(obj, key, val) {

@@ -281,16 +329,20 @@ if (obj[key] == null) { obj[key] = []; }

try {
_this._watchers[file] = fs.watch(file, opts, function(event) {
if (typeof watchOne === 'function') {
watchTwo = null;
watchOne();
}
});
fs.watchFile(file, opts, function(curr, prev) {
if (curr.mtime.getTime() !== prev.mtime.getTime()) {
if (typeof watchTwo === 'function') {
watchOne = null;
watchTwo();
if (_this.options.forceWatchMethod === false || _this.options.forceWatchMethod === 'new') {
_this._watchers[file] = fs.watch(file, opts, function(event) {
if (typeof watchOne === 'function') {
watchTwo = null;
watchOne();
}
}
});
});
}
if (_this.options.forceWatchMethod === false || _this.options.forceWatchMethod === 'old') {
fs.watchFile(file, opts, function(curr, prev) {
if (curr.mtime.getTime() !== prev.mtime.getTime()) {
if (typeof watchTwo === 'function') {
watchOne = null;
watchTwo();
}
}
});
}
} catch (err) {

@@ -327,4 +379,6 @@ if (err.code === 'EMFILE') {

var filepath = path.join(dir, file);
_this.remove(filepath);
_this.emit('deleted', filepath);
if (!_this._isDir(file)) {
_this.remove(filepath);
_this.emit('deleted', filepath);
}
});

@@ -350,7 +404,8 @@

files.forEach(function(file) {
_this._watchFile(file, function(e, filepath) {
// TODO: If event rename, update the watched index
_this._watchFile(file, function(err, filepath) {
// Only emit changed if the file still exists
// Prevents changed/deleted duplicate events
if (fs.existsSync(filepath)) {
// TODO: This ignores changed events on folders, maybe support this?
// When a file is added, a folder changed event emits first
if (fs.existsSync(filepath) && !_this._isDir(file)) {
_this.emit('changed', filepath);

@@ -357,0 +412,0 @@ }

{
"name": "gaze",
"description": "A globbing fs.watch wrapper built from the best parts of other fine watch libs.",
"version": "0.1.6",
"version": "0.2.0",
"homepage": "https://github.com/shama/gaze",

@@ -6,0 +6,0 @@ "author": {

# gaze [![Build Status](https://secure.travis-ci.org/shama/gaze.png?branch=master)](http://travis-ci.org/shama/gaze)
A globbing fs.watch wrapper built from the best parts of other fine watch libs.
A globbing fs.watch wrapper built from the best parts of other fine watch libs.
Compatible with NodeJS v0.8/0.6, Windows, OSX and Linux.

@@ -103,2 +104,9 @@

* `options` The options object passed in.
* `interval` {integer} Interval to pass to fs.watchFile
* `debounceDelay` {integer} Delay for events called in succession for the same
file/event
* `forceWatchMethod` {'new'|'old'|false} Defaults to `false` to pick the first
triggered watch method. Set to `'new'` to only use `fs.watch` or `'old'` to
only use `fs.watchFile`. `'old'` is recommended if watch isn't firing or
you're watching files over a network.

@@ -110,4 +118,5 @@ #### Events

* `added(filepath)` When a file has been added to a watch directory.
* `changed(filepath)` When a file or directory has been changed.
* `deleted(filepath)` When a file or directory has been deleted.
* `changed(filepath)` When a file has been changed.
* `deleted(filepath)` When a file has been deleted.
* `renamed(newPath, oldPath)` When a file has been renamed.
* `end()` When the watcher is closed and watches have been removed.

@@ -125,6 +134,9 @@ * `error(err)` When an error occurs.

* `watched()` Returns the currently watched files.
* `relative()` Returns the currently watched files with relative paths.
* `relative([dir, unixify])` Returns the currently watched files with relative paths.
* `dir` {string} Only return relative files for this directory.
* `unixify` {boolean} Return paths with `/` instead of `\\` if on Windows.
## FAQs
## Why Another `fs.watch` Wrapper?
### Why Another `fs.watch` Wrapper?
I liked parts of other `fs.watch` wrappers but none had all the features I

@@ -138,2 +150,9 @@ needed. This lib combines the features I needed from other fine watch libs:

### How do I fix the error `EMFILE: Too many opened files.`?
This is because of your system's max opened file limit. For OSX the default is
very low (256). Increase your limit with `ulimit -n 10480`, the number being the
new max limit. If you're still running into issues then consider setting the
option `forceWatchMethod: 'old'` to use the old and slower stat polling watch
method.
## Contributing

@@ -145,2 +164,3 @@ In lieu of a formal styleguide, take care to maintain the existing coding style.

## Release History
* 0.2.0 - Support and mark folders with `path.sep`. Add `forceWatchMethod` option. Support `renamed` events.
* 0.1.6 - Recognize the `cwd` option properly

@@ -147,0 +167,0 @@ * 0.1.5 - Catch too many open file errors

@@ -14,5 +14,5 @@ 'use strict';

new gaze.Gaze('**/*', {}, function() {
var result = this.relative();
test.deepEqual(result['.'], ['one.js']);
test.deepEqual(result['sub'], ['one.js', 'two.js']);
var result = this.relative(null, true);
test.deepEqual(result['.'], ['Project (LO)/', 'nested/', 'one.js', 'sub/']);
test.deepEqual(result['sub/'], ['one.js', 'two.js']);
this.close();

@@ -25,3 +25,3 @@ test.done();

var g = gaze('**/*', function(err, watcher) {
test.deepEqual(watcher.relative('sub'), ['one.js', 'two.js']);
test.deepEqual(watcher.relative('sub', true), ['one.js', 'two.js']);
g.close();

@@ -35,3 +35,3 @@ test.done();

g.on('ready', function(watcher) {
test.deepEqual(watcher.relative('sub'), ['one.js', 'two.js']);
test.deepEqual(watcher.relative('sub', true), ['one.js', 'two.js']);
this.close();

@@ -38,0 +38,0 @@ test.done();

@@ -14,5 +14,5 @@ 'use strict';

gaze('**/*', function() {
var result = this.relative();
test.deepEqual(result['.'], ['one.js']);
test.deepEqual(result['sub'], ['one.js', 'two.js']);
var result = this.relative(null, true);
test.deepEqual(result['.'], ['Project (LO)/', 'nested/', 'one.js', 'sub/']);
test.deepEqual(result['sub/'], ['one.js', 'two.js']);
this.close();

@@ -25,3 +25,3 @@ test.done();

gaze('**/*', function() {
test.deepEqual(this.relative('sub'), ['one.js', 'two.js']);
test.deepEqual(this.relative('sub', true), ['one.js', 'two.js']);
this.close();

@@ -34,5 +34,5 @@ test.done();

gaze(['*.js', 'sub/*.js'], function() {
var result = this.relative();
var result = this.relative(null, true);
test.deepEqual(result['.'], ['one.js']);
test.deepEqual(result['sub'], ['one.js', 'two.js']);
test.deepEqual(result['sub/'], ['one.js', 'two.js']);
this.close();

@@ -45,4 +45,4 @@ test.done();

gaze(['Project (LO)/*.js'], function() {
var result = this.relative();
test.deepEqual(result['Project (LO)'], ['one.js']);
var result = this.relative(null, true);
test.deepEqual(result['Project (LO)/'], ['one.js']);
this.close();

@@ -49,0 +49,0 @@ test.done();

@@ -14,3 +14,7 @@ 'use strict';

'sub/tmp.js',
'sub/tmp'
'sub/tmp',
'sub/renamed.js',
'added.js',
'nested/added.js',
'nested/sub/added.js'
].forEach(function(d) {

@@ -34,4 +38,4 @@ var p = path.resolve(__dirname, 'fixtures', d);

this.remove(path.resolve(__dirname, 'fixtures'));
var result = this.relative();
test.deepEqual(result['sub'], ['one.js']);
var result = this.relative(null, true);
test.deepEqual(result['sub/'], ['one.js']);
test.notDeepEqual(result['.'], ['one.js']);

@@ -167,3 +171,47 @@ this.close();

});
},
addedEmitInSubFolders: function(test) {
test.expect(3);
var times = 0;
gaze('**/*', {debounceDelay:100}, function(err, watcher) {
watcher.on('added', function(filepath) {
test.equal('added.js', path.basename(filepath));
fs.unlinkSync(filepath);
times++;
if (times > 2) {
watcher.close();
test.done();
}
});
fs.writeFileSync(path.resolve(__dirname, 'fixtures', 'nested', 'sub', 'added.js'), 'var added = true;');
setTimeout(function() {
fs.writeFileSync(path.resolve(__dirname, 'fixtures', 'added.js'), 'var added = true;');
}, 500);
setTimeout(function() {
fs.writeFileSync(path.resolve(__dirname, 'fixtures', 'nested', 'added.js'), 'var added = true;');
}, 1000);
});
},
forceWatchMethodOld: function(test) {
test.expect(1);
gaze('**/*', {forceWatchMethod:'old'}, function(err, watcher) {
watcher.on('all', function(e, filepath) {
test.ok(true);
watcher.close();
test.done();
});
fs.writeFileSync(path.resolve(__dirname, 'fixtures', 'sub', 'two.js'), 'var two = true;');
});
},
forceWatchMethodNew: function(test) {
test.expect(1);
gaze('**/*', {forceWatchMethod:'new'}, function(err, watcher) {
watcher.on('all', function(e, filepath) {
test.ok(true);
watcher.close();
test.done();
});
fs.writeFileSync(path.resolve(__dirname, 'fixtures', 'sub', 'two.js'), 'var two = true;');
});
}
};
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