123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.DefaultRenderer = void 0;
- const cliTruncate = require("cli-truncate");
- const logUpdate = require("log-update");
- const os_1 = require("os");
- const cliWrap = require("wrap-ansi");
- const colorette_1 = require("../utils/colorette");
- const figures_1 = require("../utils/figures");
- const indent_string_1 = require("../utils/indent-string");
- const is_unicode_supported_1 = require("../utils/is-unicode-supported");
- const parse_time_1 = require("../utils/parse-time");
- /** Default updating renderer for Listr2 */
- class DefaultRenderer {
- constructor(tasks, options, renderHook$) {
- this.tasks = tasks;
- this.options = options;
- this.renderHook$ = renderHook$;
- this.bottomBar = {};
- this.spinner = !(0, is_unicode_supported_1.isUnicodeSupported)() ? ['-', '\\', '|', '/'] : ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
- this.spinnerPosition = 0;
- this.options = { ...DefaultRenderer.rendererOptions, ...this.options };
- }
- getTaskOptions(task) {
- return { ...DefaultRenderer.rendererTaskOptions, ...task.rendererTaskOptions };
- }
- isBottomBar(task) {
- const bottomBar = this.getTaskOptions(task).bottomBar;
- return typeof bottomBar === 'number' && bottomBar !== 0 || typeof bottomBar === 'boolean' && bottomBar !== false;
- }
- hasPersistentOutput(task) {
- return this.getTaskOptions(task).persistentOutput === true;
- }
- hasTimer(task) {
- return this.getTaskOptions(task).showTimer === true;
- }
- getSelfOrParentOption(task, key) {
- var _a, _b, _c;
- return (_b = (_a = task === null || task === void 0 ? void 0 : task.rendererOptions) === null || _a === void 0 ? void 0 : _a[key]) !== null && _b !== void 0 ? _b : (_c = this.options) === null || _c === void 0 ? void 0 : _c[key];
- }
- /* istanbul ignore next */
- getTaskTime(task) {
- return colorette_1.default.dim(`[${(0, parse_time_1.parseTaskTime)(task.message.duration)}]`);
- }
- createRender(options) {
- options = {
- ...{
- tasks: true,
- bottomBar: true,
- prompt: true
- },
- ...options
- };
- const render = [];
- const renderTasks = this.multiLineRenderer(this.tasks);
- const renderBottomBar = this.renderBottomBar();
- const renderPrompt = this.renderPrompt();
- if (options.tasks && (renderTasks === null || renderTasks === void 0 ? void 0 : renderTasks.trim().length) > 0) {
- render.push(renderTasks);
- }
- if (options.bottomBar && (renderBottomBar === null || renderBottomBar === void 0 ? void 0 : renderBottomBar.trim().length) > 0) {
- render.push((render.length > 0 ? os_1.EOL : '') + renderBottomBar);
- }
- if (options.prompt && (renderPrompt === null || renderPrompt === void 0 ? void 0 : renderPrompt.trim().length) > 0) {
- render.push((render.length > 0 ? os_1.EOL : '') + renderPrompt);
- }
- return render.length > 0 ? render.join(os_1.EOL) : '';
- }
- render() {
- var _a;
- // Do not render if we are already rendering
- if (this.id) {
- return;
- }
- const updateRender = () => logUpdate(this.createRender());
- /* istanbul ignore if */
- if (!((_a = this.options) === null || _a === void 0 ? void 0 : _a.lazy)) {
- this.id = setInterval(() => {
- this.spinnerPosition = ++this.spinnerPosition % this.spinner.length;
- updateRender();
- }, 100);
- }
- this.renderHook$.subscribe(() => {
- updateRender();
- });
- }
- end() {
- clearInterval(this.id);
- if (this.id) {
- this.id = undefined;
- }
- // clear log updater
- logUpdate.clear();
- logUpdate.done();
- // directly write to process.stdout, since logupdate only can update the seen height of terminal
- if (!this.options.clearOutput) {
- process.stdout.write(this.createRender({ prompt: false }) + os_1.EOL);
- }
- }
- // eslint-disable-next-line
- multiLineRenderer(tasks, level = 0) {
- var _a, _b;
- let output = [];
- for (const task of tasks) {
- if (task.isEnabled()) {
- // Current Task Title
- if (task.hasTitle()) {
- if (!(tasks.some((task) => task.hasFailed()) && !task.hasFailed() && task.options.exitOnError !== false && !(task.isCompleted() || task.isSkipped()))) {
- // if task is skipped
- if (task.hasFailed() && this.getSelfOrParentOption(task, 'collapseErrors')) {
- // current task title and skip change the title
- output = [
- ...output,
- this.formatString(!task.hasSubtasks() && task.message.error && this.getSelfOrParentOption(task, 'showErrorMessage') ? task.message.error : task.title, this.getSymbol(task), level)
- ];
- }
- else if (task.isSkipped() && this.getSelfOrParentOption(task, 'collapseSkips')) {
- // current task title and skip change the title
- output = [
- ...output,
- this.formatString(this.addSuffixToMessage(task.message.skip && this.getSelfOrParentOption(task, 'showSkipMessage') ? task.message.skip : task.title, 'SKIPPED', this.getSelfOrParentOption(task, 'suffixSkips')), this.getSymbol(task), level)
- ];
- }
- else if (task.isRetrying() && this.getSelfOrParentOption(task, 'suffixRetries')) {
- output = [...output, this.formatString(this.addSuffixToMessage(task.title, `RETRYING-${task.message.retry.count}`), this.getSymbol(task), level)];
- }
- else if (task.isCompleted() && task.hasTitle() && (this.getSelfOrParentOption(task, 'showTimer') || this.hasTimer(task))) {
- // task with timer
- output = [...output, this.formatString(`${task === null || task === void 0 ? void 0 : task.title} ${this.getTaskTime(task)}`, this.getSymbol(task), level)];
- }
- else {
- // normal state
- output = [...output, this.formatString(task.title, this.getSymbol(task), level)];
- }
- }
- else {
- // some sibling task but self has failed and this has stopped
- output = [...output, this.formatString(task.title, colorette_1.default.red(figures_1.figures.squareSmallFilled), level)];
- }
- }
- // task should not have subtasks since subtasks will handle the error already
- // maybe it is a better idea to show the error or skip messages when show subtasks is disabled.
- if (!task.hasSubtasks() || !this.getSelfOrParentOption(task, 'showSubtasks')) {
- // without the collapse option for skip and errors
- if (task.hasFailed() &&
- this.getSelfOrParentOption(task, 'collapseErrors') === false &&
- (this.getSelfOrParentOption(task, 'showErrorMessage') || !this.getSelfOrParentOption(task, 'showSubtasks'))) {
- // show skip data if collapsing is not defined
- output = [...output, this.dumpData(task, level, 'error')];
- }
- else if (task.isSkipped() &&
- this.getSelfOrParentOption(task, 'collapseSkips') === false &&
- (this.getSelfOrParentOption(task, 'showSkipMessage') || !this.getSelfOrParentOption(task, 'showSubtasks'))) {
- // show skip data if collapsing is not defined
- output = [...output, this.dumpData(task, level, 'skip')];
- }
- }
- // Current Task Output
- if (task === null || task === void 0 ? void 0 : task.output) {
- if ((task.isPending() || task.isRetrying() || task.isRollingBack()) && task.isPrompt()) {
- // data output to prompt bar if prompt
- this.promptBar = task.output;
- }
- else if (this.isBottomBar(task) || !task.hasTitle()) {
- // data output to bottom bar
- const data = [this.dumpData(task, -1)];
- // create new if there is no persistent storage created for bottom bar
- if (!this.bottomBar[task.id]) {
- this.bottomBar[task.id] = {};
- this.bottomBar[task.id].data = [];
- const bottomBar = this.getTaskOptions(task).bottomBar;
- if (typeof bottomBar === 'boolean') {
- this.bottomBar[task.id].items = 1;
- }
- else {
- this.bottomBar[task.id].items = bottomBar;
- }
- }
- // persistent bottom bar and limit items in it
- if (!((_b = (_a = this.bottomBar[task.id]) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.some((element) => data.includes(element))) && !task.isSkipped()) {
- this.bottomBar[task.id].data = [...this.bottomBar[task.id].data, ...data];
- }
- }
- else if (task.isPending() || task.isRetrying() || task.isRollingBack() || this.hasPersistentOutput(task)) {
- // keep output if persistent output is set
- output = [...output, this.dumpData(task, level)];
- }
- }
- // render subtasks, some complicated conditionals going on
- if (
- // check if renderer option is on first
- this.getSelfOrParentOption(task, 'showSubtasks') !== false &&
- // if it doesnt have subtasks no need to check
- task.hasSubtasks() &&
- (task.isPending() ||
- task.hasFailed() ||
- task.isCompleted() && !task.hasTitle() ||
- // have to be completed and have subtasks
- task.isCompleted() && this.getSelfOrParentOption(task, 'collapse') === false && !task.subtasks.some((subtask) => subtask.rendererOptions.collapse === true) ||
- // if any of the subtasks have the collapse option of
- task.subtasks.some((subtask) => subtask.rendererOptions.collapse === false) ||
- // if any of the subtasks has failed
- task.subtasks.some((subtask) => subtask.hasFailed()) ||
- // if any of the subtasks rolled back
- task.subtasks.some((subtask) => subtask.hasRolledBack()))) {
- // set level
- const subtaskLevel = !task.hasTitle() ? level : level + 1;
- // render the subtasks as in the same way
- const subtaskRender = this.multiLineRenderer(task.subtasks, subtaskLevel);
- if ((subtaskRender === null || subtaskRender === void 0 ? void 0 : subtaskRender.trim()) !== '' && !task.subtasks.every((subtask) => !subtask.hasTitle())) {
- output = [...output, subtaskRender];
- }
- }
- // after task is finished actions
- if (task.isCompleted() || task.hasFailed() || task.isSkipped() || task.hasRolledBack()) {
- // clean up prompts
- this.promptBar = null;
- // clean up bottom bar items if not indicated otherwise
- if (!this.hasPersistentOutput(task)) {
- delete this.bottomBar[task.id];
- }
- }
- }
- }
- output = output.filter(Boolean);
- if (output.length > 0) {
- return output.join(os_1.EOL);
- }
- else {
- return;
- }
- }
- renderBottomBar() {
- // parse through all objects return only the last mentioned items
- if (Object.keys(this.bottomBar).length > 0) {
- this.bottomBar = Object.keys(this.bottomBar).reduce((o, key) => {
- if (!(o === null || o === void 0 ? void 0 : o[key])) {
- o[key] = {};
- }
- o[key] = this.bottomBar[key];
- this.bottomBar[key].data = this.bottomBar[key].data.slice(-this.bottomBar[key].items);
- o[key].data = this.bottomBar[key].data;
- return o;
- }, {});
- return Object.values(this.bottomBar)
- .reduce((o, value) => o = [...o, ...value.data], [])
- .filter(Boolean)
- .join(os_1.EOL);
- }
- }
- renderPrompt() {
- if (this.promptBar) {
- return this.promptBar;
- }
- }
- dumpData(task, level, source = 'output') {
- let data;
- switch (source) {
- case 'output':
- data = task.output;
- break;
- case 'skip':
- data = task.message.skip;
- break;
- case 'error':
- data = task.message.error;
- break;
- }
- // dont return anything on some occasions
- if (task.hasTitle() && source === 'error' && data === task.title) {
- return;
- }
- if (typeof data === 'string') {
- return this.formatString(data, this.getSymbol(task, true), level + 1);
- }
- }
- formatString(str, icon, level) {
- // we dont like empty data around here
- if (str.trim() === '') {
- return;
- }
- str = `${icon} ${str}`;
- let parsedStr;
- let columns = process.stdout.columns ? process.stdout.columns : 80;
- columns = columns - level * this.options.indentation - 2;
- switch (this.options.formatOutput) {
- case 'truncate':
- parsedStr = str.split(os_1.EOL).map((s, i) => {
- return cliTruncate(this.indentMultilineOutput(s, i), columns);
- });
- break;
- case 'wrap':
- parsedStr = cliWrap(str, columns, { hard: true })
- .split(os_1.EOL)
- .map((s, i) => this.indentMultilineOutput(s, i));
- break;
- default:
- throw new Error('Format option for the renderer is wrong.');
- }
- // this removes the empty lines
- if (this.options.removeEmptyLines) {
- parsedStr = parsedStr.filter(Boolean);
- }
- return (0, indent_string_1.indentString)(parsedStr.join(os_1.EOL), level * this.options.indentation);
- }
- indentMultilineOutput(str, i) {
- return i > 0 ? (0, indent_string_1.indentString)(str.trim(), 2) : str.trim();
- }
- // eslint-disable-next-line complexity
- getSymbol(task, data = false) {
- var _a, _b, _c;
- if (task.isPending() && !data) {
- return ((_a = this.options) === null || _a === void 0 ? void 0 : _a.lazy) || this.getSelfOrParentOption(task, 'showSubtasks') !== false && task.hasSubtasks() && !task.subtasks.every((subtask) => !subtask.hasTitle())
- ? colorette_1.default.yellow(figures_1.figures.pointer)
- : colorette_1.default.yellowBright(this.spinner[this.spinnerPosition]);
- }
- else if (task.isCompleted() && !data) {
- return task.hasSubtasks() && task.subtasks.some((subtask) => subtask.hasFailed()) ? colorette_1.default.yellow(figures_1.figures.warning) : colorette_1.default.green(figures_1.figures.tick);
- }
- else if (task.isRetrying() && !data) {
- return ((_b = this.options) === null || _b === void 0 ? void 0 : _b.lazy) ? colorette_1.default.yellow(figures_1.figures.warning) : colorette_1.default.yellow(this.spinner[this.spinnerPosition]);
- }
- else if (task.isRollingBack() && !data) {
- return ((_c = this.options) === null || _c === void 0 ? void 0 : _c.lazy) ? colorette_1.default.red(figures_1.figures.warning) : colorette_1.default.red(this.spinner[this.spinnerPosition]);
- }
- else if (task.hasRolledBack() && !data) {
- return colorette_1.default.red(figures_1.figures.arrowLeft);
- }
- else if (task.hasFailed() && !data) {
- return task.hasSubtasks() ? colorette_1.default.red(figures_1.figures.pointer) : colorette_1.default.red(figures_1.figures.cross);
- }
- else if (task.isSkipped() && !data && this.getSelfOrParentOption(task, 'collapseSkips') === false) {
- return colorette_1.default.yellow(figures_1.figures.warning);
- }
- else if (task.isSkipped() && (data || this.getSelfOrParentOption(task, 'collapseSkips'))) {
- return colorette_1.default.yellow(figures_1.figures.arrowDown);
- }
- return !data ? colorette_1.default.dim(figures_1.figures.squareSmallFilled) : figures_1.figures.pointerSmall;
- }
- addSuffixToMessage(message, suffix, condition) {
- return (condition !== null && condition !== void 0 ? condition : true) ? message + colorette_1.default.dim(` [${suffix}]`) : message;
- }
- }
- exports.DefaultRenderer = DefaultRenderer;
- /** designates whether this renderer can output to a non-tty console */
- DefaultRenderer.nonTTY = false;
- /** renderer options for the defauult renderer */
- DefaultRenderer.rendererOptions = {
- indentation: 2,
- clearOutput: false,
- showSubtasks: true,
- collapse: true,
- collapseSkips: true,
- showSkipMessage: true,
- suffixSkips: true,
- collapseErrors: true,
- showErrorMessage: true,
- suffixRetries: true,
- lazy: false,
- showTimer: false,
- removeEmptyLines: true,
- formatOutput: 'truncate'
- };
|