Comparing version 0.3.2 to 0.3.3
@@ -26,17 +26,3 @@ module.exports = function(grunt) { | ||
}, | ||
}, | ||
watch: { | ||
gruntfile: { | ||
files: '<%= jshint.gruntfile.src %>', | ||
tasks: ['jshint:gruntfile'] | ||
}, | ||
lib: { | ||
files: '<%= jshint.lib.src %>', | ||
tasks: ['jshint:lib', 'nodeunit'] | ||
}, | ||
test: { | ||
files: '<%= jshint.test.src %>', | ||
tasks: ['jshint:test', 'nodeunit'] | ||
}, | ||
}, | ||
} | ||
}); | ||
@@ -46,4 +32,3 @@ grunt.loadNpmTasks('grunt-benchmark'); | ||
grunt.loadNpmTasks('grunt-contrib-nodeunit'); | ||
grunt.loadNpmTasks('grunt-contrib-watch'); | ||
grunt.registerTask('default', ['jshint', 'nodeunit']); | ||
}; |
249
lib/gaze.js
@@ -15,7 +15,5 @@ /* | ||
var path = require('path'); | ||
var _ = require('lodash'); | ||
var async = require('async'); | ||
var Glob = require('glob').Glob; | ||
var fileset = require('fileset'); | ||
var minimatch = require('minimatch'); | ||
var Gaze, gaze; | ||
var Gaze; | ||
@@ -25,4 +23,6 @@ // globals | ||
// exports | ||
module.exports = gaze; | ||
// Main entry point. Start watching and call done when setup | ||
module.exports = function gaze(files, opts, done) { | ||
return new Gaze(files, opts, done); | ||
}; | ||
@@ -49,9 +49,111 @@ // Node v0.6 compat | ||
// Main entry point. Start watching and call done when setup | ||
function gaze(files, opts, done) { | ||
return new Gaze(files, opts, done); | ||
// lodash helpers | ||
var ArrayPrototype = Array.prototype; | ||
var toString = Object.prototype.toString; | ||
var has = Object.prototype.hasOwnProperty; | ||
function defaults(obj, source) { | ||
for (var prop in source) { | ||
if (obj[prop] == null) { | ||
obj[prop] = source[prop]; | ||
} | ||
} | ||
return obj; | ||
} | ||
function unique() { | ||
var array = ArrayPrototype.concat.apply(ArrayPrototype, arguments); | ||
var result = []; | ||
for (var i = 0; i < array.length; i++) { | ||
if (result.indexOf(array[i]) === -1) { | ||
result.push(array[i]); | ||
} | ||
} | ||
return result; | ||
} | ||
function union() { | ||
return unique.apply(null, arguments); | ||
} | ||
function isString(obj) { | ||
return toString.call(obj) === '[object String]'; | ||
} | ||
function isEmpty(obj) { | ||
if (obj == null) { return true; } | ||
if (Array.isArray(obj) || isString(obj)) { return obj.length === 0; } | ||
for (var key in obj) { | ||
if (has.call(obj, key)) { return false; } | ||
} | ||
return true; | ||
} | ||
// async helper | ||
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; | ||
} | ||
// `Gaze` EventEmitter object to return in the callback | ||
Gaze = gaze.Gaze = __extends(function(files, opts, done) { | ||
Gaze = module.exports.Gaze = __extends(function(files, opts, done) { | ||
var _this = this; | ||
@@ -66,3 +168,3 @@ | ||
// Default options | ||
this.options = _.defaults(opts || {}, { | ||
this.options = defaults(opts || {}, { | ||
// Tell glob to mark directories | ||
@@ -123,3 +225,3 @@ mark: true, | ||
Object.keys(this._cached).forEach(function(oldFile) { | ||
if (_.indexOf(_this._cached[oldFile], 'deleted') !== -1) { | ||
if (_this._cached[oldFile].indexOf('deleted') !== -1) { | ||
args[0] = e = 'renamed'; | ||
@@ -136,4 +238,4 @@ [].push.call(args, oldFile); | ||
var cache = this._cached[filepath] || []; | ||
if (_.indexOf(cache, e) === -1) { | ||
this._objectPush(_this._cached, filepath, e); | ||
if (cache.indexOf(e) === -1) { | ||
_objectPush(_this._cached, filepath, e); | ||
clearTimeout(timeoutId); | ||
@@ -181,14 +283,19 @@ timeoutId = setTimeout(function() { | ||
} | ||
this._patterns = _.union(this._patterns, files); | ||
async.forEachSeries(files, function(pattern, next) { | ||
if (_.isEmpty(pattern)) { return; } | ||
_this._glob = new Glob(pattern, _this.options, function(err, files) { | ||
if (err) { | ||
_this.emit('error', err); | ||
return done(err); | ||
} | ||
_this._addToWatched(files); | ||
next(); | ||
}); | ||
}, function() { | ||
this._patterns = union(this._patterns, files); | ||
var include = [], exclude = []; | ||
this._patterns.forEach(function(p) { | ||
if (p.slice(0, 1) === '!') { | ||
exclude.push(p.slice(1)); | ||
} else { | ||
include.push(p); | ||
} | ||
}); | ||
fileset(include, exclude, _this.options, function(err, files) { | ||
if (err) { | ||
_this.emit('error', err); | ||
return done(err); | ||
} | ||
_this._addToWatched(files); | ||
_this.close(false); | ||
@@ -210,3 +317,3 @@ _this._initWatched(done); | ||
Object.keys(this._watched).forEach(function(dir) { | ||
var index = _.indexOf(_this._watched[dir], file); | ||
var index = _this._watched[dir].indexOf(file); | ||
if (index) { | ||
@@ -237,3 +344,3 @@ fs.unwatchFile(file); | ||
if (dir === '') { dir = '.'; } | ||
dir = this._markDir(dir); | ||
dir = _markDir(dir); | ||
unixify = unixify || false; | ||
@@ -243,10 +350,10 @@ Object.keys(this._watched).forEach(function(dir) { | ||
if (relDir === path.sep) { relDir = '.'; } | ||
unixRelDir = unixify ? _this._unixifyPathSep(relDir) : relDir; | ||
unixRelDir = unixify ? _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 (_isDir(file)) { | ||
relFile = _markDir(relFile); | ||
} | ||
if (unixify) { | ||
relFile = _this._unixifyPathSep(relFile); | ||
relFile = _unixifyPathSep(relFile); | ||
} | ||
@@ -257,3 +364,3 @@ return relFile; | ||
if (dir && unixify) { | ||
dir = this._unixifyPathSep(dir); | ||
dir = _unixifyPathSep(dir); | ||
} | ||
@@ -263,23 +370,2 @@ 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 !== '.') { | ||
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 | ||
@@ -303,10 +389,10 @@ Gaze.prototype._addToWatched = function(files) { | ||
// is dir, init key and sub folder | ||
filepath = _this._markDir(filepath); | ||
_this._objectPush(_this._watched, filepath); | ||
filepath = _markDir(filepath); | ||
_objectPush(_this._watched, filepath); | ||
parent = path.dirname(filepath) + path.sep; | ||
_this._objectPush(_this._watched, parent, filepath); | ||
_objectPush(_this._watched, parent, filepath); | ||
} else { | ||
// is file, add to dir | ||
dir = path.dirname(filepath) + path.sep; | ||
_this._objectPush(_this._watched, dir, filepath); | ||
_objectPush(_this._watched, dir, filepath); | ||
} | ||
@@ -317,18 +403,25 @@ }); | ||
// Create a `key:[]` if doesnt exist on `obj` then push or concat the `val` | ||
Gaze.prototype._objectPush = function(obj, key, val) { | ||
if (obj[key] == null) { obj[key] = []; } | ||
if (_.isArray(val)) { obj[key] = obj[key].concat(val); } | ||
else if (val) { obj[key].push(val); } | ||
return obj[key] = _.unique(obj[key]); | ||
}; | ||
// Returns true if the file matches this._patterns | ||
Gaze.prototype._isMatch = function(file) { | ||
var matched = false; | ||
this._patterns.forEach(function(pattern) { | ||
if (matched || (matched = minimatch(file, pattern)) ) { | ||
return false; | ||
var include = [], exclude = []; | ||
this._patterns.forEach(function(p) { | ||
if (p.slice(0, 1) === '!') { | ||
exclude.push(p.slice(1)); | ||
} else { | ||
include.push(p); | ||
} | ||
}); | ||
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; | ||
@@ -373,3 +466,3 @@ }; | ||
var curWatched = Object.keys(_this._watched); | ||
async.forEachSeries(curWatched, function(dir, next) { | ||
forEachSeries(curWatched, function(dir, next) { | ||
var files = _this._watched[dir]; | ||
@@ -401,6 +494,6 @@ // Triggered when a watched dir has an event | ||
// If file was deleted | ||
_.filter(previous, function(file) { | ||
return _.indexOf(current, file) < 0; | ||
previous.filter(function(file) { | ||
return current.indexOf(file) < 0; | ||
}).forEach(function(file) { | ||
if (!_this._isDir(file)) { | ||
if (!_isDir(file)) { | ||
var filepath = path.join(dir, file); | ||
@@ -413,7 +506,9 @@ _this.remove(filepath); | ||
// If file was added | ||
_.filter(current, function(file) { | ||
return _.indexOf(previous, file) < 0; | ||
current.filter(function(file) { | ||
return previous.indexOf(file) < 0; | ||
}).forEach(function(file) { | ||
// Is it a matching pattern? | ||
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)) { | ||
@@ -432,3 +527,3 @@ // Add to watch then emit event | ||
files.forEach(function(file) { | ||
if (_this._isDir(file)) { return; } | ||
if (_isDir(file)) { return; } | ||
_this._pollFile(file, function(err, filepath) { | ||
@@ -435,0 +530,0 @@ // Only emit changed if the file still exists |
{ | ||
"name": "gaze", | ||
"description": "A globbing fs.watch wrapper built from the best parts of other fine watch libs.", | ||
"version": "0.3.2", | ||
"version": "0.3.3", | ||
"homepage": "https://github.com/shama/gaze", | ||
@@ -31,12 +31,9 @@ "author": { | ||
"dependencies": { | ||
"async": "~0.1.22", | ||
"glob": "~3.1.14", | ||
"lodash": "~0.10.0", | ||
"minimatch": "~0.2.9" | ||
"minimatch": "~0.2.9", | ||
"fileset": "~0.1.5" | ||
}, | ||
"devDependencies": { | ||
"grunt": "~0.4.0rc4", | ||
"grunt-contrib-nodeunit": "~0.1.1", | ||
"grunt-contrib-jshint": "~0.1.0", | ||
"grunt-contrib-watch": "~0.2.0", | ||
"grunt": "~0.4.0rc7", | ||
"grunt-contrib-nodeunit": "~0.1.2rc6", | ||
"grunt-contrib-jshint": "~0.1.1rc6", | ||
"grunt-benchmark": "~0.1.1" | ||
@@ -43,0 +40,0 @@ }, |
@@ -154,2 +154,3 @@ # gaze [![Build Status](https://secure.travis-ci.org/shama/gaze.png?branch=master)](http://travis-ci.org/shama/gaze) | ||
## Release History | ||
* 0.3.3 - Fix for multiple patterns with negate. | ||
* 0.3.2 - Emit `end` before removeAllListeners. | ||
@@ -156,0 +157,0 @@ * 0.3.1 - Fix added events within subfolder patterns. |
@@ -39,2 +39,11 @@ 'use strict'; | ||
}, | ||
globArrayDot: function(test) { | ||
test.expect(1); | ||
gaze(['./sub/*.js'], function() { | ||
var result = this.relative(null, true); | ||
test.deepEqual(result['sub/'], ['one.js', 'two.js']); | ||
this.close(); | ||
test.done(); | ||
}); | ||
}, | ||
oddName: function(test) { | ||
@@ -41,0 +50,0 @@ test.expect(1); |
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
40087
2
4
26
1033
172
6
+ Addedfileset@~0.1.5
+ Addedfileset@0.1.8(transitive)
+ Addedglob@3.2.11(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedminimatch@0.3.0(transitive)
- Removedasync@~0.1.22
- Removedglob@~3.1.14
- Removedlodash@~0.10.0
- Removedasync@0.1.22(transitive)
- Removedglob@3.1.21(transitive)
- Removedgraceful-fs@1.2.3(transitive)
- Removedinherits@1.0.2(transitive)
- Removedlodash@0.10.0(transitive)