1// Common utilities for interacting with `args` library. 2// These functions should be used by every command. 3import arg from 'arg'; 4import chalk from 'chalk'; 5import { existsSync } from 'fs'; 6import { resolve } from 'path'; 7 8import * as Log from '../log'; 9 10/** 11 * Parse the first argument as a project directory. 12 * 13 * @returns valid project directory. 14 */ 15export function getProjectRoot(args: arg.Result<arg.Spec>) { 16 const projectRoot = resolve(args._[0] || '.'); 17 18 if (!existsSync(projectRoot)) { 19 Log.exit(`Invalid project root: ${projectRoot}`); 20 } 21 22 return projectRoot; 23} 24 25/** 26 * Parse args and assert unknown options. 27 * 28 * @param schema the `args` schema for parsing the command line arguments. 29 * @param argv extra strings 30 * @returns processed args object. 31 */ 32export function assertArgs(schema: arg.Spec, argv?: string[]): arg.Result<arg.Spec> { 33 return assertWithOptionsArgs(schema, { argv }); 34} 35 36export function assertWithOptionsArgs( 37 schema: arg.Spec, 38 options: arg.Options 39): arg.Result<arg.Spec> { 40 try { 41 return arg(schema, options); 42 } catch (error: any) { 43 // Ensure unknown options are handled the same way. 44 if (error.code === 'ARG_UNKNOWN_OPTION') { 45 Log.exit(error.message, 1); 46 } 47 // Otherwise rethrow the error. 48 throw error; 49 } 50} 51 52export function printHelp(info: string, usage: string, options: string, extra: string = ''): never { 53 Log.exit( 54 chalk` 55 {bold Info} 56 ${info} 57 58 {bold Usage} 59 {dim $} ${usage} 60 61 {bold Options} 62 ${options.split('\n').join('\n ')} 63` + extra, 64 0 65 ); 66} 67