Skip to content

Commit

Permalink
Fix: Match glob handling to vinyl-fs (fixes gulpjs/gulp#2192)
Browse files Browse the repository at this point in the history
  • Loading branch information
James Quigley authored and phated committed Nov 15, 2018
1 parent 10d7de9 commit b274b50
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 1 deletion.
49 changes: 48 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ var chokidar = require('chokidar');
var debounce = require('just-debounce');
var asyncDone = require('async-done');
var defaults = require('object.defaults/immutable');
var isNegatedGlob = require('is-negated-glob');
var anymatch = require('anymatch');

var defaultOpts = {
delay: 200,
Expand All @@ -24,6 +26,10 @@ function hasErrorListener(ee) {
return listenerCount(ee, 'error') !== 0;
}

function exists(val) {
return val != null;
}

function watch(glob, options, cb) {
if (typeof options === 'function') {
cb = options;
Expand All @@ -36,10 +42,51 @@ function watch(glob, options, cb) {
opt.events = [opt.events];
}

if (Array.isArray(glob)) {
// We slice so we don't mutate the passed globs array
glob = glob.slice();
} else {
glob = [glob];
}

var queued = false;
var running = false;

var watcher = chokidar.watch(glob, opt);
// These use sparse arrays to keep track of the index in the
// original globs array
var positives = new Array(glob.length);
var negatives = new Array(glob.length);

// Reverse the glob here so we don't end up with a positive
// and negative glob in position 0 after a reverse
glob.reverse().forEach(sortGlobs);

function sortGlobs(globString, index) {
var result = isNegatedGlob(globString);
if (result.negated) {
negatives[index] = result.pattern;
} else {
positives[index] = result.pattern;
}
}

function shouldBeIgnored(path) {
var positiveMatch = anymatch(positives, path, true);
var negativeMatch = anymatch(negatives, path, true);
// If negativeMatch is -1, that means it was never negated
if (negativeMatch === -1) {
return false;
}

// If the negative is "less than" the positive, that means
// it came later in the glob array before we reversed them
return negativeMatch < positiveMatch;
}

var toWatch = positives.filter(exists);

opt.ignored = shouldBeIgnored;
var watcher = chokidar.watch(toWatch, opt);

function runComplete(err) {
running = false;
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
"coveralls": "npm run cover && istanbul-coveralls"
},
"dependencies": {
"anymatch": "^2.0.0",
"async-done": "^1.2.0",
"chokidar": "^2.0.0",
"is-negated-glob": "^1.0.0",
"just-debounce": "^1.0.0",
"object.defaults": "^1.1.0"
},
Expand Down
40 changes: 40 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ describe('glob-watcher', function() {
var outFile2 = path.join(outDir, 'added.js');
var globPattern = '**/*.js';
var outGlob = normalizePath(path.join(outDir, globPattern));
var singleAdd = normalizePath(path.join(outDir, 'changed.js'));
var ignoreGlob = '!' + singleAdd;

function changeFile() {
fs.writeFileSync(outFile1, 'hello changed');
Expand Down Expand Up @@ -279,4 +281,42 @@ describe('glob-watcher', function() {
setTimeout(done, 500);
});
});

it('can ignore a glob after it has been added', function(done) {
watcher = watch([outGlob, ignoreGlob]);

watcher.once('change', function(filepath) {
// It should never reach here
expect(filepath).toNotExist();
done();
});

// We default `ignoreInitial` to true, so always wait for `on('ready')`
watcher.on('ready', changeFile);

setTimeout(done, 1500);
});

it('can re-add a glob after it has been negated', function(done) {
watcher = watch([outGlob, ignoreGlob, singleAdd]);

watcher.once('change', function(filepath) {
expect(filepath).toEqual(singleAdd);
done();
});

// We default `ignoreInitial` to true, so always wait for `on('ready')`
watcher.on('ready', changeFile);
});

it('does not mutate the globs array', function(done) {
var globs = [outGlob, ignoreGlob, singleAdd];
watcher = watch(globs);

expect(globs[0]).toEqual(outGlob);
expect(globs[1]).toEqual(ignoreGlob);
expect(globs[2]).toEqual(singleAdd);

done();
});
});

0 comments on commit b274b50

Please sign in to comment.