aboutsummaryrefslogtreecommitdiff
path: root/node_modules/test-exclude/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/test-exclude/index.js')
-rw-r--r--node_modules/test-exclude/index.js161
1 files changed, 161 insertions, 0 deletions
diff --git a/node_modules/test-exclude/index.js b/node_modules/test-exclude/index.js
new file mode 100644
index 0000000..aecb72d
--- /dev/null
+++ b/node_modules/test-exclude/index.js
@@ -0,0 +1,161 @@
+'use strict';
+
+const path = require('path');
+const { promisify } = require('util');
+const glob = promisify(require('glob'));
+const minimatch = require('minimatch');
+const { defaults } = require('@istanbuljs/schema');
+const isOutsideDir = require('./is-outside-dir');
+
+class TestExclude {
+ constructor(opts = {}) {
+ Object.assign(
+ this,
+ {relativePath: true},
+ defaults.testExclude
+ );
+
+ for (const [name, value] of Object.entries(opts)) {
+ if (value !== undefined) {
+ this[name] = value;
+ }
+ }
+
+ if (typeof this.include === 'string') {
+ this.include = [this.include];
+ }
+
+ if (typeof this.exclude === 'string') {
+ this.exclude = [this.exclude];
+ }
+
+ if (typeof this.extension === 'string') {
+ this.extension = [this.extension];
+ } else if (this.extension.length === 0) {
+ this.extension = false;
+ }
+
+ if (this.include && this.include.length > 0) {
+ this.include = prepGlobPatterns([].concat(this.include));
+ } else {
+ this.include = false;
+ }
+
+ if (
+ this.excludeNodeModules &&
+ !this.exclude.includes('**/node_modules/**')
+ ) {
+ this.exclude = this.exclude.concat('**/node_modules/**');
+ }
+
+ this.exclude = prepGlobPatterns([].concat(this.exclude));
+
+ this.handleNegation();
+ }
+
+ /* handle the special case of negative globs
+ * (!**foo/bar); we create a new this.excludeNegated set
+ * of rules, which is applied after excludes and we
+ * move excluded include rules into this.excludes.
+ */
+ handleNegation() {
+ const noNeg = e => e.charAt(0) !== '!';
+ const onlyNeg = e => e.charAt(0) === '!';
+ const stripNeg = e => e.slice(1);
+
+ if (Array.isArray(this.include)) {
+ const includeNegated = this.include.filter(onlyNeg).map(stripNeg);
+ this.exclude.push(...prepGlobPatterns(includeNegated));
+ this.include = this.include.filter(noNeg);
+ }
+
+ this.excludeNegated = this.exclude.filter(onlyNeg).map(stripNeg);
+ this.exclude = this.exclude.filter(noNeg);
+ this.excludeNegated = prepGlobPatterns(this.excludeNegated);
+ }
+
+ shouldInstrument(filename, relFile) {
+ if (
+ this.extension &&
+ !this.extension.some(ext => filename.endsWith(ext))
+ ) {
+ return false;
+ }
+
+ let pathToCheck = filename;
+
+ if (this.relativePath) {
+ relFile = relFile || path.relative(this.cwd, filename);
+
+ // Don't instrument files that are outside of the current working directory.
+ if (isOutsideDir(this.cwd, filename)) {
+ return false;
+ }
+
+ pathToCheck = relFile.replace(/^\.[\\/]/, ''); // remove leading './' or '.\'.
+ }
+
+ const dot = { dot: true };
+ const matches = pattern => minimatch(pathToCheck, pattern, dot);
+ return (
+ (!this.include || this.include.some(matches)) &&
+ (!this.exclude.some(matches) || this.excludeNegated.some(matches))
+ );
+ }
+
+ globSync(cwd = this.cwd) {
+ const globPatterns = getExtensionPattern(this.extension || []);
+ const globOptions = { cwd, nodir: true, dot: true };
+ /* If we don't have any excludeNegated then we can optimize glob by telling
+ * it to not iterate into unwanted directory trees (like node_modules). */
+ if (this.excludeNegated.length === 0) {
+ globOptions.ignore = this.exclude;
+ }
+
+ return glob
+ .sync(globPatterns, globOptions)
+ .filter(file => this.shouldInstrument(path.resolve(cwd, file)));
+ }
+
+ async glob(cwd = this.cwd) {
+ const globPatterns = getExtensionPattern(this.extension || []);
+ const globOptions = { cwd, nodir: true, dot: true };
+ /* If we don't have any excludeNegated then we can optimize glob by telling
+ * it to not iterate into unwanted directory trees (like node_modules). */
+ if (this.excludeNegated.length === 0) {
+ globOptions.ignore = this.exclude;
+ }
+
+ const list = await glob(globPatterns, globOptions);
+ return list.filter(file => this.shouldInstrument(path.resolve(cwd, file)));
+ }
+}
+
+function prepGlobPatterns(patterns) {
+ return patterns.reduce((result, pattern) => {
+ // Allow gitignore style of directory exclusion
+ if (!/\/\*\*$/.test(pattern)) {
+ result = result.concat(pattern.replace(/\/$/, '') + '/**');
+ }
+
+ // Any rules of the form **/foo.js, should also match foo.js.
+ if (/^\*\*\//.test(pattern)) {
+ result = result.concat(pattern.replace(/^\*\*\//, ''));
+ }
+
+ return result.concat(pattern);
+ }, []);
+}
+
+function getExtensionPattern(extension) {
+ switch (extension.length) {
+ case 0:
+ return '**';
+ case 1:
+ return `**/*${extension[0]}`;
+ default:
+ return `**/*{${extension.join()}}`;
+ }
+}
+
+module.exports = TestExclude;