UNPKG

clivo

Version:
209 lines (207 loc) 5.8 kB
// src/cli.ts function parseCli(params) { const keyValues = {}; const args = params.args.slice(params.parseFrom || 2); const nameByLetter = {}; const optionNames = /* @__PURE__ */ new Set(); const optionLetters = /* @__PURE__ */ new Set(); if (params.options != null) { for (const option of params.options) { if (optionNames.has(option.name)) { throw new Error(`Duplicate option name: ${option.name}`); } optionNames.add(option.name); if (option.letter) { if (optionLetters.has(option.letter)) { throw new Error(`Duplicate option letter: ${option.letter}`); } optionLetters.add(option.letter); nameByLetter[option.letter] = option.name; } } } let followOptions = null; const addValue = (key, value) => { if (!keyValues[key]) { keyValues[key] = []; } keyValues[key].push(value); }; const addValues = (key, values) => { if (!keyValues[key]) { keyValues[key] = []; } if (values.length > 0) { keyValues[key].push(...values); } else { keyValues[key].push("yes"); } }; const addFollowOptions = (value) => { if (followOptions == null) { return; } if (params.equalSignValuesOnly && value != null) { addValue("_", value); return; } for (const key of followOptions) { if (optionNames.has(key) || params.acceptUnspecifiedOptions) { if (value != null) { addValue(key, value); } else if (keyValues[key] == null) { addValue(key, "yes"); } } } }; for (const arg of args) { if (arg.startsWith("--")) { if (followOptions != null) { addFollowOptions(); } const [key, ...values] = arg.slice(2).split("="); followOptions = [key]; if (values.length > 0 && optionNames.has(key) || params.acceptUnspecifiedOptions) { addValues(key, values); } } else if (arg.startsWith("-")) { if (followOptions != null) { addFollowOptions(); } followOptions = null; const [letters, ...values] = arg.slice(1).split("="); for (const letter of letters) { const key = nameByLetter[letter] || params.acceptUnspecifiedOptions && letter; if (key) { if (followOptions == null) { followOptions = []; } if (values.length > 0) { addValues(key, values); } else { followOptions.push(key); } } } } else if (followOptions != null) { addFollowOptions(arg); } else { addValue("_", arg); } } if (followOptions != null) { addFollowOptions(); } return keyValues; } // src/prompts.ts import { EventEmitter } from "events"; import readline from "readline"; var emitter = new EventEmitter(); function listenClivoEvent(event, listener) { emitter.on(event, listener); } function registerSignals(readlineInterface) { const sigintListener = () => { emitter.emit("clivoCancel"); readlineInterface.close(); }; readlineInterface.on("SIGINT", sigintListener); } async function promptOptions(message, choices) { return new Promise( (resolve, reject) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); console.log(message); choices.forEach((choice, index) => { console.log(`${index + 1}. ${choice.label ?? choice.name}`); }); registerSignals(rl); rl.question("Select an option: ", (answer) => { const choiceIndex = parseInt(answer, 10) - 1; rl.close(); if (choiceIndex >= 0 && choiceIndex < choices.length) { resolve(choices[choiceIndex]); } else { reject(new Error("Invalid option, please try again.")); } }); } ).catch(() => promptOptions(message, choices)); } async function promptText(message) { return new Promise((resolve) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); registerSignals(rl); rl.question(`${message}: `, (answer) => { rl.close(); resolve(answer); }); }); } async function promptNumber(message) { return new Promise( (resolve, reject) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); registerSignals(rl); rl.question(`${message}: `, (answer) => { rl.close(); const number = parseFloat(answer); if (!isNaN(number)) { resolve(number); } else { reject(new Error("Invalid number, please try again.")); } }); } ).catch(() => promptNumber(message)); } async function promptWorkflow(message, workflow) { console.log(message); const results = []; for (const step of workflow) { if (step.type === "options" && step.choices) { const choice = await promptOptions(step.message, step.choices); results.push(choice); } else if (step.type === "text") { const text = await promptText(step.message); results.push(text); } else if (step.type === "number") { const number = await promptNumber(step.message); results.push(number); } } return results; } async function promptMenu(message, menu) { const choices = menu.map((item, index) => { return { label: item.label, name: "act" + (index + 1) }; }); const choice = await promptOptions(message, choices); const selectedItem = menu.find((item) => item.label === choice.label); if (selectedItem) { await selectedItem.action(); } } export { listenClivoEvent, parseCli, promptMenu, promptNumber, promptOptions, promptText, promptWorkflow };