UNPKG

zcatalyst-cli

Version:

Command Line Tool for CATALYST

320 lines (319 loc) 12.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const ansi_colors_1 = require("ansi-colors"); const cli_cursor_1 = __importDefault(require("cli-cursor")); const choices_1 = __importDefault(require("inquirer/lib/objects/choices")); const base_1 = __importDefault(require("inquirer/lib/prompts/base")); const events_1 = __importDefault(require("inquirer/lib/utils/events")); const paginator_1 = __importDefault(require("inquirer/lib/utils/paginator")); const operators_1 = require("rxjs/operators"); const error_1 = __importDefault(require("../../error")); class SearchBox extends base_1.default { constructor(questions, rl, answers) { questions.prefix = ''; super(questions, rl, answers); this.pointer = 0; if (!this.opt.highlight) { this.opt.highlight = false; } if (!this.opt.searchable) { this.opt.searchable = false; } if (this.opt.default === undefined || this.opt.default === null) { this.opt.default = undefined; } if (!this.opt.source) { this.throwParamError('source'); } if (this.opt.notFoundMsg === undefined) { this.opt.notFoundMsg = 'No results...'; } if (this.opt.searchMsg === undefined) { this.opt.searchMsg = 'Searching...'; } this.boxType = this.opt.boxType || 'check-box'; this.pointer = 0; this.choices = new choices_1.default([], answers); this.checkedChoices = []; this.value = []; this.lastQuery = undefined; this.searching = false; this.lastSourcePromise = undefined; this.default = this.opt.default; this.opt.default = undefined; this.done = undefined; this.paginator = new paginator_1.default(this.screen); } _run(callback) { this.done = callback; this.executeSource().then(() => { const events = (0, events_1.default)(this.rl); const validation = this.handleSubmitEvents(events.line.pipe((0, operators_1.map)(this.getCurrentValue.bind(this)))); validation.success.forEach(this.onEnd.bind(this)); validation.error.forEach(this.onError.bind(this)); events.normalizedUpKey .pipe((0, operators_1.takeUntil)(validation.success)) .forEach(this.onUpKey.bind(this)); events.normalizedDownKey .pipe((0, operators_1.takeUntil)(validation.success)) .forEach(this.onDownKey.bind(this)); if (this.boxType === 'check-box') { events.spaceKey .pipe((0, operators_1.takeUntil)(validation.success)) .forEach(this.onSpaceKey.bind(this)); if (this.opt.searchable === false) { events.numberKey .pipe((0, operators_1.takeUntil)(validation.success)) .forEach(this.onNumberKey.bind(this)); events.aKey .pipe((0, operators_1.takeUntil)(validation.success)) .forEach(this.onAllKey.bind(this)); events.iKey .pipe((0, operators_1.takeUntil)(validation.success)) .forEach(this.onInverseKey.bind(this)); } else { events.keypress .pipe((0, operators_1.takeUntil)(validation.success)) .forEach(this.onKeypress.bind(this)); } } else { events.keypress .pipe((0, operators_1.takeUntil)(validation.success)) .forEach(this.onKeypress.bind(this)); } if (this.rl.line) { this.onKeypress(); } cli_cursor_1.default.hide(); this.render(); }); return this; } getValue(choice) { if (choice.type === 'separator') { return undefined; } return choice.value; } executeSource() { let sourcePromise; this.rl.line = this.rl.line.trim(); if (this.rl.line === this.lastQuery) { return Promise.resolve(undefined); } if (this.opt.searchable) { sourcePromise = this.opt.source(this.answers, this.rl.line); } else { sourcePromise = this.opt.source(this.answers, undefined); } this.lastQuery = this.rl.line; this.lastSourcePromise = sourcePromise; this.searching = true; sourcePromise.then((choices) => { if (this.lastSourcePromise !== sourcePromise) { return; } this.searching = false; this.choices = new choices_1.default(choices, this.answers); this.choices.forEach((choice) => { var _a; if (this.value.some((eachValue) => this.getValue(choice) === eachValue)) { this.toggleChoice(choice, true); } else { this.toggleChoice(choice, false); } if (this.default !== null) { if ((_a = this.default) === null || _a === void 0 ? void 0 : _a.some((defaultValue) => this.getValue(choice) === defaultValue)) { this.toggleChoice(choice, true); } } }); this.pointer = 0; this.render(); this.default = undefined; }); return sourcePromise; } render({ answer, error } = {}) { let message = this.getQuestion(); let bottomContent = ''; if (this.status === 'answered') { if (answer === undefined) { throw new error_1.default(`Unable to get the answer for search-box(${this.opt.name}) :: ${answer}`, { exit: 2 }); } message += (0, ansi_colors_1.cyan)(Array.isArray(answer) ? answer.map((ans) => ans.short).join(', ') : answer.short); return this.screen.render(message, bottomContent); } if (this.rl.line.length === 0) { switch (this.boxType) { case 'check-box': { if (this.opt.searchable) { message += (0, ansi_colors_1.dim)(`(Press ${ansi_colors_1.cyan.bold('<space>')} to select, or type anything to filter the list)`); } else { message += (0, ansi_colors_1.dim)(`(Press ${ansi_colors_1.cyan.bold('<space>')} to select, ${ansi_colors_1.cyan.bold('<a>')} to toggle all, ${ansi_colors_1.cyan.bold('<i>')} to invert selection)`); } break; } case 'list': { message += (0, ansi_colors_1.dim)(`(Press ${ansi_colors_1.cyan.bold('<return>')} to select)`); break; } } } if (this.opt.searchable) { message += (0, ansi_colors_1.green)(this.rl.line); } if (this.searching) { message += `\n ${(0, ansi_colors_1.cyan)(this.opt.searchMsg || '')}`; } else if (!this.choices.length) { message += `\n ${(0, ansi_colors_1.yellow)(this.opt.notFoundMsg || '')}`; } else { const choicesStr = this.renderChoices(this.choices, this.pointer, this.boxType === 'check-box'); const choice = this.choices.getChoice(this.pointer); const indexPosition = this.choices.indexOf(choice); message += `\n${this.paginator.paginate(choicesStr, indexPosition, this.opt.pageSize)}`; } if (error) { bottomContent = (0, ansi_colors_1.red)('>> ') + error; } return this.screen.render(message, bottomContent); } onEnd(state) { var _a; this.status = 'answered'; const answer = 'value' in state ? state.value : undefined; this.render({ answer }); this.screen.done(); cli_cursor_1.default.show(); (_a = this.done) === null || _a === void 0 ? void 0 : _a.call(this, Array.isArray(answer) ? answer.map((ans) => ans.value) : answer.value); } onError(state) { if (typeof state.isValid === 'string') { const _errStr = state.isValid; this.executeSource().then(() => { this.render({ error: _errStr }); }); } } getCurrentValue() { switch (this.boxType) { case 'check-box': { return this.checkedChoices; } case 'list': { return this.choices.getChoice(this.pointer); } } } onUpKey() { const len = this.choices.realLength; this.pointer = this.pointer > 0 ? this.pointer - 1 : len - 1; this.render(); } onDownKey() { const len = this.choices.realLength; this.pointer = this.pointer < len - 1 ? this.pointer + 1 : 0; this.render(); } onNumberKey(input) { if (input <= this.choices.realLength) { this.pointer = input - 1; this.toggleChoice(this.choices.getChoice(this.pointer)); } this.render(); } onSpaceKey() { if (this.boxType !== 'check-box') { return; } if (!this.choices.getChoice(this.pointer)) { return; } this.toggleChoice(this.choices.getChoice(this.pointer)); this.render(); } onAllKey() { const shouldBeChecked = Boolean(this.choices.find((choice) => { return choice.type !== 'separator' && !choice.checked; })); this.choices.forEach((choice) => { if (choice.type !== 'separator') { choice.checked = shouldBeChecked; } return choice; }); this.render(); } onInverseKey() { this.choices.forEach((choice) => { if (choice.type !== 'separator') { choice.checked = !choice.checked; } }); this.render(); } onKeypress() { this.executeSource(); this.render(); } toggleChoice(choice, nextChecked) { var _a; if (choice.type === 'separator') { return; } const checked = nextChecked === undefined ? !((_a = choice.checked) !== null && _a !== void 0 ? _a : false) : nextChecked; this.value = this.value.filter((eachValue) => eachValue !== choice.value); this.checkedChoices = this.checkedChoices.filter((checkedChoice) => checkedChoice.value !== choice.value); choice.checked = false; if (checked === true) { this.value.push(choice.value); this.checkedChoices.push(choice); choice.checked = true; } } static getCheckboxFigure(checked = false) { return checked ? (0, ansi_colors_1.green)('◉') : '◯'; } renderChoices(choices, pointer, checkBox = true) { const output = []; let separatorOffset = 0; choices.forEach((choice, index) => { if (choice.type === 'separator') { separatorOffset += 1; output.push(` ${choice}\n`); return; } if (choice.disabled) { separatorOffset += 1; output.push(` - ${choice.name} (${typeof choice.disabled === 'string' ? choice.disabled : 'Disabled'})\n`); return; } if (index - separatorOffset === pointer) { const pointedLine = checkBox ? `❯ ${SearchBox.getCheckboxFigure(choice.checked)} ${choice.name}` : `❯ ${choice.name}`; output.push(this.opt.highlight ? (0, ansi_colors_1.cyan)(pointedLine) : pointedLine); } else { output.push(checkBox ? ` ${SearchBox.getCheckboxFigure(choice.checked)} ${choice.name}` : ` ${choice.name}`); } output.push('\n'); }); return output.join('').replace(/\n$/, ''); } } exports.default = SearchBox;