UNPKG

@catladder/cli

Version:

Panter cli tool for cloud CI/CD and DevOps

205 lines (204 loc) • 6.66 kB
"use strict"; var __createBinding = this && this.__createBinding || (Object.create ? function (o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function () { return m[k]; } }; } Object.defineProperty(o, k2, desc); } : function (o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; }); var __setModuleDefault = this && this.__setModuleDefault || (Object.create ? function (o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); } : function (o, v) { o["default"] = v; }); var __importStar = this && this.__importStar || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createTerminalIO = exports.createTerminalContext = void 0; const types_1 = require("../core/types"); const baseContext_1 = require("./baseContext"); /** * Resolve choices from a choices function. */ async function resolveChoices(choices, ctx) { const raw = await choices(ctx); return raw.map(c => typeof c === "string" ? { name: c, value: c } : c); } /** * Prompt the user interactively using @inquirer/prompts. * The UI is determined by the value type + presence of choices. */ async function promptInteractive(spec, ctx) { const inquirer = await Promise.resolve().then(() => __importStar(require("@inquirer/prompts"))); switch (spec.type) { case "string": { if (spec.choices) { const choices = await resolveChoices(spec.choices, ctx); return inquirer.select({ message: spec.message, choices }); } return inquirer.input({ message: spec.message, default: spec.default }); } case "string[]": { if (spec.choices) { const choices = await resolveChoices(spec.choices, ctx); return inquirer.checkbox({ message: spec.message, choices }); } const raw = await inquirer.input({ message: spec.message }); return raw ? raw.split(",").map(s => s.trim()) : []; } case "number": return inquirer.number({ message: spec.message, default: spec.default }); case "boolean": return inquirer.confirm({ message: spec.message, default: spec.default }); default: throw new Error(`Unsupported input type: ${spec.type}`); } } class TerminalContext extends baseContext_1.BaseContext { constructor(command, options) { super(command); this.options = options; } log(message) { console.log(message); } async confirm(message) { var _a; if (this.options.yes) return true; const isInteractive = (_a = this.options.interactive) !== null && _a !== void 0 ? _a : process.stdin.isTTY === true; if (!isInteractive) return true; const inquirer = await Promise.resolve().then(() => __importStar(require("@inquirer/prompts"))); return inquirer.confirm({ message }); } async resolveInput(name, spec) { const { cliOptions = {}, jsonInputs = {}, interactive } = this.options; const isInteractive = interactive !== null && interactive !== void 0 ? interactive : process.stdin.isTTY === true; // Helper: validate a pre-supplied value against choices if they exist const validateAgainstChoices = async value => { if (!("choices" in spec) || !spec.choices) return; const choices = await resolveChoices(spec.choices, this); const validValues = choices.map(c => c.value); if (Array.isArray(value)) { const invalid = value.filter(v => !validValues.includes(v)); if (invalid.length > 0) { throw new Error(`Invalid value(s) for "${name}": ${invalid.join(", ")}. Valid choices: ${validValues.join(", ")}`); } } else if (!validValues.includes(value)) { throw new Error(`Invalid value for "${name}": "${value}". Valid choices: ${validValues.join(", ")}`); } }; // 1. CLI flag or positional arg if (name in cliOptions && cliOptions[name] !== undefined) { await validateAgainstChoices(cliOptions[name]); return cliOptions[name]; } // 2. JSON inputs if (name in jsonInputs && jsonInputs[name] !== undefined) { await validateAgainstChoices(jsonInputs[name]); return jsonInputs[name]; } // 3. Default (check before prompting, so optional inputs with defaults don't prompt) if ("default" in spec && spec.default !== undefined) { return spec.default; } // 4. Optional inputs: don't prompt, throw so baseContext returns undefined if (spec.required === false) { throw new types_1.MissingInputError(name, spec.message); } // 5. Interactive prompt if (isInteractive) { return promptInteractive({ ...spec, name }, this); } // 6. Throw throw new types_1.MissingInputError(name, spec.message); } } /** * Create a CommandContext for terminal usage. */ function createTerminalContext(command, options = {}) { return new TerminalContext(command, options); } exports.createTerminalContext = createTerminalContext; /** * Create a bare IO instance for terminal helper functions. */ function createTerminalIO(options = {}) { return { log(message) { console.log(message); }, async confirm(message) { var _a; if (options.yes) return true; const isInteractive = (_a = options.interactive) !== null && _a !== void 0 ? _a : process.stdin.isTTY === true; if (!isInteractive) return true; const inquirer = await Promise.resolve().then(() => __importStar(require("@inquirer/prompts"))); return inquirer.confirm({ message }); }, async promptDirect(spec) { var _a; const isInteractive = (_a = options.interactive) !== null && _a !== void 0 ? _a : process.stdin.isTTY === true; if (isInteractive) { return promptInteractive(spec, null); } if ("default" in spec && spec.default !== undefined) { return spec.default; } throw new types_1.MissingInputError(spec.name, spec.message); } }; } exports.createTerminalIO = createTerminalIO;