Skip to content

Commit 4ff70bd

Browse files
committed
change handling of negated source patterns
Fixes #614. Allow negated source patterns to be specified without unsetting the default negation patterns. Allow source patterns to override the default negation patterns if they start with one of the ignored directories.
1 parent 36e2c24 commit 4ff70bd

File tree

3 files changed

+83
-36
lines changed

3 files changed

+83
-36
lines changed

docs/recipes/watch-mode.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ In AVA there's a distinction between *source files* and *test files*. As you can
5959

6060
By default AVA watches for changes to the test files, `package.json`, and any other `.js` files. It'll ignore files in [certain directories](https://github.com/novemberborn/ignore-by-default/blob/master/index.js) as provided by the [`ignore-by-default`] package.
6161

62-
You can configure patterns for the source files using the [`--source` CLI flag] or in the `ava` section of your `package.json` file. Note that if you specify a negative pattern the directories from [`ignore-by-default`] will no longer be ignored, so you may want to repeat these in your config.
62+
You can configure patterns for the source files using the [`--source` CLI flag] or in the `ava` section of your `package.json` file.
63+
64+
You can specify patterns to match files in the folders that would otherwise be ignored, e.g. use `node_modules/some-dependency/*.js` to specify all `.js` files in `node_modules/some-dependency` as a source, even though normally all files in `node_modules` are ignored. Note that you need to specify an exact directory; `{.bower_components,node_modules}/**/*.js` won't work.
6365

6466
If your tests write to disk they may trigger the watcher to rerun your tests. If this occurs you will need to use the `--source` flag.
6567

lib/watcher.js

+49-19
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ function rethrowAsync(err) {
2626
});
2727
}
2828

29+
function getDefaultIgnorePatterns() {
30+
return defaultIgnore.map(function (dir) {
31+
return dir + '/**/*';
32+
});
33+
}
34+
2935
// Used on paths before they're passed to multimatch to Harmonize matching
3036
// across platforms.
3137
var matchable = process.platform === 'win32' ? slash : function (path) {
@@ -281,42 +287,51 @@ function getChokidarPatterns(files, sources) {
281287
}
282288
});
283289

290+
// Allow source patterns to override the default ignore patterns. Chokidar
291+
// ignores paths that match the list of ignored patterns. It uses anymatch
292+
// under the hood, which supports negation patterns. For any source pattern
293+
// that starts with an ignored directory, ensure the corresponding negation
294+
// pattern is added to the ignored paths.
295+
var overrideDefaultIgnorePatterns = paths.filter(function (pattern) {
296+
return defaultIgnore.indexOf(pattern.split('/')[0]) >= 0;
297+
}).map(function (pattern) {
298+
return '!' + pattern;
299+
});
300+
ignored = getDefaultIgnorePatterns().concat(ignored, overrideDefaultIgnorePatterns);
301+
284302
if (paths.length === 0) {
285303
paths = ['package.json', '**/*.js'];
286304
}
287-
288305
paths = paths.concat(files);
289306

290-
if (ignored.length === 0) {
291-
ignored = defaultIgnore;
292-
}
293-
294307
return {
295308
paths: paths,
296309
ignored: ignored
297310
};
298311
}
299312

300313
function makeSourceMatcher(sources) {
301-
var patterns = sources;
314+
var mixedPatterns = [];
315+
var defaultIgnorePatterns = getDefaultIgnorePatterns();
316+
var overrideDefaultIgnorePatterns = [];
302317

303-
var hasPositivePattern = patterns.some(function (pattern) {
304-
return pattern[0] !== '!';
305-
});
318+
var hasPositivePattern = false;
319+
sources.forEach(function (pattern) {
320+
mixedPatterns.push(pattern);
321+
if (!hasPositivePattern && pattern[0] !== '!') {
322+
hasPositivePattern = true;
323+
}
306324

307-
var hasNegativePattern = patterns.some(function (pattern) {
308-
return pattern[0] === '!';
325+
// Extract patterns that start with an ignored directory. These need to be
326+
// rematched separately.
327+
if (defaultIgnore.indexOf(pattern.split('/')[0]) >= 0) {
328+
overrideDefaultIgnorePatterns.push(pattern);
329+
}
309330
});
310331

311332
// Same defaults as used for Chokidar.
312333
if (!hasPositivePattern) {
313-
patterns = ['package.json', '**/*.js'].concat(patterns);
314-
}
315-
316-
if (!hasNegativePattern) {
317-
patterns = patterns.concat(defaultIgnore.map(function (dir) {
318-
return '!' + dir + '/**/*';
319-
}));
334+
mixedPatterns = ['package.json', '**/*.js'].concat(mixedPatterns);
320335
}
321336

322337
return function (path) {
@@ -328,7 +343,22 @@ function makeSourceMatcher(sources) {
328343
return false;
329344
}
330345

331-
return multimatch(path, patterns).length === 1;
346+
var isSource = multimatch(path, mixedPatterns).length === 1;
347+
if (!isSource) {
348+
return false;
349+
}
350+
351+
var isIgnored = multimatch(path, defaultIgnorePatterns).length === 1;
352+
if (!isIgnored) {
353+
return true;
354+
}
355+
356+
var isErroneouslyIgnored = multimatch(path, overrideDefaultIgnorePatterns).length === 1;
357+
if (isErroneouslyIgnored) {
358+
return true;
359+
}
360+
361+
return false;
332362
};
333363
}
334364

test/watcher.js

+31-16
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@ group('chokidar is installed', function (beforeEach, test, group) {
158158
t.same(chokidar.watch.firstCall.args, [
159159
['package.json', '**/*.js'].concat(files),
160160
{
161-
ignored: defaultIgnore,
161+
ignored: defaultIgnore.map(function (dir) {
162+
return dir + '/**/*';
163+
}),
162164
ignoreInitial: true
163165
}
164166
]);
@@ -172,21 +174,25 @@ group('chokidar is installed', function (beforeEach, test, group) {
172174
t.same(chokidar.watch.firstCall.args, [
173175
['foo.js', 'baz.js'].concat(files),
174176
{
175-
ignored: ['bar.js', 'qux.js'],
177+
ignored: defaultIgnore.map(function (dir) {
178+
return dir + '/**/*';
179+
}).concat('bar.js', 'qux.js'),
176180
ignoreInitial: true
177181
}
178182
]);
179183
});
180184

181-
test('default set of ignored files if configured sources does not contain exclusion patterns', function (t) {
185+
test('configured sources can override default ignore patterns', function (t) {
182186
t.plan(2);
183-
start(['foo.js', 'baz.js']);
187+
start(['node_modules/foo/*.js']);
184188

185189
t.ok(chokidar.watch.calledOnce);
186190
t.same(chokidar.watch.firstCall.args, [
187-
['foo.js', 'baz.js'].concat(files),
191+
['node_modules/foo/*.js'].concat(files),
188192
{
189-
ignored: defaultIgnore,
193+
ignored: defaultIgnore.map(function (dir) {
194+
return dir + '/**/*';
195+
}).concat('!node_modules/foo/*.js'),
190196
ignoreInitial: true
191197
}
192198
]);
@@ -796,7 +802,7 @@ group('chokidar is installed', function (beforeEach, test, group) {
796802
});
797803
});
798804

799-
test('uses default patterns', function (t) {
805+
test('uses default source patterns', function (t) {
800806
t.plan(4);
801807
seed();
802808

@@ -821,16 +827,11 @@ group('chokidar is installed', function (beforeEach, test, group) {
821827
});
822828
});
823829

824-
test('uses default exclusion patterns if no exclusion pattern is given', function (t) {
830+
test('uses default exclusion patterns', function (t) {
825831
t.plan(2);
826832

827-
// Ensure each directory is treated as containing sources, but rely on
828-
// the default exclusion patterns, also based on these directories, to
829-
// exclude them again.
830-
var sources = defaultIgnore.map(function (dir) {
831-
return dir + '/**/*';
832-
});
833-
seed(sources);
833+
// Ensure each directory is treated as containing sources.
834+
seed(['**/*']);
834835

835836
// Synthesize an excluded file for each directory that's ignored by
836837
// default. Apply deeper nesting for each file.
@@ -839,7 +840,7 @@ group('chokidar is installed', function (beforeEach, test, group) {
839840
for (var i = index; i >= 0; i--) {
840841
relPath = path.join(relPath, String(i));
841842
}
842-
return relPath;
843+
return relPath + '.js';
843844
});
844845

845846
// Ensure test/1.js also depends on the excluded files.
@@ -858,6 +859,20 @@ group('chokidar is installed', function (beforeEach, test, group) {
858859
});
859860
});
860861

862+
test('allows default exclusion patterns to be overriden', function (t) {
863+
t.plan(2);
864+
seed(['node_modules/foo/*.js']);
865+
866+
var dep = path.join('node_modules', 'foo', 'index.js');
867+
emitDependencies(path.join('test', '1.js'), [path.resolve(dep)]);
868+
change(dep);
869+
870+
return debounce(1).then(function () {
871+
t.ok(api.run.calledTwice);
872+
t.same(api.run.secondCall.args, [[path.join('test', '1.js')], {runOnlyExclusive: false}]);
873+
});
874+
});
875+
861876
test('ignores dependencies outside of the current working directory', function (t) {
862877
t.plan(4);
863878
seed(['**/*.js', '..foo.js']);

0 commit comments

Comments
 (0)