@mondaycom/apps-cli
Version:
A cli tool to manage apps (and monday-code projects) in monday.com
187 lines (186 loc) • 6.95 kB
JavaScript
import fuzzy from 'fuzzy';
import inquirer from 'inquirer';
import autocomplete from 'inquirer-autocomplete-prompt';
import DatePrompt from 'inquirer-date-prompt';
import isEmail from 'isemail';
import { APP_ID_TO_ENTER, APP_VERSION_ID_TO_ENTER } from '../consts/messages.js';
import { checkIfFileExists, getFileExtension } from './files-service.js';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
inquirer.registerPrompt('date', DatePrompt);
inquirer.registerPrompt('autocomplete', autocomplete);
function validateIfRequired(input, message, isRequired = false) {
if (isRequired && !input) {
return message;
}
return true;
}
export function validateIfValueIsANumber(input, message, isRequired = false) {
// If not required and input is empty, it's valid
if (!isRequired && !input) {
return true;
}
// If required and input is empty, return error
if (isRequired && !input) {
return message;
}
// Check if it's a valid non-negative integer (including 0)
const isNumber = /^\d+$/.test(input);
if (!isNumber) {
return message;
}
return true;
}
export const PromptService = {
async promptList(message, choices, defaultValue) {
const res = await inquirer.prompt([
{
name: 'selection',
message: message || 'Please choose one of the values',
type: 'list',
choices,
...(defaultValue && { default: defaultValue }),
},
]);
return res.selection;
},
async promptDateTimePicker(message, selectedDate = new Date(), options = {}) {
const baseOptions = {
type: 'date',
name: 'timestamp',
message,
default: selectedDate,
locale: 'en-US',
format: { month: 'short', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' },
clearable: false,
};
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const config = Object.assign(baseOptions, options);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const prompt = await inquirer.prompt(config);
return prompt.timestamp;
},
async promptConfirm(message, defaultValue = false) {
const res = await inquirer.prompt([
{
name: 'confirm',
message: message || 'Are you sure?',
type: 'confirm',
default: defaultValue,
},
]);
return res.confirm;
},
async promptForEmail(message) {
const res = await inquirer.prompt([
{
name: 'email',
message: message || 'Please enter your email',
type: 'input',
validate(input) {
if (!input)
return 'You must enter your email';
if (!isEmail.validate(input))
return 'You must enter a valid email - <local-part>@<domain>';
return true;
},
},
]);
return res.email;
},
async promptForHiddenInput(name, message, validationMessage) {
const res = await inquirer.prompt([
{
name,
message,
type: 'password',
validate(input) {
return validateIfRequired(input, validationMessage, true);
},
},
]);
return res[name];
},
async promptForPassword() {
return this.promptForHiddenInput('password', 'Please enter your password', 'You must enter a password');
},
async promptInput(message, required = false, allowUndefined = false) {
const res = await inquirer.prompt([
{
name: 'input',
message: message || 'Please enter value',
type: 'input',
validate(input) {
return validateIfRequired(input, 'You must enter a value', required);
},
},
]);
if (allowUndefined && (!res.input || (typeof res.input === 'string' && res.input === ''))) {
return undefined;
}
return res.input;
},
async promptInputNumber(message, required = false, allowUndefined = false) {
const res = await inquirer.prompt([
{
name: 'input',
message: message || 'Please enter value',
type: 'input',
validate(input) {
return validateIfValueIsANumber(input, 'You must enter a number', required);
},
},
]);
if (allowUndefined && (!res.input || (typeof res.input === 'string' && res.input === ''))) {
return undefined;
}
return Number(res.input);
},
async promptFile(message, extensions) {
const res = await inquirer.prompt([
{
name: 'filePath',
message: message || 'Please type full file path',
type: 'input',
extensions,
validate(input) {
if (!input)
return 'You must enter valid file path';
if (!checkIfFileExists(input))
return 'You must enter valid file path';
if (extensions && extensions.length > 0 && !extensions.includes(getFileExtension(input).toLowerCase())) {
return `The process supports those file extensions: ${extensions.join(',')}`;
}
return true;
},
},
]);
return res.filePath;
},
async promptSelectionWithAutoComplete(message, choices, options = {}) {
const fuzzySearch = (_answers, input = '') => {
return new Promise(resolve => {
const finalChoices = options.includeInputInSelection && input ? [...new Set([...choices, input])] : choices;
// eslint-disable-next-line import/no-named-as-default-member
const results = fuzzy.filter(input, finalChoices).map(element => element.original);
resolve(results);
});
};
const res = await inquirer.prompt([
{
name: 'selection',
message: message || 'Please choose one of the values',
type: 'autocomplete',
source: fuzzySearch,
...options,
},
]);
return res.selection;
},
async appVersionPrompt() {
return PromptService.promptInputNumber(APP_VERSION_ID_TO_ENTER, true);
},
async appPrompt() {
return PromptService.promptInputNumber(APP_ID_TO_ENTER, true);
},
};