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.3.4 to 0.4.0

lib/helper.js

314

lib/gaze.js

@@ -16,4 +16,4 @@ /*

var path = require('path');
var fileset = require('fileset');
var minimatch = require('minimatch');
var globule = require('globule');
var helper = require('./helper');

@@ -25,4 +25,4 @@ // globals

function Gaze(patterns, opts, done) {
var _this = this;
EE.call(_this);
var self = this;
EE.call(self);

@@ -52,2 +52,5 @@ // If second arg is the callback

// Store watchFile listeners
this._pollers = Object.create(null);
// Store patterns

@@ -81,75 +84,6 @@ this._patterns = [];

// Node v0.6 compat
fs.existsSync = fs.existsSync || path.existsSync;
path.sep = path.sep || path.normalize('/');
/**
* Lo-Dash 1.0.1 <http://lodash.com/>
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.4.4 <http://underscorejs.org/>
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
* Available under MIT license <http://lodash.com/license>
*/
function unique() { var array = Array.prototype.concat.apply(Array.prototype, arguments); var result = []; for (var i = 0; i < array.length; i++) { if (result.indexOf(array[i]) === -1) { result.push(array[i]); } } return result; }
/**
* Copyright (c) 2010 Caolan McMahon
* Available under MIT license <https://raw.github.com/caolan/async/master/LICENSE>
*/
function forEachSeries(arr, iterator, callback) {
if (!arr.length) { return callback(); }
var completed = 0;
var iterate = function() {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function() {};
} else {
completed += 1;
if (completed === arr.length) {
callback(null);
} else {
iterate();
}
}
});
};
iterate();
}
// other helpers
// Returns boolean whether filepath is dir terminated
function _isDir(dir) {
if (typeof dir !== 'string') { return false; }
return (dir.slice(-(path.sep.length)) === path.sep);
}
// Create a `key:[]` if doesnt exist on `obj` then push or concat the `val`
function _objectPush(obj, key, val) {
if (obj[key] == null) { obj[key] = []; }
if (Array.isArray(val)) { obj[key] = obj[key].concat(val); }
else if (val) { obj[key].push(val); }
return obj[key] = unique(obj[key]);
}
// Ensures the dir is marked with path.sep
function _markDir(dir) {
if (typeof dir === 'string' &&
dir.slice(-(path.sep.length)) !== path.sep &&
dir !== '.') {
dir += path.sep;
}
return dir;
}
// Changes path.sep to unix ones for testing
function _unixifyPathSep(filepath) {
return (process.platform === 'win32') ? String(filepath).replace(/\\/g, '/') : filepath;
}
// Override the emit function to emit `all` events
// and debounce on duplicate events per file
Gaze.prototype.emit = function() {
var _this = this;
var self = this;
var args = arguments;

@@ -163,3 +97,3 @@

if (e.slice(-2) !== 'ed') {
Gaze.super_.prototype.emit.apply(_this, args);
Gaze.super_.prototype.emit.apply(self, args);
return this;

@@ -171,6 +105,6 @@ }

Object.keys(this._cached).forEach(function(oldFile) {
if (_this._cached[oldFile].indexOf('deleted') !== -1) {
if (self._cached[oldFile].indexOf('deleted') !== -1) {
args[0] = e = 'renamed';
[].push.call(args, oldFile);
delete _this._cached[oldFile];
delete self._cached[oldFile];
return false;

@@ -185,10 +119,10 @@ }

if (cache.indexOf(e) === -1) {
_objectPush(_this._cached, filepath, e);
helper.objectPush(self._cached, filepath, e);
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
delete _this._cached[filepath];
delete self._cached[filepath];
}, this.options.debounceDelay);
// Emit the event and `all` event
Gaze.super_.prototype.emit.apply(_this, args);
Gaze.super_.prototype.emit.apply(_this, ['all', e].concat([].slice.call(args, 1)));
Gaze.super_.prototype.emit.apply(self, args);
Gaze.super_.prototype.emit.apply(self, ['all', e].concat([].slice.call(args, 1)));
}

@@ -201,22 +135,19 @@

Gaze.prototype.close = function(_reset) {
var _this = this;
var self = this;
_reset = _reset === false ? false : true;
Object.keys(_this._watchers).forEach(function(file) {
_this._watchers[file].close();
Object.keys(self._watchers).forEach(function(file) {
self._watchers[file].close();
});
_this._watchers = Object.create(null);
self._watchers = Object.create(null);
Object.keys(this._watched).forEach(function(dir) {
fs.unwatchFile(dir);
_this._watched[dir].forEach(function(uFile) {
fs.unwatchFile(uFile);
});
self._unpollDir(dir);
});
if (_reset) {
_this._watched = Object.create(null);
self._watched = Object.create(null);
setTimeout(function() {
_this.emit('end');
_this.removeAllListeners();
}, delay + 100);
self.emit('end');
self.removeAllListeners();
}, delay + 100);
}
return _this;
return self;
};

@@ -226,26 +157,25 @@

Gaze.prototype.add = function(files, done) {
var _this = this;
if (typeof files === 'string') {
files = [files];
}
this._patterns = unique.apply(null, [this._patterns, files]);
if (typeof files === 'string') { files = [files]; }
this._patterns = helper.unique.apply(null, [this._patterns, files]);
files = globule.find(this._patterns, this.options);
this._addToWatched(files);
this.close(false);
this._initWatched(done);
};
var include = [], exclude = [];
this._patterns.forEach(function(p) {
if (p.slice(0, 1) === '!') {
exclude.push(p.slice(1));
} else {
include.push(p);
// Dont increment patterns and dont call done if nothing added
Gaze.prototype._internalAdd = function(file, done) {
var files = [];
if (helper.isDir(file)) {
files = globule.find(this._patterns, this.options);
} else {
if (globule.isMatch(this._patterns, file, this.options)) {
files = [file];
}
});
fileset(include, exclude, _this.options, function(err, files) {
if (err) {
_this.emit('error', err);
return done(err);
}
_this._addToWatched(files);
_this.close(false);
_this._initWatched(done);
});
}
if (files.length > 0) {
this._addToWatched(files);
this.close(false);
this._initWatched(done);
}
};

@@ -255,7 +185,6 @@

Gaze.prototype.remove = function(file) {
var _this = this;
var self = this;
if (this._watched[file]) {
// is dir, remove all files
fs.unwatchFile(file);
this._watched[file].forEach(fs.unwatchFile);
this._unpollDir(file);
delete this._watched[file];

@@ -265,6 +194,6 @@ } else {

Object.keys(this._watched).forEach(function(dir) {
var index = _this._watched[dir].indexOf(file);
if (index !== -1) {
fs.unwatchFile(file);
_this._watched[dir].splice(index, 1);
var index = self._watched[dir].indexOf(file);
if (index) {
self._unpollFile(file);
delete self._watched[dir][index];
return false;

@@ -287,3 +216,3 @@ }

Gaze.prototype.relative = function(dir, unixify) {
var _this = this;
var self = this;
var relative = Object.create(null);

@@ -293,3 +222,3 @@ var relDir, relFile, unixRelDir;

if (dir === '') { dir = '.'; }
dir = _markDir(dir);
dir = helper.markDir(dir);
unixify = unixify || false;

@@ -299,10 +228,10 @@ Object.keys(this._watched).forEach(function(dir) {

if (relDir === path.sep) { relDir = '.'; }
unixRelDir = unixify ? _unixifyPathSep(relDir) : relDir;
relative[unixRelDir] = _this._watched[dir].map(function(file) {
relFile = path.relative(path.join(cwd, relDir), file);
if (_isDir(file)) {
relFile = _markDir(relFile);
unixRelDir = unixify ? helper.unixifyPathSep(relDir) : relDir;
relative[unixRelDir] = self._watched[dir].map(function(file) {
relFile = path.relative(path.join(cwd, relDir) || '', file || '');
if (helper.isDir(file)) {
relFile = helper.markDir(relFile);
}
if (unixify) {
relFile = _unixifyPathSep(relFile);
relFile = helper.unixifyPathSep(relFile);
}

@@ -313,3 +242,3 @@ return relFile;

if (dir && unixify) {
dir = _unixifyPathSep(dir);
dir = helper.unixifyPathSep(dir);
}

@@ -321,41 +250,27 @@ return dir ? relative[dir] || [] : relative;

Gaze.prototype._addToWatched = function(files) {
var _this = this;
files.forEach(function(file) {
var filepath = path.resolve(_this.options.cwd, file);
for (var i = 0; i < files.length; i++) {
var file = files[i];
var filepath = path.resolve(this.options.cwd, file);
var dirname = (helper.isDir(file)) ? filepath : path.dirname(filepath);
dirname = helper.markDir(dirname);
if (file.slice(-1) === '/') { filepath += path.sep; }
_objectPush(_this._watched, path.dirname(filepath) + path.sep, filepath);
});
return this;
};
helper.objectPush(this._watched, path.dirname(filepath) + path.sep, filepath);
// Returns true if the file matches this._patterns
Gaze.prototype._isMatch = function(file) {
var include = [], exclude = [];
this._patterns.forEach(function(p) {
if (p.slice(0, 1) === '!') {
exclude.push(p.slice(1));
} else {
include.push(p);
// add folders into the mix
var readdir = fs.readdirSync(dirname);
for (var j = 0; j < readdir.length; j++) {
var dirfile = path.join(dirname, readdir[j]);
if (fs.statSync(dirfile).isDirectory()) {
helper.objectPush(this._watched, dirname, dirfile + path.sep);
}
}
});
var matched = false, i = 0;
for (i = 0; i < include.length; i++) {
if (minimatch(file, include[i])) {
matched = true;
break;
}
}
for (i = 0; i < exclude.length; i++) {
if (minimatch(file, exclude[i])) {
matched = false;
break;
}
}
return matched;
return this;
};
Gaze.prototype._watchDir = function(dir, done) {
var _this = this;
try {
_this._watchers[dir] = fs.watch(dir, function(event) {
this._watchers[dir] = fs.watch(dir, function(event) {
// race condition. Let's give the fs a little time to settle down. so we

@@ -375,12 +290,29 @@ // don't fire events on non existent files.

Gaze.prototype._unpollFile = function(file) {
if (this._pollers[file]) {
fs.unwatchFile(file, this._pollers[file] );
delete this._pollers[file];
}
return this;
};
Gaze.prototype._unpollDir = function(dir) {
this._unpollFile(dir);
for (var i = 0; i < this._watched[dir].length; i++) {
this._unpollFile(this._watched[dir][i]);
}
};
Gaze.prototype._pollFile = function(file, done) {
var _this = this;
var opts = { persistent: true, interval: _this.options.interval };
var opts = { persistent: true, interval: this.options.interval };
if (!this._pollers[file]) {
this._pollers[file] = function(curr, prev) {
done(null, file);
};
try {
fs.watchFile(file, opts, function(curr, prev) {
done(null, file);
});
fs.watchFile(file, opts, this._pollers[file]);
} catch (err) {
return this._handleError(err);
}
}
return this;

@@ -391,13 +323,15 @@ };

Gaze.prototype._initWatched = function(done) {
var _this = this;
var self = this;
var cwd = this.options.cwd || process.cwd();
var curWatched = Object.keys(_this._watched);
forEachSeries(curWatched, function(dir, next) {
var files = _this._watched[dir];
var curWatched = Object.keys(self._watched);
helper.forEachSeries(curWatched, function(dir, next) {
dir = dir || '';
var files = self._watched[dir];
// Triggered when a watched dir has an event
_this._watchDir(dir, function(event, dirpath) {
self._watchDir(dir, function(event, dirpath) {
var relDir = cwd === dir ? '.' : path.relative(cwd, dir);
relDir = relDir || '';
fs.readdir(dirpath, function(err, current) {
if (err) { return _this.emit('error', err); }
if (err) { return self.emit('error', err); }
if (!current) { return; }

@@ -419,3 +353,3 @@

// Get watched files for this dir
var previous = _this.relative(relDir);
var previous = self.relative(relDir);

@@ -426,6 +360,6 @@ // If file was deleted

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

@@ -440,10 +374,6 @@ });

var relFile = path.join(relDir, file);
// TODO: this can be optimized more
// we shouldnt need isMatch() and could just use add()
if (_this._isMatch(relFile)) {
// Add to watch then emit event
_this.add(relFile, function() {
_this.emit('added', path.join(dir, file));
});
}
// Add to watch then emit event
self._internalAdd(relFile, function() {
self.emit('added', path.join(dir, file));
});
});

@@ -456,10 +386,8 @@

files.forEach(function(file) {
if (_isDir(file)) { return; }
_this._pollFile(file, function(err, filepath) {
if (helper.isDir(file)) { return; }
self._pollFile(file, function(err, filepath) {
// Only emit changed if the file still exists
// Prevents changed/deleted duplicate events
// 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.emit('changed', filepath);
self.emit('changed', filepath);
}

@@ -475,4 +403,4 @@ });

setTimeout(function() {
_this.emit('ready', _this);
done.call(_this, null, _this);
self.emit('ready', self);
done.call(self, null, self);
}, delay + 100);

@@ -479,0 +407,0 @@

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

@@ -25,3 +25,3 @@ "author": {

"engines": {
"node": ">= 0.6.0"
"node": ">= 0.8.0"
},

@@ -32,10 +32,9 @@ "scripts": {

"dependencies": {
"minimatch": "~0.2.9",
"fileset": "~0.1.5"
"globule": "~0.1.0"
},
"devDependencies": {
"grunt": "~0.4.0rc7",
"grunt-contrib-nodeunit": "~0.1.2rc6",
"grunt-contrib-jshint": "~0.1.1rc6",
"grunt-benchmark": "~0.1.1"
"grunt": "~0.4.1",
"grunt-contrib-nodeunit": "~0.2.0",
"grunt-contrib-jshint": "~0.6.0",
"grunt-benchmark": "~0.2.0"
},

@@ -42,0 +41,0 @@ "keywords": [

@@ -5,3 +5,3 @@ # gaze [![Build Status](https://secure.travis-ci.org/shama/gaze.png?branch=master)](http://travis-ci.org/shama/gaze)

Compatible with NodeJS v0.8/0.6, Windows, OSX and Linux.
Compatible with Node.js 0.10/0.8, Windows, OSX and Linux.

@@ -155,2 +155,3 @@ ## Usage

## Release History
* 0.4.0 - Drop support for node v0.6. Use globule for file matching. Avoid node v0.10 path.resolve/join errors. Register new files when added to non-existent folder. Multiple instances can now poll the same files (@jpommerening).
* 0.3.4 - Code clean up. Fix path must be strings errors (@groner). Fix incorrect added events (@groner).

@@ -157,0 +158,0 @@ * 0.3.3 - Fix for multiple patterns with negate.

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

var fixtures = path.resolve(__dirname, 'fixtures');
exports.add = {
setUp: function(done) {
process.chdir(path.resolve(__dirname, 'fixtures'));
process.chdir(fixtures);
done();

@@ -23,9 +25,9 @@ },

'nested/sub/two.js',
'one.js'
'one.js',
];
var expected = {
'Project (LO)/': ['one.js'],
'.': ['Project (LO)/', 'nested/', 'one.js'],
'nested/': ['one.js', 'three.js', 'sub/'],
'nested/sub/': ['two.js']
'.': ['Project (LO)/', 'nested/', 'one.js', 'sub/'],
'nested/': ['sub/', 'sub2/', 'one.js', 'three.js'],
'nested/sub/': ['two.js'],
};

@@ -32,0 +34,0 @@ var gaze = new Gaze('addnothingtowatch');

@@ -1,1 +0,1 @@

var test = true;
var test = true;
'use strict';
var gaze = require('../lib/gaze.js');
var grunt = require('grunt');
var path = require('path');
var fixtures = path.resolve(__dirname, 'fixtures');
function cleanUp(done) {
[
'newfolder',
].forEach(function(d) {
var p = path.join(fixtures, d);
if (grunt.file.exists(p)) {
grunt.file.delete(p);
}
});
done();
}
exports.matching = {
setUp: function(done) {
process.chdir(path.resolve(__dirname, 'fixtures'));
done();
process.chdir(fixtures);
cleanUp(done);
},
tearDown: cleanUp,
globAll: function(test) {

@@ -33,3 +49,3 @@ test.expect(2);

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

@@ -57,3 +73,20 @@ this.close();

});
}
},
addedLater: function(test) {
test.expect(2);
var times = 0;
gaze('**/*.js', function(err, watcher) {
watcher.on('all', function(status, filepath) {
times++;
var result = watcher.relative(null, true);
test.deepEqual(result['newfolder/'], ['added.js']);
if (times > 1) { watcher.close(); }
});
grunt.file.write(path.join(fixtures, 'newfolder', 'added.js'), 'var added = true;');
setTimeout(function() {
grunt.file.write(path.join(fixtures, 'newfolder', 'added.js'), 'var added = true;');
}, 1000);
watcher.on('end', test.done);
});
},
};

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

gaze._addToWatched(files);
test.deepEqual(gaze.relative('.', true), ['Project (LO)/', 'nested/', 'one.js']);
test.deepEqual(gaze.relative('.', true), ['Project (LO)/', 'nested/', 'one.js', 'sub/']);
test.done();
}
};

@@ -7,5 +7,2 @@ 'use strict';

// Node v0.6 compat
fs.existsSync = fs.existsSync || path.existsSync;
// Clean up helper to call in setUp and tearDown

@@ -12,0 +9,0 @@ function cleanUp(done) {

@@ -7,5 +7,2 @@ 'use strict';

// Node v0.6 compat
fs.existsSync = fs.existsSync || path.existsSync;
// Clean up helper to call in setUp and tearDown

@@ -12,0 +9,0 @@ function cleanUp(done) {

@@ -8,5 +8,2 @@ 'use strict';

// Node v0.6 compat
fs.existsSync = fs.existsSync || path.existsSync;
// Clean up helper to call in setUp and tearDown

@@ -208,2 +205,42 @@ function cleanUp(done) {

},
multipleWatchersSimultaneously: function(test) {
test.expect(2);
var did = 0;
var ready = 0;
var cwd = path.resolve(__dirname, 'fixtures', 'sub');
var watchers = [];
var timeout = setTimeout(function() {
test.ok(false, "Only " + did + " of " + ready + " watchers fired.");
test.done();
watchers.forEach(function(watcher) {
watcher.close();
});
}, 1000);
function isReady() {
ready++;
if (ready > 1) {
fs.writeFileSync(path.resolve(cwd, 'one.js'), 'var one = true;');
}
}
function isDone() {
did++;
if (did > 1) {
clearTimeout(timeout);
watchers.forEach(function(watcher) {
watcher.close();
});
test.done();
}
}
function changed(filepath) {
test.equal(path.join('sub', 'one.js'), path.relative(process.cwd(), filepath));
isDone();
}
for (var i = 0; i < 2; i++) {
watchers[i] = new gaze.Gaze('sub/one.js');
watchers[i].on('changed', changed);
watchers[i].on('ready', isReady);
}
},
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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