libyear
Version:
A simple measure of software dependency freshness
61 lines (60 loc) • 2.25 kB
JavaScript
import { stripVTControlCharacters, styleText } from "node:util";
import terminalLink from "terminal-link";
const compact = process.stdout.columns < 110;
const cellSeparator = compact ? " " : " │ ";
const rowStart = compact ? "" : "│ ";
const rowEnd = compact ? "" : " │";
const styleCell = (cell, length) => {
const { format, href, value } = typeof cell === "object"
? cell
: { value: cell };
let text = String(value);
if (href) {
text = terminalLink(text, href, { fallback: false });
}
const maxLength = length + (text.length - stripVTControlCharacters(text).length);
switch (typeof value) {
case "number":
text = text.padStart(maxLength, " ");
break;
default:
text = text.padEnd(maxLength, " ");
}
if (format) {
text = styleText(format, text);
}
return text;
};
const styleRow = (cells) => `${rowStart}${cells.join(cellSeparator)}${rowEnd}`;
const styleBodyRow = (data, schema) => styleRow(Object.entries(data).map(([key, cell]) => styleCell(cell, schema[key] ?? 0)));
const styleHeaderRow = (schema) => styleRow(Object.entries(schema).map(([key, value]) => key.padEnd(value, " ")));
const styleDivider = (type, schema) => {
const spacer = "─";
const [start, middle, end] = compact
? ["", "─", ""]
: {
top: ["┌", "┬", "┐"],
middle: ["├", "┼", "┤"],
bottom: ["└", "┴", "┘"],
}[type];
return `${start}${Object.values(schema)
.map((length) => spacer.repeat(length + (cellSeparator.length - 1)))
.join(middle)}${end}`;
};
export const styleTable = (data) => {
const schema = {};
data.forEach((row) => {
Object.entries(row).forEach(([key, cell]) => {
schema[key] = Math.max(schema[key] ?? 0, key.length, String(cell?.value ?? cell).length);
});
});
return [
styleDivider("top", schema),
styleHeaderRow(schema),
styleDivider("middle", schema),
...data
.map((row) => styleBodyRow(row, schema))
.toSpliced(data.length - 1, 0, styleDivider("middle", schema)),
styleDivider("bottom", schema),
].join("\n");
};