🌳
pt0/deployF/cliF/cliBaseF.mts
1import * as _ from 'lodash-es'
8import { cliSchemaFlags, cliFlag, type CliSchema } from '../../serverF/cliArgAI.mts'
9import { tsAbsPath } from '../../ptDirF.mts'
15type ScopesInfo = {scopeCmds: string[], examplePath?: string}
17const appendSchemaFlags = (description: string, cliSchema: CliSchema) => {
18 const flags = cliSchemaFlags(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}`)
29 }
30 if (getExtraHelpLines) lines.push(...getExtraHelpLines())
31 return lines.join('\n') + '\n'
34export const cliBase = ({
35 actionNames,
36 actionsH = {},
37 scopesInfo,
38 buildScopeCmdHelpFnc,
39 builtinActions = {},
40 getExtraHelpLines,
41 scriptName,
42 exampleName,
43}: {
44 actionNames: string[]
45 actionsH?: ActionsH
46 scopesInfo?: ScopesInfo
47 buildScopeCmdHelpFnc?: (opts: {actionName: string, cliDescript?: string | Record<string, unknown>, scriptPath: string}) => string
48 builtinActions?: ActionsH
49 getExtraHelpLines?: () => string[]
50 scriptName?: string
51 exampleName?: string
52}) => {
53 if (exampleName) captureSaveExampleMeta({name: exampleName})
54 const scriptPath = scriptName || absPathToPtPath(tsAbsPath(getProcArgv()[1]))
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 })
69 })
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) {
77 const scopeVals = getEpScopeOptA().join('|')
78 lines.push(`\ncan filter by --${epScopeKey}=${scopeVals}:`)
79 inScopeSection = true
80 }
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}`)
84 }
85 if (getExtraHelpLines) lines.push(...getExtraHelpLines())
86 return lines.join('\n') + '\n'
87 }
89 const action = getDefaultAction()
91 // Check unknown args before any early exits (including help)
92 const unknownArgs = getUnknownArgs(actionsH[action])
93 if (unknownArgs.length) {
94 console.error(`${unknownArgsPrefix} ${unknownArgs.join(', ')}`)
95 if (commands.has(action)) {
96 console.log(commands.get(action).helpFnc())
97 } else {
98 console.log(buildHelp())
99 }
100 process.exit(1)
101 }
103 if (cliFlag('--help', '-h')) {
104 if (commands.has(action)) {
105 console.log(commands.get(action).helpFnc())
106 process.exit(0)
107 }
108 console.log(buildHelp())
109 process.exit(0)
110 }
112 const helpIdx = getProcArgv().indexOf('help')
113 if (helpIdx !== -1 && getProcArgv()[helpIdx + 1]) {
114 const targetAction = getProcArgv()[helpIdx + 1]
115 if (commands.has(targetAction)) {
116 console.log(commands.get(targetAction).helpFnc())
117 process.exit(0)
118 }
119 }
121 if (action === 'help') {
122 console.log(buildHelp())
123 process.exit(0)
124 }
126 if (!commands.has(action)) {
127 console.error(`error: unknown command '${action}'`)
128 console.log(buildHelp())
129 process.exit(1)
130 }
132 return { action, commands }