zcatalyst-cli
Version:
Command Line Tool for CATALYST
320 lines (319 loc) • 12.6 kB
JavaScript
"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;