node-watch
Advanced tools
Comparing version 0.5.9 to 0.6.0
# Changelog | ||
## 0.6.0 | ||
Special thanks to [Timo Tijhof](https://github.com/Krinkle) | ||
* Drop support for node < 6.0 | ||
* Add `ready` event for the watcher. | ||
* Lots of bug fixed. | ||
## 0.5.9 | ||
@@ -4,0 +11,0 @@ * Fix function detection. |
@@ -16,2 +16,8 @@ var fs = require('fs'); | ||
}, | ||
emptyObject: function(item) { | ||
for (var key in item) { | ||
return false; | ||
} | ||
return true; | ||
}, | ||
buffer: function(item) { | ||
@@ -18,0 +24,0 @@ return Buffer.isBuffer(item); |
156
lib/watch.js
@@ -13,9 +13,4 @@ var fs = require('fs'); | ||
function makeArray(arr, offset) { | ||
return is.array(arr) | ||
? arr : [].slice.call(arr, offset || 0); | ||
} | ||
function hasDup(arr) { | ||
return makeArray(arr).some(function(v, i, self) { | ||
return arr.some(function(v, i, self) { | ||
return self.indexOf(v) !== i; | ||
@@ -26,3 +21,3 @@ }); | ||
function unique(arr) { | ||
return makeArray(arr).filter(function(v, i, self) { | ||
return arr.filter(function(v, i, self) { | ||
return self.indexOf(v) === i; | ||
@@ -32,18 +27,2 @@ }); | ||
function assign(obj/*, props */) { | ||
if (Object.assign) { | ||
return Object.assign.apply(Object, arguments); | ||
} | ||
return makeArray(arguments, 1) | ||
.reduce(function(mix, prop) { | ||
for (var name in prop) { | ||
if (prop.hasOwnProperty(name)) { | ||
mix[name] = prop[name]; | ||
} | ||
} | ||
return mix; | ||
}, obj); | ||
} | ||
function assertEncoding(encoding) { | ||
@@ -55,10 +34,2 @@ if (encoding && encoding !== 'buffer' && !Buffer.isEncoding(encoding)) { | ||
function toStringBuffer(input) { | ||
if (Buffer.from) { | ||
return Buffer.from(input); | ||
} | ||
return new Buffer(input); | ||
} | ||
function guard(fn) { | ||
@@ -79,6 +50,6 @@ return function(arg, action) { | ||
function composeMessage(names) { | ||
return makeArray(names).map(function(n) { | ||
if (!is.exists(n)) return [EVENT_REMOVE, n]; | ||
return [EVENT_UPDATE, n]; | ||
return names.map(function(n) { | ||
return is.exists(n) | ||
? [EVENT_UPDATE, n] | ||
: [EVENT_REMOVE, n]; | ||
}); | ||
@@ -103,5 +74,4 @@ } | ||
function debounce(fn) { | ||
function debounce(info, fn) { | ||
var timer, cache = []; | ||
var info = fn.info; | ||
var encoding = info.options.encoding; | ||
@@ -114,3 +84,3 @@ var delay = info.options.delay; | ||
getMessages(cache).forEach(function(msg) { | ||
msg[1] = toStringBuffer(msg[1]); | ||
msg[1] = Buffer.from(msg[1]); | ||
if (encoding !== 'buffer') { | ||
@@ -124,9 +94,4 @@ msg[1] = msg[1].toString(encoding); | ||
} | ||
return function(evt, name) { | ||
if (is.nil(name)) { | ||
name = ''; | ||
} | ||
cache.push( | ||
path.join(info.fpath, name) | ||
); | ||
return function(rawEvt, name) { | ||
cache.push(name); | ||
if (!timer) { | ||
@@ -153,3 +118,3 @@ timer = setTimeout(handle, delay); | ||
function getSubDirectories(dir, fn) { | ||
function getSubDirectories(dir, fn, done = function() {}) { | ||
if (is.directory(dir)) { | ||
@@ -162,3 +127,3 @@ fs.readdir(dir, function(err, all) { | ||
} | ||
else if (is.array(all)) { | ||
else { | ||
all.forEach(function(f) { | ||
@@ -168,7 +133,25 @@ var sdir = path.join(dir, f); | ||
}); | ||
done(); | ||
} | ||
}); | ||
} else { | ||
done(); | ||
} | ||
} | ||
function semaphore(final) { | ||
var counter = 0; | ||
return function start() { | ||
counter++; | ||
return function stop() { | ||
counter--; | ||
if (counter === 0) final(); | ||
}; | ||
}; | ||
} | ||
function nullCounter() { | ||
return function nullStop() {}; | ||
} | ||
var deprecationWarning = util.deprecate( | ||
@@ -184,2 +167,3 @@ function() {}, | ||
this.watchers = {}; | ||
this._isReady = false; | ||
this._isClosed = false; | ||
@@ -229,6 +213,21 @@ } | ||
} | ||
this._isClosed = true; | ||
process.nextTick(emitClose, this); | ||
// Do not close the Watcher unless all child watchers are closed. | ||
// https://github.com/yuanchuan/node-watch/issues/75 | ||
if (is.emptyObject(self.watchers)) { | ||
this._isClosed = true; | ||
process.nextTick(emitClose, this); | ||
} | ||
}; | ||
function emitReady(self) { | ||
if (!self._isReady) { | ||
self._isReady = true; | ||
// do not call emit for 'ready' until after watch() has returned, | ||
// so that consumer can call on(). | ||
process.nextTick(function () { | ||
self.emit('ready'); | ||
}); | ||
} | ||
} | ||
function emitClose(self) { | ||
@@ -244,6 +243,17 @@ self.emit('close'); | ||
var callback = function(evt, name) { | ||
// Internal callback for handling fs.FSWatcher 'change' events | ||
var internalOnChange = function(rawEvt, rawName) { | ||
if (self.isClosed()) { | ||
return; | ||
} | ||
// normalise lack of name and convert to full path | ||
var name; | ||
if (is.nil(rawName)) { | ||
name = ''; | ||
} else { | ||
name = rawName; | ||
} | ||
name = path.join(info.fpath, name); | ||
if (info.options.recursive) { | ||
@@ -254,3 +264,3 @@ hasNativeRecursive(function(has) { | ||
// remove watcher on removal | ||
if (evt === EVENT_REMOVE) { | ||
if (!is.exists(name)) { | ||
self.close(fullPath); | ||
@@ -266,2 +276,7 @@ } | ||
handlePublicEvents(rawEvt, name); | ||
}; | ||
// Debounced based on the 'delay' option | ||
var handlePublicEvents = debounce(info, function (evt, name) { | ||
// watch single file | ||
@@ -281,6 +296,4 @@ if (info.compareName) { | ||
} | ||
}; | ||
}); | ||
callback.info = info; | ||
watcher.on('error', function(err) { | ||
@@ -299,3 +312,3 @@ if (self.isClosed()) { | ||
watcher.on('change', debounce(callback)); | ||
watcher.on('change', internalOnChange); | ||
} | ||
@@ -305,3 +318,3 @@ | ||
var parent = path.join(file, '../'); | ||
var opts = assign({}, options, { | ||
var opts = Object.assign({}, options, { | ||
// no need to watch recursively | ||
@@ -318,3 +331,3 @@ recursive: false, | ||
fpath: parent, | ||
options: assign({}, opts, { | ||
options: Object.assign({}, opts, { | ||
encoding: options.encoding | ||
@@ -333,4 +346,5 @@ }), | ||
Watcher.prototype.watchDirectory = function(dir, options, fn) { | ||
Watcher.prototype.watchDirectory = function(dir, options, fn, counter = nullCounter) { | ||
var self = this; | ||
var done = counter(); | ||
hasNativeRecursive(function(has) { | ||
@@ -340,7 +354,7 @@ // always specify recursive | ||
// using utf8 internally | ||
var opts = assign({}, options, { | ||
var opts = Object.assign({}, options, { | ||
encoding: 'utf8' | ||
}); | ||
if (!has) { | ||
assign(opts, { recursive: false }); | ||
Object.assign(opts, { recursive: false }); | ||
} | ||
@@ -363,5 +377,7 @@ | ||
getSubDirectories(dir, function(d) { | ||
self.watchDirectory(d, options); | ||
}); | ||
self.watchDirectory(d, options, null, counter); | ||
}, counter()); | ||
} | ||
done(); | ||
}); | ||
@@ -373,2 +389,3 @@ } | ||
var filterDups = createDupsFilter(); | ||
var counter = watchers.length; | ||
watchers.forEach(function(w) { | ||
@@ -381,3 +398,9 @@ w.on('change', filterDups(function(evt, name) { | ||
}); | ||
w.on('ready', function() { | ||
if (!(--counter)) { | ||
emitReady(watcher); | ||
} | ||
}); | ||
}); | ||
watcher.close = function() { | ||
@@ -400,2 +423,5 @@ watchers.forEach(function(w) { | ||
if (is.array(fpath)) { | ||
if (fpath.length === 1) { | ||
return watch(fpath[0], options, fn); | ||
} | ||
var filterDups = createDupsFilter(); | ||
@@ -438,6 +464,10 @@ return composeWatcher(unique(fpath).map(function(f) { | ||
watcher.watchFile(fpath, options, fn); | ||
emitReady(watcher); | ||
} | ||
else if (is.directory(fpath)) { | ||
watcher.watchDirectory(fpath, options, fn); | ||
var counter = semaphore(function () { | ||
emitReady(watcher); | ||
}); | ||
watcher.watchDirectory(fpath, options, fn, counter); | ||
} | ||
@@ -444,0 +474,0 @@ |
@@ -14,3 +14,3 @@ { | ||
], | ||
"version": "0.5.9", | ||
"version": "0.6.0", | ||
"bugs": { | ||
@@ -24,4 +24,7 @@ "url": "https://github.com/yuanchuan/node-watch/issues" | ||
"scripts": { | ||
"test": "mocha test/test.js --exit" | ||
"test": "mocha test/test.js --exit --slow 500" | ||
}, | ||
"engines": { | ||
"node": ">=6" | ||
}, | ||
"devDependencies": { | ||
@@ -28,0 +31,0 @@ "fs-extra": "^7.0.1", |
@@ -93,5 +93,5 @@ # node-watch [![Status](https://travis-ci.org/yuanchuan/node-watch.svg?branch=master)](https://travis-ci.org/yuanchuan/node-watch "See test builds") | ||
```js | ||
var watcher = watch('./', { recursive: true }); | ||
#### Watcher events | ||
``` | ||
watcher.on('change', function(evt, name) { | ||
@@ -105,2 +105,10 @@ // callback | ||
watcher.on('ready', function() { | ||
// the watcher is ready to respond to changes | ||
}); | ||
``` | ||
#### Close | ||
``` | ||
// close | ||
@@ -129,2 +137,5 @@ watcher.close(); | ||
**Windows** | ||
* Will output its parent directory when a new file/directory is created in a deep directory. | ||
**Windows, node < v4.2.5** | ||
@@ -186,3 +197,3 @@ | ||
| :---: | :---: | :---: | :---: | :---: | :---: | :---: | | ||
| [<img src="https://avatars3.githubusercontent.com/u/142875?v=4" width="100px;"/><br /><sub><b>Steve Shreeve</b></sub>](https://github.com/shreeve)<br />[💻](https://github.com/yuanchuan/node-watch/commits?author=shreeve "Code") | [<img src="https://avatars2.githubusercontent.com/u/1456400?v=4" width="100px;"/><br /><sub><b>Blake Regalia</b></sub>](https://github.com/blake-regalia)<br />[💻](https://github.com/yuanchuan/node-watch/commits?author=blake-regalia "Code") | [<img src="https://avatars3.githubusercontent.com/u/1587937?v=4" width="100px;"/><br /><sub><b>Mike Collins</b></sub>](https://github.com/intervalia)<br />[💻](https://github.com/yuanchuan/node-watch/commits?author=intervalia "Code") | | ||
| [<img src="https://avatars3.githubusercontent.com/u/142875?v=4" width="100px;"/><br /><sub><b>Steve Shreeve</b></sub>](https://github.com/shreeve)<br />[💻](https://github.com/yuanchuan/node-watch/commits?author=shreeve "Code") | [<img src="https://avatars2.githubusercontent.com/u/1456400?v=4" width="100px;"/><br /><sub><b>Blake Regalia</b></sub>](https://github.com/blake-regalia)<br />[💻](https://github.com/yuanchuan/node-watch/commits?author=blake-regalia "Code") | [<img src="https://avatars3.githubusercontent.com/u/1587937?v=4" width="100px;"/><br /><sub><b>Mike Collins</b></sub>](https://github.com/intervalia)<br />[💻](https://github.com/yuanchuan/node-watch/commits?author=intervalia "Code") | [<img src="https://avatars3.githubusercontent.com/u/156867?v=4" width="100px;"/><br /><sub><b>Timo Tijhof</b></sub>](https://timotijhof.net)<br />[💻](https://github.com/yuanchuan/node-watch/commits?author=Krinkle "Code") | | ||
<!-- ALL-CONTRIBUTORS-LIST:END --> | ||
@@ -189,0 +200,0 @@ |
454
test/test.js
@@ -1,2 +0,1 @@ | ||
/* eslint-env mocha */ | ||
var assert = require('assert'); | ||
@@ -9,16 +8,15 @@ var Tree = require('./utils/builder'); | ||
function newBuffer(input) { | ||
if (Buffer.from) { | ||
return Buffer.from(input); | ||
} | ||
return new Buffer(input); | ||
} | ||
beforeEach(function(done) { | ||
beforeEach(function() { | ||
tree = Tree(); | ||
if (watcher && !watcher.isClosed()) watcher.close(); | ||
setTimeout(done, 500); | ||
}); | ||
afterEach(function(done) { | ||
if (watcher && !watcher.isClosed()) { | ||
watcher.on('close', done); | ||
watcher.close(); | ||
} else { | ||
done(); | ||
} | ||
}); | ||
after(function() { | ||
@@ -30,10 +28,47 @@ if (tree) { | ||
describe('process events', function() { | ||
it('should emit `close` event', function(done) { | ||
var file = 'home/a/file1'; | ||
var fpath = tree.getPath(file); | ||
watcher = watch(fpath, function() {}); | ||
watcher.on('close', function() { | ||
done(); | ||
}); | ||
watcher.close(); | ||
}); | ||
it('should emit `ready` event when watching a file', function(done) { | ||
var file = 'home/a/file1'; | ||
var fpath = tree.getPath(file); | ||
watcher = watch(fpath); | ||
watcher.on('ready', function() { | ||
done(); | ||
}); | ||
}); | ||
it('should emit `ready` event when watching a directory recursively', function(done) { | ||
var dir = tree.getPath('home'); | ||
watcher = watch(dir, { recursive: true }); | ||
watcher.on('ready', function() { | ||
done(); | ||
}); | ||
}); | ||
it('should emit `ready` properly in a composed watcher', function(done) { | ||
var dir1 = tree.getPath('home/a'); | ||
var dir2 = tree.getPath('home/b'); | ||
var file = tree.getPath('home/b/file1'); | ||
watcher = watch([dir1, dir2, file], { recursive: true }); | ||
watcher.on('ready', function() { | ||
done(); | ||
}); | ||
}); | ||
}); | ||
describe('watch for files', function() { | ||
it('should watch a single file and keep watching', function(done) { | ||
this.timeout(3000); // eslint-disable-line no-invalid-this | ||
var times = 1; | ||
var file = 'home/a/file1'; | ||
var fpath = tree.getPath(file); | ||
watcher = watch(fpath, function(evt, name) { | ||
watcher = watch(fpath, { delay: 0 }, function(evt, name) { | ||
assert.equal(fpath, name) | ||
@@ -44,5 +79,7 @@ if (times++ >= 3) { | ||
}); | ||
tree.modify(file, 100); | ||
tree.modify(file, 500); | ||
tree.modify(file, 900); | ||
watcher.on('ready', function() { | ||
tree.modify(file); | ||
tree.modify(file, 100); | ||
tree.modify(file, 200); | ||
}); | ||
}); | ||
@@ -56,3 +93,3 @@ | ||
]; | ||
watcher = watch(fpath, function(evt, name) { | ||
watcher = watch(fpath, { delay: 0 }, function(evt, name) { | ||
stack.splice(stack.indexOf(name), 1); | ||
@@ -62,4 +99,6 @@ if (!stack.length) done(); | ||
tree.modify('home/a/file1', 200); | ||
tree.modify('home/a/file2', 300); | ||
watcher.on('ready', function() { | ||
tree.modify('home/a/file1'); | ||
tree.modify('home/a/file2', 100); | ||
}); | ||
}); | ||
@@ -71,29 +110,63 @@ | ||
var times = 0; | ||
watcher = watch(fpath, function(evt, name) { | ||
watcher = watch(fpath, { delay: 200 }, function(evt, name) { | ||
if (fpath === name) times++; | ||
}); | ||
watcher.on('ready', function() { | ||
tree.modify(file); | ||
tree.modify(file, 100); | ||
tree.modify(file, 150); | ||
setTimeout(function() { | ||
assert(times === 1) | ||
assert.equal(times, 1) | ||
done(); | ||
}, 200); | ||
}, 250); | ||
}); | ||
tree.modify(file, 100); | ||
tree.modify(file, 120); | ||
tree.modify(file, 150); | ||
}); | ||
// https://github.com/yuanchuan/node-watch/issues/79 | ||
it('should listen to new created files', function(done) { | ||
var home = tree.getPath('home'); | ||
var newfile1 = 'home/a/newfile' + Math.random(); | ||
var newfile2 = 'home/a/newfile' + Math.random(); | ||
var changes = []; | ||
watcher = watch(home, { delay: 0, recursive: true }, function(evt, name) { | ||
changes.push(name); | ||
}); | ||
watcher.on('ready', function() { | ||
tree.newFile(newfile1); | ||
tree.newFile(newfile2); | ||
setTimeout(function() { | ||
assert.deepStrictEqual( | ||
changes, | ||
[tree.getPath(newfile1), tree.getPath(newfile2)] | ||
); | ||
done(); | ||
}, 100); | ||
}); | ||
}); | ||
}); | ||
describe('watch for directoies', function() { | ||
describe('watch for directories', function() { | ||
it('should watch directories inside a directory', function(done) { | ||
var home = tree.getPath('home'); | ||
var dir = tree.getPath('home/c'); | ||
var events = []; | ||
watcher = watch(home, { recursive: true }, function(evt, name) { | ||
assert.equal(dir, name); | ||
done(); | ||
watcher = watch(home, { delay: 0, recursive: true }, function(evt, name) { | ||
if (name === dir) { | ||
events.push(evt); | ||
} | ||
}); | ||
watcher.on('ready', function() { | ||
tree.remove('home/c'); | ||
tree.remove('home/c', 300); | ||
setTimeout(function () { | ||
assert.deepStrictEqual( | ||
events, | ||
[ 'remove' ] | ||
); | ||
done(); | ||
}, 400); | ||
}); | ||
}); | ||
@@ -103,3 +176,3 @@ | ||
var home = tree.getPath('home'); | ||
watcher = watch(home, { recursive: true }, function(evt, name) { | ||
watcher = watch(home, { delay: 0, recursive: true }, function(evt, name) { | ||
if (name === tree.getPath('home/new/file1')) { | ||
@@ -109,8 +182,56 @@ done(); | ||
}); | ||
tree.newFile('home/new/file1', 200); | ||
tree.modify('home/new/file1', 500); | ||
watcher.on('ready', function() { | ||
// newFile() will create the 'new/' directory and the 'new/file1' file, | ||
// but, only the creation of the directory is observed. | ||
// Because of that, there will only be one event for file1, when it | ||
// is modified, not when it is created. | ||
tree.newFile('home/new/file1'); | ||
tree.modify('home/new/file1', 100); | ||
}); | ||
}); | ||
it('should keep watching after removal of sub directory', function(done) { | ||
var home = tree.getPath('home'); | ||
var file1 = tree.getPath('home/e/file1'); | ||
var file2 = tree.getPath('home/e/file2'); | ||
var dir = tree.getPath('home/e/sub'); | ||
var events = []; | ||
watcher = watch(home, { delay: 0, recursive: true }, function(evt, name) { | ||
if (name === dir || name === file1 || name === file2) { | ||
events.push(name); | ||
} | ||
}); | ||
watcher.on('ready', function() { | ||
tree.remove('home/e/sub', 50); | ||
tree.modify('home/e/file1', 100); | ||
tree.modify('home/e/file2', 200); | ||
setTimeout(function() { | ||
assert.deepStrictEqual(events, [dir, file1, file2]); | ||
done(); | ||
}, 300); | ||
}); | ||
}); | ||
it('should watch new directories without delay', function(done) { | ||
var home = tree.getPath('home'); | ||
var events = []; | ||
watcher = watch(home, { delay: 200, recursive: true }, function(evt, name) { | ||
if (name === tree.getPath('home/new/file1')) { | ||
events.push(evt); | ||
} | ||
}); | ||
watcher.on('ready', function() { | ||
tree.newFile('home/new/file1'); | ||
tree.modify('home/new/file1', 50); | ||
tree.modify('home/new/file1', 100); | ||
setTimeout(function() { | ||
assert.deepStrictEqual(events, ['update']); | ||
done(); | ||
}, 350); | ||
}); | ||
}); | ||
}); | ||
describe('events', function() { | ||
describe('file events', function() { | ||
it('should identify `remove` event', function(done) { | ||
@@ -122,3 +243,5 @@ var file = 'home/a/file1'; | ||
}); | ||
tree.remove(file, 100); | ||
watcher.on('ready', function() { | ||
tree.remove(file); | ||
}); | ||
}); | ||
@@ -132,13 +255,5 @@ | ||
}); | ||
tree.modify(file, 100); | ||
}); | ||
it('should emit `close` event', function(done) { | ||
var file = 'home/a/file1'; | ||
var fpath = tree.getPath(file); | ||
watcher = watch(fpath, function() {}); | ||
watcher.on('close', function() { | ||
done(); | ||
watcher.on('ready', function() { | ||
tree.modify(file); | ||
}); | ||
watcher.close(); | ||
}); | ||
@@ -153,5 +268,6 @@ | ||
}); | ||
tree.newFile(file); | ||
watcher.on('ready', function() { | ||
tree.newFile(file); | ||
}); | ||
}); | ||
}); | ||
@@ -165,6 +281,9 @@ | ||
watcher = watch(dir, { recursive: true }, function(evt, name) { | ||
assert.equal(file, name); | ||
done(); | ||
if (file === name) { | ||
done(); | ||
} | ||
}); | ||
tree.modify('home/bb/file1', 300); | ||
watcher.on('ready', function() { | ||
tree.modify('home/bb/file1'); | ||
}); | ||
}); | ||
@@ -188,6 +307,8 @@ }); | ||
watcher = watch(dir, 'utf8', function(evt, name) { | ||
assert(name.toString() === fpath); | ||
assert.equal(name.toString(), fpath); | ||
done(); | ||
}); | ||
tree.modify(file, 200); | ||
watcher.on('ready', function() { | ||
tree.modify(file); | ||
}); | ||
}); | ||
@@ -201,6 +322,8 @@ | ||
assert(Buffer.isBuffer(name), 'not a Buffer') | ||
assert(name.toString() === fpath); | ||
assert.equal(name.toString(), fpath); | ||
done(); | ||
}); | ||
tree.modify(file, 200); | ||
watcher.on('ready', function() { | ||
tree.modify(file); | ||
}); | ||
}); | ||
@@ -213,4 +336,5 @@ | ||
watcher = watch(dir, 'base64', function(evt, name) { | ||
assert( | ||
name === newBuffer(fpath).toString('base64'), | ||
assert.equal( | ||
name, | ||
Buffer.from(fpath).toString('base64'), | ||
'wrong base64 encoding' | ||
@@ -220,3 +344,5 @@ ); | ||
}); | ||
tree.modify(file, 200); | ||
watcher.on('ready', function() { | ||
tree.modify(file); | ||
}); | ||
}); | ||
@@ -229,4 +355,5 @@ | ||
watcher = watch(dir, 'hex', function(evt, name) { | ||
assert( | ||
name === newBuffer(fpath).toString('hex'), | ||
assert.equal( | ||
name, | ||
Buffer.from(fpath).toString('hex'), | ||
'wrong hex encoding' | ||
@@ -236,3 +363,5 @@ ); | ||
}); | ||
tree.modify(file, 200); | ||
watcher.on('ready', function() { | ||
tree.modify(file); | ||
}); | ||
}); | ||
@@ -243,6 +372,7 @@ }); | ||
it('should only watch filtered directories', function(done) { | ||
var shouldModify = true; | ||
var shouldNotModify = false; | ||
var matchRegularDir = false; | ||
var matchIgnoredDir = false; | ||
var option = { | ||
var options = { | ||
delay: 0, | ||
recursive: true, | ||
@@ -254,18 +384,19 @@ filter: function(name) { | ||
watcher = watch(tree.getPath('home'), option, function(evt, name) { | ||
watcher = watch(tree.getPath('home'), options, function(evt, name) { | ||
if (/deep_node_modules/.test(name)) { | ||
shouldNotModify = true; | ||
matchIgnoredDir = true; | ||
} else { | ||
shouldModify = false; | ||
matchRegularDir = true; | ||
} | ||
}); | ||
watcher.on('ready', function() { | ||
tree.modify('home/b/file1'); | ||
tree.modify('home/deep_node_modules/ma/file1'); | ||
tree.modify('home/b/file1', 200); | ||
tree.modify('home/deep_node_modules/ma/file1', 500); | ||
setTimeout(function() { | ||
assert(!shouldModify, 'watch failed'); | ||
assert(!shouldNotModify, 'fail to ingore path `deep_node_modules`'); | ||
done(); | ||
}, 900); | ||
setTimeout(function() { | ||
assert(matchRegularDir, 'watch failed to detect regular file'); | ||
assert(!matchIgnoredDir, 'fail to ignore path `deep_node_modules`'); | ||
done(); | ||
}, 100); | ||
}); | ||
}); | ||
@@ -279,2 +410,3 @@ | ||
var options = { | ||
delay: 0, | ||
recursive: true, | ||
@@ -287,12 +419,19 @@ filter: function(name) { | ||
var times = 0; | ||
var matchIgnoredFile = false; | ||
watcher = watch(dir, options, function(evt, name) { | ||
times++; | ||
if (name === tree.getPath(file2)) { | ||
assert(times, 1, 'home/bb/file1 should be ignored.'); | ||
done(); | ||
if (name === tree.getPath(file1)) { | ||
matchIgnoredFile = true; | ||
} | ||
}); | ||
watcher.on('ready', function() { | ||
tree.modify(file1); | ||
tree.modify(file2); | ||
tree.modify(file1, 200); | ||
tree.modify(file2, 400); | ||
setTimeout(function() { | ||
assert.equal(times, 1, 'report file2'); | ||
assert.equal(matchIgnoredFile, false, 'home/bb/file1 should be ignored'); | ||
done(); | ||
}, 100); | ||
}); | ||
}); | ||
@@ -306,2 +445,3 @@ | ||
var options = { | ||
delay: 0, | ||
recursive: true, | ||
@@ -312,12 +452,19 @@ filter: /file2/ | ||
var times = 0; | ||
var matchIgnoredFile = false; | ||
watcher = watch(dir, options, function(evt, name) { | ||
times++; | ||
if (name === tree.getPath(file2)) { | ||
assert(times, 1, 'home/bb/file1 should be ignored.'); | ||
done(); | ||
if (name === tree.getPath(file1)) { | ||
matchIgnoredFile = true; | ||
} | ||
}); | ||
watcher.on('ready', function() { | ||
tree.modify(file1); | ||
tree.modify(file2); | ||
tree.modify(file1, 200); | ||
tree.modify(file2, 400); | ||
setTimeout(function() { | ||
assert(times, 1, 'report file2'); | ||
assert(!matchIgnoredFile, 'home/bb/file1 should be ignored'); | ||
done(); | ||
}, 100); | ||
}); | ||
}); | ||
@@ -331,18 +478,15 @@ }); | ||
var start; | ||
watcher = watch(dir, { delay: 1000 }, function(evt, name) { // eslint-disable-line no-unused-vars | ||
assert(Date.now() - start > 1000, 'delay not working'); | ||
watcher = watch(dir, { delay: 300 }, function(evt, name) { | ||
assert(Date.now() - start > 300, 'delay not working'); | ||
done(); | ||
}); | ||
setTimeout(function() { | ||
watcher.on('ready', function() { | ||
tree.modify(file); | ||
start = Date.now(); | ||
}, 200); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('parameters', function() { | ||
it('should throw error on non-existed file', function(done) { | ||
@@ -359,7 +503,9 @@ var somedir = tree.getPath('home/somedir'); | ||
var fpath = tree.getPath('home/a/file1'); | ||
watcher = watch(newBuffer(fpath), function(evt, name) { | ||
assert(name === fpath); | ||
watcher = watch(Buffer.from(fpath), { delay: 0 }, function(evt, name) { | ||
assert.equal(name, fpath); | ||
done(); | ||
}); | ||
tree.modify('home/a/file1', 100); | ||
watcher.on('ready', function() { | ||
tree.modify('home/a/file1'); | ||
}); | ||
}); | ||
@@ -376,3 +522,3 @@ | ||
var times = 0; | ||
watcher = watch(fpaths, function(evt, name) { | ||
watcher = watch(fpaths, { delay: 0 }, function(evt, name) { | ||
if (fpaths.indexOf(name) !== -1) times++; | ||
@@ -382,39 +528,41 @@ if (times === 2) done(); // calling done more than twice causes mocha test to fail | ||
tree.modify(file1, 100); | ||
tree.modify(file2, 150); | ||
watcher.on('ready', function() { | ||
tree.modify(file1); | ||
tree.modify(file2); | ||
}); | ||
}); | ||
it('should filter duplicate events for composed watcher', function(done) { | ||
var file1 = 'home'; | ||
var file2 = 'home/a'; | ||
var file3 = 'home/a/file2'; | ||
var newFile = 'home/a/newfile' + Date.now(); | ||
var home = 'home'; | ||
var dir = 'home/a'; | ||
var file1 = 'home/a/file1'; | ||
var file2 = 'home/a/file2'; | ||
var fpaths = [ | ||
tree.getPath(home), | ||
tree.getPath(dir), | ||
tree.getPath(file1), | ||
tree.getPath(file2), | ||
tree.getPath(file3) | ||
tree.getPath(file2) | ||
]; | ||
var changed = []; | ||
watcher = watch(fpaths, { recursive: true }, function(evt, name) { | ||
changed.push(name); | ||
var changes = []; | ||
watcher = watch(fpaths, { delay: 0, recursive: true }, function(evt, name) { | ||
changes.push(name); | ||
}); | ||
tree.modify(file3, 100); | ||
tree.newFile(newFile, 200); | ||
watcher.on('ready', function() { | ||
tree.modify(file1); | ||
tree.modify(file2); | ||
setTimeout(function() { | ||
assert.strictEqual(changed.length, 2, 'should log extactly 2 events'); | ||
assert(~changed.indexOf(tree.getPath(file3)), 'should include ' + file3); | ||
assert(~changed.indexOf(tree.getPath(newFile)), 'should include ' + newFile); | ||
done(); | ||
}, 600); | ||
setTimeout(function() { | ||
assert.deepStrictEqual( | ||
changes, | ||
[tree.getPath(file1), tree.getPath(file2)] | ||
); | ||
done(); | ||
}, 100); | ||
}); | ||
}); | ||
}); | ||
describe('watcher object', function() { | ||
it('should using watcher object to watch', function(done) { | ||
@@ -425,10 +573,11 @@ var dir = tree.getPath('home/a'); | ||
watcher = watch(dir); | ||
watcher.on('change', function(evt, name) { | ||
assert(evt === 'update'); | ||
assert(name === fpath); | ||
done(); | ||
watcher = watch(dir, { delay: 0 }); | ||
watcher.on('ready', function() { | ||
watcher.on('change', function(evt, name) { | ||
assert.equal(evt, 'update'); | ||
assert.equal(name, fpath); | ||
done(); | ||
}); | ||
tree.modify(file); | ||
}); | ||
tree.modify(file); | ||
}); | ||
@@ -440,15 +589,19 @@ | ||
var times = 0; | ||
watcher = watch(dir); | ||
watcher.on('change', function(evt, name) { // eslint-disable-line no-unused-vars | ||
watcher = watch(dir, { delay: 0 }); | ||
watcher.on('change', function(evt, name) { | ||
times++; | ||
}); | ||
watcher.close(); | ||
watcher.on('ready', function() { | ||
tree.modify(file); | ||
tree.modify(file, 300); | ||
setTimeout(function() { | ||
assert(watcher.isClosed(), 'watcher should be closed'); | ||
assert(times === 0, 'failed to close the watcher'); | ||
done(); | ||
}, 400); | ||
watcher.close(); | ||
tree.modify(file); | ||
tree.modify(file, 100); | ||
setTimeout(function() { | ||
assert(watcher.isClosed(), 'watcher should be closed'); | ||
assert.equal(times, 0, 'failed to close the watcher'); | ||
done(); | ||
}, 150); | ||
}); | ||
}); | ||
@@ -460,21 +613,22 @@ | ||
var times = 0; | ||
watcher = watch(dir); | ||
watcher = watch(dir, { delay: 0 }); | ||
watcher.on('change', function(evt, name) { | ||
times++; | ||
}); | ||
watcher.on('ready', function() { | ||
watcher.close(); | ||
watcher.close(); | ||
var timer = setInterval(function() { | ||
tree.modify(file); | ||
var timer = setInterval(function() { | ||
tree.modify(file); | ||
}); | ||
setTimeout(function() { | ||
clearInterval(timer); | ||
assert(watcher.isClosed(), 'watcher should be closed'); | ||
assert.equal(times, 0, 'failed to close the watcher'); | ||
done(); | ||
}, 100); | ||
}); | ||
setTimeout(function() { | ||
clearInterval(timer); | ||
assert(watcher.isClosed(), 'watcher should be closed'); | ||
assert(times === 0, 'failed to close the watcher'); | ||
done(); | ||
}, 400); | ||
}); | ||
}); |
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
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
46366
1187
204