UNPKG

@thi.ng/args

Version:

Declarative, functional & typechecked CLI argument/options parser, value coercions etc.

75 lines (74 loc) 2.1 kB
import { illegalArgs } from "@thi.ng/errors/illegal-arguments"; import { StreamLogger } from "@thi.ng/logger/stream"; import { padRight } from "@thi.ng/strings/pad-right"; import { PRESET_ANSI16, PRESET_NONE } from "@thi.ng/text-format/presets"; import { parse } from "./parse.js"; import { usage } from "./usage.js"; const cliApp = async (config) => { const argv = config.argv || process.argv; const isColor = !process.env.NO_COLOR; const usageOpts = { prefix: "", color: isColor, ...config.usage }; try { let cmdID; let cmd; let start = config.start ?? 2; if (config.single) { cmdID = Object.keys(config.commands)[0]; if (!cmdID) illegalArgs("no command provided"); cmd = config.commands[cmdID]; } else { cmdID = argv[start]; cmd = config.commands[cmdID]; usageOpts.prefix += __descriptions(config.commands); if (!cmd) __usageAndExit(config, usageOpts); start++; } let parsed; try { parsed = parse({ ...config.opts, ...cmd.opts }, argv, { showUsage: true, usageOpts, start }); } catch (_) { } if (!parsed) process.exit(1); if (cmd.inputs !== void 0 && cmd.inputs !== parsed.rest.length) { process.stderr.write(`expected ${cmd.inputs || 0} input(s) `); __usageAndExit(config, usageOpts); } const ctx = await config.ctx( { logger: new StreamLogger(process.stderr, config.name, "INFO"), format: isColor ? PRESET_ANSI16 : PRESET_NONE, opts: parsed.result, inputs: parsed.rest }, cmd ); await cmd.fn(ctx); if (config.post) await config.post(ctx, cmd); } catch (e) { process.stderr.write(e.message + "\n\n"); process.exit(1); } }; const __usageAndExit = (config, usageOpts) => { process.stderr.write(usage(config.opts, usageOpts)); process.exit(1); }; const __descriptions = (commands) => [ "\nAvailable commands:\n", ...Object.keys(commands).map( (x) => `${padRight(16)(x)}: ${commands[x].desc}` ), "\n" ].join("\n"); export { cliApp };