ts-node-app
Version:
CLI para geração de componentes em arquiteturas DDD, hexagonal ou Clean Architecture ...
143 lines (123 loc) • 3.27 kB
JavaScript
import { exit, stdin, stdout } from "process";
import { createInterface } from "readline";
import { Logger, styled } from "./logger.js";
import { spawnSync } from "child_process";
export class Prompt {
constructor() {
this.yesToAll = false;
this.logger = new Logger(Prompt.name);
}
/**
*
* @param {string} command
* @param {readonly string[]} args
* @param {import("child_process").SpawnSyncOptionsWithBufferEncoding} options
*/
spawn(command, args, options = {}) {
this.logger.debug(`Spawn: ${command}`, args.join(" "));
const result = spawnSync(command, args, { ...options, encoding: "utf-8" });
if (result.error) {
this.logger.error("Failed to run command:", result.error);
return null;
}
return result.stdout || result.stderr ? (result.stdout + result.stderr).trim() : "";
}
async delay(time) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
/**
* @param {string} question
* @returns {Promise<string>}
*/
async ask(question) {
const rl = createInterface({
input: stdin,
output: stdout,
});
return new Promise((resolve) => {
rl.question(styled("italic", question), (answer) => {
resolve(answer);
rl.close();
});
});
}
/**
*
* @param {string} question
* @param {readonly string[]} options
*/
async select(question, options, { cancelLabel = "Cancel" } = {}) {
const rl = this.#createReadLineInterface();
let value;
const format = styled("italic", ` > ${question}: `);
const optionsFormat = [cancelLabel]
.concat(options)
.map((option, index) => {
return ` ${index}. ${styled("cyan", option)}`;
})
.join("\n");
stdout.write(format + "\n" + optionsFormat + "\n > ");
return new Promise((resolve) => {
stdin.on("keypress", (answer) => {
const index = parseInt(answer);
value = options[index - 1];
rl.close();
});
stdin.on("ready", () => {
stdout.write(optionsFormat);
});
rl.on("close", () => {
stdout.write("\n");
resolve(value);
});
});
}
/**
* @param {string} question
* @returns {Promise<boolean>}
*/
async confirm(question) {
if (this.yesToAll) return true;
const format = styled("italic", ` > ${question} (y|n|all): `);
let value = false;
const rl = this.#createReadLineInterface();
stdout.write(format);
return new Promise((resolve) => {
stdin.on("keypress", (str) => {
value = this.#parseInput(str);
rl.close();
});
rl.on("close", () => {
stdout.write("\n");
resolve(value);
});
});
}
/**
* @param {string} input
*/
#parseInput(input) {
if (["\r", "\n", "y"].includes(input)) return true;
if (input === "a") {
this.yesToAll = true;
return true;
}
return false;
}
#createReadLineInterface() {
const rl = createInterface({
input: stdin,
output: stdout,
});
if (stdin.isTTY) {
stdin.setRawMode(true);
}
rl.on("SIGINT", exit);
rl.on("SIGCONT", exit);
rl.on("SIGTSTP", exit);
rl.on("SIGBREAK", exit);
return rl;
}
}