UNPKG

yargs-file-commands

Version:

A yargs helper function that lets you define your commands structure via directory and file naming conventions.

110 lines (98 loc) 3.14 kB
import { readdir, stat } from 'fs/promises'; import path, { join } from 'path'; /** * Options for directory scanning * @interface ScanDirectoryOptions */ export interface ScanDirectoryOptions { /** File extensions to consider when scanning for command files */ extensions?: string[]; /** Regular expressions for patterns to ignore when scanning directories */ ignorePatterns?: RegExp[]; /** Logging verbosity level */ logLevel?: 'info' | 'debug'; /** Prefix for log messages */ logPrefix?: string; } /** * Recursively scans a directory for command files * @async * @param {string} dirPath - The directory path to scan * @param {ScanDirectoryOptions} options - Scanning configuration options * @returns {Promise<string[]>} Array of full paths to command files * * @description * Performs a recursive directory scan, filtering files based on: * - Ignore patterns (skips matching files/directories) * - File extensions (only includes matching files) * The scan is performed in parallel for better performance. */ export const scanDirectory = async ( dirPath: string, commandDir: string, options: ScanDirectoryOptions = {} ): Promise<string[]> => { const { ignorePatterns = [], extensions = ['.js', '.ts'], logLevel = 'info', logPrefix = '' } = options; try { const entries = await readdir(dirPath); const commandPaths: string[] = []; for (const entry of entries) { const fullPath = join(dirPath, entry); const localPath = fullPath.replace(commandDir, ''); // apply ignore pattern and early return if matched const shouldIgnore = ignorePatterns.some((pattern) => pattern.test(localPath) ); if (shouldIgnore) { if (logLevel === 'debug') { console.debug( `${logPrefix}${localPath} - ignoring because it matches ignorePattern: ${ignorePatterns .filter((pattern) => pattern.test(localPath)) .join(', ')}` ); } continue; } const stats = await stat(fullPath); if (stats.isDirectory()) { if (logLevel === 'debug') { console.debug( `${logPrefix}${localPath} - directory, scanning for commands:` ); } commandPaths.push( ...(await scanDirectory(fullPath, commandDir, { ...options, logPrefix: `${logPrefix} ` })) ); continue; } const extension = path.extname(fullPath); if (!extensions.includes(extension)) { if (logLevel === 'debug') { console.debug( `${logPrefix}${localPath} - ignoring as its extension, ${extension}, doesn't match required extension: ${extensions.join( ', ' )}` ); } continue; } if (logLevel === 'debug') { console.debug(`${logPrefix}${localPath} - possible command file`); } commandPaths.push(fullPath); } return commandPaths; } catch (error) { throw new Error( `${logPrefix}Failed to scan directory ${dirPath}: ${error}` ); } };