#!/usr/bin/env node import figlet from 'figlet'; import arg from 'arg'; import { getCommandAbsolutePaths } from './utils/command'; import path from 'path'; import chalk from 'chalk'; import { CommandOptions } from './command-types'; const introMessage = figlet.textSync('AuditBoard', { font: 'Slant', horizontalLayout: 'default', verticalLayout: 'default', }); console.log(introMessage); function parseArgs(rawArgs: string[], commandOptions: CommandOptions) { // @ts-ignore const args = arg(commandOptions.args, { argv: rawArgs.slice(3) }); // loop through args._ and extract non '--' things const result: Record = {}; const failures: string[] = []; let index = 0; // if there are required parameters if (commandOptions.required && commandOptions.required.length) { // if there is no params provided and there are non required if (!args._.length && commandOptions.required && !commandOptions.required.length) { failures.push(...commandOptions.required.map(r => r.message || '')); } for (const key of Object.keys(commandOptions.required)) { // if there are required params but aren't provided if (!args._[index] && commandOptions.required[index]) { failures.push(commandOptions.required[index].message || `Require parameter missing: ${commandOptions.required[index].name}`); } result[commandOptions.required[index].name] = args._[index]; index++; } } // parse optional args for (const key of Object.keys(args)) { if (key.startsWith('--')) { result[key.replace('--', '')] = (args as unknown as Record)[key]; } } // throw errors if (failures.length) { console.log(chalk.red(`There were ${failures.length} error${failures.length === 1 ? '' : 's'} while running your command...`)); for (let i = 0; i < failures.length ; i++) { console.log(chalk.black.bgWhite.bold(`${i+1})`), chalk.red(failures[i])); } process.exit(1); } return result; } function parseCommand(commandString: string) { const commandPaths = getCommandAbsolutePaths(); for (const item of commandPaths) { const commandName = path.basename(item).replace(/\_/g, ':').replace('.ts', '').replace('.js', ''); const moduleName = path.normalize(item).replace('.ts', '').replace('.js', ''); if (commandString === commandName) { // found the command return import(moduleName); } } console.log(chalk.red("Error: command ") + chalk.bold(commandString) + chalk.red(" not found.")); process.exit(1); } async function cli(rawArgs: string[]) { let inputCommandString = rawArgs[2]; if (!inputCommandString) { inputCommandString = 'list'; } const rawCommandOutput = await parseCommand(inputCommandString); const { command, commandOptions } = rawCommandOutput.default ? rawCommandOutput.default : rawCommandOutput; const options = parseArgs(rawArgs, commandOptions); try { let successMessage = await command(options); // if not list or test then we want to log something if (!['test', 'list', 'help'].includes(inputCommandString)) { // default message successMessage = successMessage || `Your command ${inputCommandString} ran successfully!`; console.log(chalk.green(successMessage)); } } catch (err) { // do something else with error handling console.error(err); process.exit(1); } }; (async () => { try { await cli(process.argv); // explicitly exit the process once the buffer has been completely flushed process.stdout.write('', () => process.exit(0)); } catch (err) { console.error(err); process.exit(1); } })();