173 lines
4.7 KiB
TypeScript
173 lines
4.7 KiB
TypeScript
import { table } from "table";
|
|
|
|
/**
|
|
* Print a formatted table with consistent styling
|
|
* @param rows - Array of string arrays representing table rows
|
|
* @param options - Optional table configuration
|
|
*/
|
|
|
|
export function tableString(
|
|
rows: string[][],
|
|
options?: {
|
|
title?: string;
|
|
indent?: string;
|
|
drawHorizontalLine?: (lineIndex: number, rowCount: number) => boolean;
|
|
}
|
|
): string {
|
|
const {
|
|
title,
|
|
indent = "",
|
|
drawHorizontalLine = (lineIndex: number, rowCount: number) => {
|
|
return lineIndex === 0 || (options?.title && lineIndex === 1) || lineIndex === rowCount;
|
|
},
|
|
} = options || {};
|
|
|
|
if (options?.title) {
|
|
rows.unshift([options.title]);
|
|
}
|
|
|
|
const tableOutput = table(rows, {
|
|
drawHorizontalLine,
|
|
border: {
|
|
topBody: `─`,
|
|
topJoin: `┬`,
|
|
topLeft: `┌`,
|
|
topRight: `┐`,
|
|
|
|
bottomBody: `─`,
|
|
bottomJoin: `┴`,
|
|
bottomLeft: `└`,
|
|
bottomRight: `┘`,
|
|
|
|
bodyLeft: `│`,
|
|
bodyRight: `│`,
|
|
bodyJoin: `│`,
|
|
|
|
joinBody: `─`,
|
|
joinLeft: `├`,
|
|
joinRight: `┤`,
|
|
joinJoin: `┼`,
|
|
},
|
|
});
|
|
|
|
const indentedOutput = tableOutput.split("\n").join(`\n${indent}`).trim();
|
|
|
|
return `${indent}${indentedOutput}`;
|
|
}
|
|
|
|
/**
|
|
* Print a multi-line string in a formatted box with text wrapping
|
|
* @param text - The text to display
|
|
* @param options - Optional configuration for the box
|
|
*/
|
|
export function boxString(
|
|
text: string,
|
|
options?: {
|
|
title?: string;
|
|
maxWidth?: number;
|
|
indent?: string;
|
|
padding?: number;
|
|
}
|
|
): string {
|
|
const { title, maxWidth = 80, indent = "", padding = 1 } = options || {};
|
|
|
|
// Clean up the text and split into lines
|
|
const lines = text.trim().split("\n");
|
|
|
|
// Word wrap each line to fit within maxWidth
|
|
const wrappedLines: string[] = [];
|
|
for (const line of lines) {
|
|
if (line.length <= maxWidth - padding * 2) {
|
|
wrappedLines.push(line);
|
|
} else {
|
|
// Word wrap the line
|
|
const words = line.split(" ");
|
|
let currentLine = "";
|
|
|
|
for (const word of words) {
|
|
const testLine = currentLine ? `${currentLine} ${word}` : word;
|
|
if (testLine.length <= maxWidth - padding * 2) {
|
|
currentLine = testLine;
|
|
} else {
|
|
if (currentLine) {
|
|
wrappedLines.push(currentLine);
|
|
currentLine = word;
|
|
} else {
|
|
// Word is too long, break it
|
|
wrappedLines.push(word.substring(0, maxWidth - padding * 2));
|
|
currentLine = word.substring(maxWidth - padding * 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (currentLine) {
|
|
wrappedLines.push(currentLine);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Find the maximum line length for box sizing
|
|
const maxLineLength = Math.max(...wrappedLines.map((line) => line.length));
|
|
const boxWidth = maxLineLength + padding * 2;
|
|
|
|
// Create the box
|
|
const topBorder = "┌" + "─".repeat(boxWidth) + "┐";
|
|
const bottomBorder = "└" + "─".repeat(boxWidth) + "┘";
|
|
const sideBorder = "│";
|
|
|
|
let result = "";
|
|
|
|
// Add title if provided
|
|
if (title) {
|
|
const titleLine = ` ${title} `;
|
|
const titlePadding = Math.max(0, boxWidth - titleLine.length);
|
|
result += `${indent}┌${titleLine}${"─".repeat(titlePadding)}┐\n`;
|
|
}
|
|
|
|
// Add top border (or title border)
|
|
if (!title) {
|
|
result += `${indent}${topBorder}\n`;
|
|
}
|
|
|
|
// Add content lines
|
|
for (const line of wrappedLines) {
|
|
const paddedLine = line.padEnd(maxLineLength);
|
|
result += `${indent}${sideBorder}${" ".repeat(padding)}${paddedLine}${" ".repeat(padding)}${sideBorder}\n`;
|
|
}
|
|
|
|
// Add bottom border
|
|
result += `${indent}${bottomBorder}`;
|
|
|
|
return result;
|
|
}
|
|
|
|
// /**
|
|
// * Create a simple two-column table for displaying key-value pairs
|
|
// * @param data - Array of [key, value] pairs
|
|
// * @param title - Optional table title
|
|
// * @param indent - Optional indentation string
|
|
// */
|
|
// export function printKeyValueTable(
|
|
// data: [string, string][],
|
|
// title?: string,
|
|
// indent?: string
|
|
// ): void {
|
|
// const rows: string[][] = [["Key", "Value"], ...data];
|
|
// const options: Parameters<typeof printTable>[1] = {};
|
|
// if (title !== undefined) options.title = title;
|
|
// if (indent !== undefined) options.indent = indent;
|
|
// printTable(rows, options);
|
|
// }
|
|
|
|
// /**
|
|
// * Create a path resolution table (specific use case)
|
|
// * @param pathData - Array of [location, resolvedPath] pairs
|
|
// * @param indent - Optional indentation string
|
|
// */
|
|
// export function printPathTable(pathData: [string, string][], indent?: string): void {
|
|
// const rows: string[][] = [["Location", "Resolved path"], ...pathData];
|
|
// const options: Parameters<typeof printTable>[1] = {};
|
|
// if (indent !== undefined) options.indent = indent;
|
|
// printTable(rows, options);
|
|
// }
|