UNPKG

ava

Version:

Node.js test runner that lets you develop with confidence.

120 lines (96 loc) 3.38 kB
import path from 'node:path'; import process from 'node:process'; import ignoreByDefault from 'ignore-by-default'; import picomatch from 'picomatch'; import slash from 'slash'; const defaultIgnorePatterns = [...ignoreByDefault.directories(), '**/node_modules']; export {defaultIgnorePatterns}; const defaultPicomatchIgnorePatterns = [ ...defaultIgnorePatterns, // Unlike globby(), picomatch needs a complete pattern when ignoring directories. ...defaultIgnorePatterns.map(pattern => `${pattern}/**/*`), ]; const matchingCache = new WeakMap(); const processMatchingPatterns = input => { let result = matchingCache.get(input); if (!result) { const ignore = [...defaultPicomatchIgnorePatterns]; const patterns = input.filter(pattern => { if (pattern.startsWith('!')) { // Unlike globby(), picomatch needs a complete pattern when ignoring directories. ignore.push(pattern.slice(1), `${pattern.slice(1)}/**/*`); return false; } return true; }); result = { match: picomatch(patterns, {ignore}), matchNoIgnore: picomatch(patterns), individualMatchers: patterns.map(pattern => ({pattern, match: picomatch(pattern, {ignore})})), }; matchingCache.set(input, result); } return result; }; export {processMatchingPatterns}; export function classify(file, {cwd, extensions, filePatterns}) { file = normalizeFileForMatching(cwd, file); return { isTest: hasExtension(extensions, file) && !isHelperish(file) && filePatterns.length > 0 && matches(file, filePatterns), }; } export function hasExtension(extensions, file) { return extensions.includes(path.extname(file).slice(1)); } export function isHelperish(file) { // Assume file has been normalized already. // File names starting with an underscore are deemed "helpers". if (path.basename(file).startsWith('_')) { return true; } // This function assumes the file has been normalized. If it couldn't be, // don't check if it's got a parent directory that starts with an underscore. // Deem it not a "helper". if (path.isAbsolute(file)) { return false; } // If the file has a parent directory that starts with only a single // underscore, it's deemed a "helper". return path.dirname(file).split('/').some(dir => /^_(?:$|[^_])/.test(dir)); } export function matches(file, patterns) { const {match} = processMatchingPatterns(patterns); return match(file); } export function normalizeFileForMatching(cwd, file) { if (process.platform === 'win32') { cwd = slash(cwd); file = slash(file); } // Note that if `file` is outside `cwd` we can't normalize it. If this turns // out to be a real-world scenario we may have to make changes in calling code // to make sure the file isn't even selected for matching. if (!file.startsWith(cwd)) { return file; } // Assume `cwd` does *not* end in a slash. return file.slice(cwd.length + 1); } export function normalizePattern(pattern) { // Always use `/` in patterns, harmonizing matching across platforms if (process.platform === 'win32') { pattern = slash(pattern); } if (pattern.endsWith('/')) { pattern = pattern.slice(0, -1); } if (pattern.startsWith('./')) { return pattern.slice(2); } if (pattern.startsWith('!./')) { return `!${pattern.slice(3)}`; } return pattern; } export function normalizePatterns(patterns) { return patterns.map(pattern => normalizePattern(pattern)); }