aboutsummaryrefslogtreecommitdiff
path: root/node_modules/ava/lib/ava-files.js
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-05-28 00:38:50 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-05-28 00:40:43 +0200
commit7fff4499fd915bcea3fa93b1aa8b35f4fe7a6027 (patch)
tree6de9a1aebd150a23b7f8c273ec657a5d0a18fe3e /node_modules/ava/lib/ava-files.js
parent963b7a41feb29cc4be090a2446bdfe0c1f1bcd81 (diff)
add linting (and some initial fixes)
Diffstat (limited to 'node_modules/ava/lib/ava-files.js')
-rw-r--r--node_modules/ava/lib/ava-files.js282
1 files changed, 282 insertions, 0 deletions
diff --git a/node_modules/ava/lib/ava-files.js b/node_modules/ava/lib/ava-files.js
new file mode 100644
index 000000000..dd9a2ee6d
--- /dev/null
+++ b/node_modules/ava/lib/ava-files.js
@@ -0,0 +1,282 @@
+'use strict';
+const fs = require('fs');
+const path = require('path');
+const Promise = require('bluebird');
+const slash = require('slash');
+const globby = require('globby');
+const flatten = require('lodash.flatten');
+const autoBind = require('auto-bind');
+const defaultIgnore = require('ignore-by-default').directories();
+const multimatch = require('multimatch');
+
+function handlePaths(files, excludePatterns, globOptions) {
+ // Convert Promise to Bluebird
+ files = Promise.resolve(globby(files.concat(excludePatterns), globOptions));
+
+ const searchedParents = new Set();
+ const foundFiles = new Set();
+
+ function alreadySearchingParent(dir) {
+ if (searchedParents.has(dir)) {
+ return true;
+ }
+
+ const parentDir = path.dirname(dir);
+
+ if (parentDir === dir) {
+ // We have reached the root path
+ return false;
+ }
+
+ return alreadySearchingParent(parentDir);
+ }
+
+ return files
+ .map(file => {
+ file = path.resolve(globOptions.cwd, file);
+
+ if (fs.statSync(file).isDirectory()) {
+ if (alreadySearchingParent(file)) {
+ return null;
+ }
+
+ searchedParents.add(file);
+
+ let pattern = path.join(file, '**', '*.js');
+
+ if (process.platform === 'win32') {
+ // Always use `/` in patterns, harmonizing matching across platforms
+ pattern = slash(pattern);
+ }
+
+ return handlePaths([pattern], excludePatterns, globOptions);
+ }
+
+ // `globby` returns slashes even on Windows. Normalize here so the file
+ // paths are consistently platform-accurate as tests are run.
+ return path.normalize(file);
+ })
+ .then(flatten)
+ .filter(file => file && path.extname(file) === '.js')
+ .filter(file => {
+ if (path.basename(file)[0] === '_' && globOptions.includeUnderscoredFiles !== true) {
+ return false;
+ }
+
+ return true;
+ })
+ .map(file => path.resolve(file))
+ .filter(file => {
+ const alreadyFound = foundFiles.has(file);
+ foundFiles.add(file);
+ return !alreadyFound;
+ });
+}
+
+const defaultExcludePatterns = () => [
+ '!**/node_modules/**',
+ '!**/fixtures/**',
+ '!**/helpers/**'
+];
+
+const defaultIncludePatterns = () => [
+ 'test.js',
+ 'test-*.js',
+ 'test',
+ '**/__tests__',
+ '**/*.test.js'
+];
+
+const defaultHelperPatterns = () => [
+ '**/__tests__/helpers/**/*.js',
+ '**/__tests__/**/_*.js',
+ '**/test/helpers/**/*.js',
+ '**/test/**/_*.js'
+];
+
+const getDefaultIgnorePatterns = () => defaultIgnore.map(dir => `${dir}/**/*`);
+
+// Used on paths before they're passed to multimatch to harmonize matching
+// across platforms
+const matchable = process.platform === 'win32' ? slash : (path => path);
+
+class AvaFiles {
+ constructor(options) {
+ options = options || {};
+
+ let files = (options.files || []).map(file => {
+ // `./` should be removed from the beginning of patterns because
+ // otherwise they won't match change events from Chokidar
+ if (file.slice(0, 2) === './') {
+ return file.slice(2);
+ }
+
+ return file;
+ });
+
+ if (files.length === 0) {
+ files = defaultIncludePatterns();
+ }
+
+ this.excludePatterns = defaultExcludePatterns();
+ this.files = files;
+ this.sources = options.sources || [];
+ this.cwd = options.cwd || process.cwd();
+
+ autoBind(this);
+ }
+ findTestFiles() {
+ return handlePaths(this.files, this.excludePatterns, {
+ cwd: this.cwd,
+ cache: Object.create(null),
+ statCache: Object.create(null),
+ realpathCache: Object.create(null),
+ symlinks: Object.create(null)
+ });
+ }
+ findTestHelpers() {
+ return handlePaths(defaultHelperPatterns(), ['!**/node_modules/**'], {
+ cwd: this.cwd,
+ includeUnderscoredFiles: true,
+ cache: Object.create(null),
+ statCache: Object.create(null),
+ realpathCache: Object.create(null),
+ symlinks: Object.create(null)
+ });
+ }
+ isSource(filePath) {
+ let mixedPatterns = [];
+ const defaultIgnorePatterns = getDefaultIgnorePatterns();
+ const overrideDefaultIgnorePatterns = [];
+
+ let hasPositivePattern = false;
+ this.sources.forEach(pattern => {
+ mixedPatterns.push(pattern);
+
+ // TODO: Why not just `pattern[0] !== '!'`?
+ if (!hasPositivePattern && pattern[0] !== '!') {
+ hasPositivePattern = true;
+ }
+
+ // Extract patterns that start with an ignored directory. These need to be
+ // rematched separately.
+ if (defaultIgnore.indexOf(pattern.split('/')[0]) >= 0) {
+ overrideDefaultIgnorePatterns.push(pattern);
+ }
+ });
+
+ // Same defaults as used for Chokidar
+ if (!hasPositivePattern) {
+ mixedPatterns = ['package.json', '**/*.js'].concat(mixedPatterns);
+ }
+
+ filePath = matchable(filePath);
+
+ // Ignore paths outside the current working directory.
+ // They can't be matched to a pattern.
+ if (/^\.\.\//.test(filePath)) {
+ return false;
+ }
+
+ const isSource = multimatch(filePath, mixedPatterns).length === 1;
+ if (!isSource) {
+ return false;
+ }
+
+ const isIgnored = multimatch(filePath, defaultIgnorePatterns).length === 1;
+ if (!isIgnored) {
+ return true;
+ }
+
+ const isErroneouslyIgnored = multimatch(filePath, overrideDefaultIgnorePatterns).length === 1;
+ if (isErroneouslyIgnored) {
+ return true;
+ }
+
+ return false;
+ }
+ isTest(filePath) {
+ const excludePatterns = this.excludePatterns;
+ const initialPatterns = this.files.concat(excludePatterns);
+
+ // Like in `api.js`, tests must be `.js` files and not start with `_`
+ if (path.extname(filePath) !== '.js' || path.basename(filePath)[0] === '_') {
+ return false;
+ }
+
+ // Check if the entire path matches a pattern
+ if (multimatch(matchable(filePath), initialPatterns).length === 1) {
+ return true;
+ }
+
+ // Check if the path contains any directory components
+ const dirname = path.dirname(filePath);
+ if (dirname === '.') {
+ return false;
+ }
+
+ // Compute all possible subpaths. Note that the dirname is assumed to be
+ // relative to the working directory, without a leading `./`.
+ const subpaths = dirname.split(/[\\/]/).reduce((subpaths, component) => {
+ const parent = subpaths[subpaths.length - 1];
+
+ if (parent) {
+ // Always use `/`` to makes multimatch consistent across platforms
+ subpaths.push(`${parent}/${component}`);
+ } else {
+ subpaths.push(component);
+ }
+
+ return subpaths;
+ }, []);
+
+ // Check if any of the possible subpaths match a pattern. If so, generate a
+ // new pattern with **/*.js.
+ const recursivePatterns = subpaths
+ .filter(subpath => multimatch(subpath, initialPatterns).length === 1)
+ // Always use `/` to makes multimatch consistent across platforms
+ .map(subpath => `${subpath}/**/*.js`);
+
+ // See if the entire path matches any of the subpaths patterns, taking the
+ // excludePatterns into account. This mimicks the behavior in api.js
+ return multimatch(matchable(filePath), recursivePatterns.concat(excludePatterns)).length === 1;
+ }
+ getChokidarPatterns() {
+ let paths = [];
+ let ignored = [];
+
+ this.sources.forEach(pattern => {
+ if (pattern[0] === '!') {
+ ignored.push(pattern.slice(1));
+ } else {
+ paths.push(pattern);
+ }
+ });
+
+ // Allow source patterns to override the default ignore patterns. Chokidar
+ // ignores paths that match the list of ignored patterns. It uses anymatch
+ // under the hood, which supports negation patterns. For any source pattern
+ // that starts with an ignored directory, ensure the corresponding negation
+ // pattern is added to the ignored paths.
+ const overrideDefaultIgnorePatterns = paths
+ .filter(pattern => defaultIgnore.indexOf(pattern.split('/')[0]) >= 0)
+ .map(pattern => `!${pattern}`);
+
+ ignored = getDefaultIgnorePatterns().concat(ignored, overrideDefaultIgnorePatterns);
+
+ if (paths.length === 0) {
+ paths = ['package.json', '**/*.js'];
+ }
+
+ paths = paths.concat(this.files);
+
+ return {
+ paths,
+ ignored
+ };
+ }
+}
+
+module.exports = AvaFiles;
+module.exports.defaultIncludePatterns = defaultIncludePatterns;
+module.exports.defaultExcludePatterns = defaultExcludePatterns;