1import * as _ from 'lodash-es' 15type ScopesInfo = {scopeCmds: string[], examplePath?: string} 17const appendSchemaFlags = (description: string, cliSchema: CliSchema) => { 19 return description ? `${description} ${flags}` : flags 22export const buildHelpStr = ({scriptName, actionsH, getExtraHelpLines}: {scriptName: string, actionsH: ActionsH, getExtraHelpLines?: () => string[]}) => { 23 const lines = [`$ ${scriptName} help\n`, '[action]s:'] 24 for (const [name, cfg] of Object.entries(actionsH)) { 25 let description = typeof cfg === 'string' ? cfg : String(formatCliDescript(cfg?.cliDescript, name, undefined) || '') 26 if (cfg?.cliSchema) description = appendSchemaFlags(description, cfg.cliSchema) 27 const padding = ' '.repeat(Math.max(1, 14 - name.length)) 28 lines.push(` ${name}${padding}${description}`) 30 if (getExtraHelpLines) lines.push(...getExtraHelpLines()) 31 return lines.join('\n') + '\n' 34export const cliBase = ({ 46 scopesInfo?: ScopesInfo 47 buildScopeCmdHelpFnc?: (opts: {actionName: string, cliDescript?: string | Record<string, unknown>, scriptPath: string}) => string 49 getExtraHelpLines?: () => string[] 55 const scopeCmdSet = new Set(scopesInfo?.scopeCmds || []) 57 const commands = new Map() 58 _.each(actionNames, (actionName) => { 59 const fnc = { ...actionsH, ...builtinActions }[actionName] 60 const { cliDescript, cliSchema } = fnc || {} 61 let description = String(formatCliDescript(cliDescript, actionName, scopesInfo?.examplePath) || '') 62 if (cliSchema) description = appendSchemaFlags(description, cliSchema) 64 const helpFnc = (scopeCmdSet.has(actionName) && buildScopeCmdHelpFnc) 65 ? () => buildScopeCmdHelpFnc({ actionName, cliDescript, scriptPath }) 66 : () => description ? `${description}\n` : '' 68 commands.set(actionName, { description, helpFnc }) 71 const buildHelp = () => { 72 const cmdPrefix = scriptName || `${ptnodeBin} ${scriptPath}` 73 const lines = [`$ ${cmdPrefix} help\n`, '[action]s:'] 74 let inScopeSection = false 75 for (const [name, { description }] of commands) { 76 if (scopesInfo && scopesInfo.scopeCmds[0] === name && !inScopeSection) { 78 lines.push(`\ncan filter by --${epScopeKey}=${scopeVals}:`) 81 const padding = ' '.repeat(Math.max(1, 14 - name.length)) 82 const desc = inScopeSection ? description.replace(new RegExp(`\\s*\\[--${epScopeKey}=<[^>]*>\\]`), '') : description 83 lines.push(` ${name}${padding}${desc}`) 85 if (getExtraHelpLines) lines.push(...getExtraHelpLines()) 86 return lines.join('\n') + '\n' 91 // Check unknown args before any early exits (including help) 93 if (unknownArgs.length) { 95 if (commands.has(action)) { 96 console.log(commands.get(action).helpFnc()) 98 console.log(buildHelp()) 104 if (commands.has(action)) { 105 console.log(commands.get(action).helpFnc()) 108 console.log(buildHelp()) 115 if (commands.has(targetAction)) { 116 console.log(commands.get(targetAction).helpFnc()) 121 if (action === 'help') { 122 console.log(buildHelp()) 126 if (!commands.has(action)) { 127 console.error(`error: unknown command '${action}'`) 128 console.log(buildHelp()) 132 return { action, commands }