UNPKG

@rawcmd/typewriters

Version:

Collection of typewriters for styling command-line messages for Rawcmd.

99 lines (86 loc) 3.31 kB
import { EOL, alignText, wrapText, trucateText, repairAnsi, TextAlign } from '@rawcmd/text'; import { toArray, toString } from '@rawcmd/utils'; /** * Row typewriter configuration options. */ export interface RowTypewriterOptions { separatorSymbol?: string; truncationSymbol?: string; } /** * Row column configuration options. */ export interface ColumnRowTypewriterOptions { index: number; width?: number; textLength?: number; textWrap?: boolean; textAlign?: TextAlign; } /** * Row typewriter data type. */ export type RowTypewriterData = any[]; /** * Returns a typewriter function which converts the provided `data` into a * string representing a row with one or more columns. * NOTE: This method supports multibyte characters. * @param columns List of column related configuration options. * @param options Row related configuration options. */ export function rowTypewriter(columns?: ColumnRowTypewriterOptions[], options?: RowTypewriterOptions) { columns = columns || []; options = { separatorSymbol: ' ', truncationSymbol: '…', ...options, }; return (data: RowTypewriterData) => { data = (data || []).map((value) => { // make sure every data item is a string return toString(value) || ''; }); const config = data.map((value, index) => { // build configuration for each column return { index, width: Infinity, textLength: Infinity, textWrap: true, textAlign: TextAlign.LEFT, ...columns.find((column) => column.index === index), }; }); const grid = data.map((text, index) => { // build data rows for each column const { truncationSymbol } = options; const { textLength } = config[index]; return trucateText(text, textLength, truncationSymbol) || ''; // shorten text to allowed length }).map((text, index) => { const { width, textWrap } = config[index]; return toArray(textWrap ? wrapText(text, width) : text); // split column text into rows based on allowed column width }).map((rows, index) => { const { truncationSymbol } = options; const { width } = config[index]; return rows.map((row) => { return trucateText(row, width, truncationSymbol); // shorten text of each column line (could be a word which is longer then allowed column width) }); }); const size = [ // calculate grid dimension data.length, Math.max(...grid.map((rows) => rows.length)), ]; const output = grid.map((rows) => { // build final output structure return repairAnsi(...rows); }).map((rows, index) => { // build final output structure return rows.concat( ...Array(size[1] - rows.length).fill(' '), // make sure all columns have the same number of rows ).map((row) => { const { width, textAlign } = config[index]; return alignText(row, width, textAlign); // align each column data by adding spaces }); }).reduce((r, a) => { // transpose data by columns to rows and rows to collumns return a.map((v, i) => [...(r[i] || []), v]) as any; }, []).map((rows) => { // merge parts into string return rows.join(options.separatorSymbol || ''); }); return output.length ? output.join(EOL) : ''; // always return value }; }