UNPKG

ts-node-test

Version:

Use the Node.js test runner, but with TypeScript via ts-node

52 lines (51 loc) 2.23 kB
import { join } from 'node:path'; import { readdir } from 'node:fs/promises'; /** * Resolve a given set of (user-provided) input paths to explicit file names. * * Paths referring to singular files will be returned as-is, while paths referring to directories will be recursed into * and the list of all deeply nested files will be returned. * * The resulting list will be filtered to only contain supported file extensions. * * @param paths The input paths. * @param extensions The supported file extensions. * @param readDirectory A function which can return the names of the files and folders in a directory (excluding '.' and '..') * @returns An array containing all (matching and non-directory) file names explicitly. */ export async function resolveTestPaths(paths, extensions, readDirectory) { const resolvedPaths = []; for (const inputPath of paths) { resolvedPaths.push(...await walkPath(inputPath, (fileName) => extensions.some((extension) => fileName.endsWith(extension)), readDirectory ?? readdir)); } return resolvedPaths; } export async function walkPath(path, predicate, readDirectory) { const found = []; const stack = [path]; // Walk stack depth-first (in tree order) while (stack.length > 0) { const [item] = stack.splice(0, 1); try { // If item can be successfully read as a directory, we add its files to the top-of-stack. const dirFileNames = await readDirectory(item); stack.unshift(...dirFileNames.filter((fileName) => fileName !== 'node_modules').map((fileName) => join(item, fileName))); } catch (err) { if (isNodeError(err) && err.code === 'ENOTDIR') { // item seems to refer to a file instead of a directory. // We want to return it only if it was provided explicitly by the user, or it matches the predicate. if (item === path || predicate(item)) { found.push(item); } continue; } throw err; } } return found; } // TS type guard function isNodeError(err) { return typeof err === 'object' && err != null && 'code' in err; }