UNPKG

console-toolkit

Version:

Toolkit to produce a fancy console output (boxes, tables, charts, colors).

133 lines (114 loc) 3.74 kB
'use strict'; import process from 'node:process'; import {CURSOR_DOWN1, CURSOR_RESTORE_POS, CURSOR_SAVE_POS} from '../ansi/csi.js'; import {getLength, matchCsiNoGroups, matchCsiNoSgrNoGroups, toStrings} from '../strings.js'; const write = async (stream, chunk, encoding = 'utf8') => new Promise((resolve, reject) => stream.write(chunk, encoding, error => (error ? reject(error) : resolve()))); export class Writer { constructor(stream = process.stdout, forceColorDepth) { this.stream = stream; this.forceColorDepth = forceColorDepth; } get isTTY() { return this.stream.isTTY; } get columns() { return this.stream.columns; } get rows() { return this.stream.rows; } get size() { const [columns, rows] = this.stream.getWindowSize?.() || []; return {columns, rows}; } getColorDepth(...args) { return this.forceColorDepth || this.stream.getColorDepth?.(...args); } hasColors(...args) { return this.forceColorDepth ? args[0] <= Math.pow(2, this.forceColorDepth) : this.stream.hasColors?.(...args); } clearLine(dir) { return new Promise((resolve, reject) => { if (typeof this.stream.clearLine == 'function') { this.stream.clearLine(dir, error => (error ? reject(error) : resolve(true))); } else { resolve(false); } }); } clearScreenDown() { return new Promise((resolve, reject) => { if (typeof this.stream.clearScreenDown == 'function') { this.stream.clearScreenDown(error => (error ? reject(error) : resolve(true))); } else { resolve(false); } }); } cursorTo(x, y) { return new Promise((resolve, reject) => { if (typeof this.stream.cursorTo == 'function') { this.stream.cursorTo(x, y, error => (error ? reject(error) : resolve(true))); } else { resolve(false); } }); } moveCursor(dx, dy) { return new Promise((resolve, reject) => { if (typeof this.stream.moveCursor == 'function') { this.stream.moveCursor(dx, dy, error => (error ? reject(error) : resolve(true))); } else { resolve(false); } }); } async writeString(s) { s = String(s); if (this.isTTY) { await write(this.stream, s); return; } // no cursor/screen commands if (this.forceColorDepth) { matchCsiNoSgrNoGroups.lastIndex = 0; await write(this.stream, s.replace(matchCsiNoSgrNoGroups, '')); return; } // no colors matchCsiNoGroups.lastIndex = 0; await write(this.stream, s.replace(matchCsiNoGroups, '')); } async write(s, {sameColumn, noLastNewLine, beforeLine = '', afterLine = ''} = {}) { s = toStrings(s); if (!this.isTTY) { const matcher = this.forceColorDepth ? matchCsiNoSgrNoGroups : matchCsiNoGroups; let lines = Array.from(s).map(line => beforeLine + line + afterLine).join('\n'); if (!noLastNewLine) lines += '\n'; matcher.lastIndex = 0; lines = lines.replace(matcher, ''); await write(this.stream, lines); return; } if (sameColumn === 'save') { for (const line of s) { await write(this.stream, CURSOR_SAVE_POS + beforeLine + line + afterline + CURSOR_RESTORE_POS + CURSOR_DOWN1); } return; } if (sameColumn) { for (const line of s) { const fullLine = beforeLine + line + afterLine, length = getLength(fullLine); await write(this.stream, fullLine); await this.moveCursor(-length, 1); } return; } let lines = Array.from(s).map(line => beforeLine + line + afterLine).join('\n'); if (!noLastNewLine) lines += '\n'; await write(this.stream, lines); } } export default Writer;