diff --git a/.gitignore b/.gitignore index 397b8d1ea..f47f288c0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ test/build/ *.covered.js *.swp needs-transpile.js + +!*test/fixtures/cli/include-exclude/node_modules/ diff --git a/index.js b/index.js index f98122e93..77d492678 100755 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ /* global __coverage__ */ +const arrayUniq = require('array-uniq') const arrify = require('arrify') const cachingTransform = require('caching-transform') const util = require('util') @@ -247,16 +248,20 @@ NYC.prototype.instrumentAllFiles = function (input, output, cb) { } NYC.prototype.walkAllFiles = function (dir, visitor) { - var pattern = null - if (this.extensions.length === 1) { - pattern = '**/*' + this.extensions[0] - } else { - pattern = '**/*{' + this.extensions.join() + '}' - } + const pattern = (this.extensions.length === 1) + ? `**/*${this.extensions[0]}` + : `**/*{${this.extensions.join()}}` - glob.sync(pattern, { cwd: dir, nodir: true, ignore: this.exclude.exclude }).forEach(function (filename) { - visitor(filename) + let filesToWalk = glob.sync(pattern, { cwd: dir, nodir: true, ignore: this.exclude.exclude }) + + // package node-glob no longer observes negated excludes, so we need to restore these files ourselves + const excludeNegatedPaths = this.exclude.excludeNegated + excludeNegatedPaths.forEach(pattern => { + filesToWalk = filesToWalk.concat(glob.sync(pattern, { cwd: dir, nodir: true })) }) + filesToWalk = arrayUniq(filesToWalk) + + filesToWalk.forEach(visitor) } NYC.prototype._maybeInstrumentSource = function (code, filename, relFile) { diff --git a/package-lock.json b/package-lock.json index 10f0767a9..5f98c1fe6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -215,6 +215,11 @@ "es-abstract": "^1.7.0" } }, + "array-uniq": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-2.0.0.tgz", + "integrity": "sha512-O3QZEr+3wDj7otzF7PjNGs6CA3qmYMLvt5xGkjY/V0VxS+ovvqVo/5wKM/OVOAyuX4DTh9H31zE/yKtO66hTkg==" + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", diff --git a/package.json b/package.json index 326571721..1d789a7ed 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "license": "ISC", "dependencies": { "archy": "^1.0.0", + "array-uniq": "^2.0.0", "arrify": "^1.0.1", "caching-transform": "^3.0.1", "convert-source-map": "^1.6.0", diff --git a/test/fixtures/cli/include-exclude/exclude-negated.js b/test/fixtures/cli/include-exclude/exclude-negated.js new file mode 100644 index 000000000..239a04e74 --- /dev/null +++ b/test/fixtures/cli/include-exclude/exclude-negated.js @@ -0,0 +1,2 @@ +'use strict'; +console.log('Hello, World!') diff --git a/test/fixtures/cli/include-exclude/excluded.js b/test/fixtures/cli/include-exclude/excluded.js new file mode 100644 index 000000000..239a04e74 --- /dev/null +++ b/test/fixtures/cli/include-exclude/excluded.js @@ -0,0 +1,2 @@ +'use strict'; +console.log('Hello, World!') diff --git a/test/fixtures/cli/include-exclude/node_modules/cover-me.js b/test/fixtures/cli/include-exclude/node_modules/cover-me.js new file mode 100644 index 000000000..239a04e74 --- /dev/null +++ b/test/fixtures/cli/include-exclude/node_modules/cover-me.js @@ -0,0 +1,2 @@ +'use strict'; +console.log('Hello, World!') diff --git a/test/nyc-bin.js b/test/nyc-bin.js index 1aae65b97..3529ee9ba 100644 --- a/test/nyc-bin.js +++ b/test/nyc-bin.js @@ -101,6 +101,48 @@ describe('the nyc cli', function () { done() }) }) + + it('should allow negated exclude patterns', function (done) { + const args = [bin, '--all', '--exclude', '**/include-exclude/**', '--exclude', '!**/exclude-negated.js', process.execPath, './half-covered.js'] + + const proc = spawn(process.execPath, args, { + cwd: fixturesCLI, + env: env + }) + + let stdout = '' + proc.stdout.on('data', chunk => { + stdout += chunk + }) + + proc.on('close', code => { + code.should.equal(0) + stdout.should.not.match(/excluded\.js/) + stdout.should.match(/exclude-negated\.js/) + done() + }) + }) + + it('should include \'node_modules\' using exclude patterns', function (done) { + const args = [bin, '--all', '--exclude', '!**/node_modules/**', process.execPath, './half-covered.js'] + + const proc = spawn(process.execPath, args, { + cwd: fixturesCLI, + env: env + }) + + let stdout = '' + proc.stdout.on('data', chunk => { + stdout += chunk + }) + + proc.on('close', code => { + code.should.equal(0) + stdout.should.match(/include-exclude\/node_modules/) + stdout.should.match(/cover-me\.js/) + done() + }) + }) }) describe('--ignore-class-method', function () {