// SPDX-License-Identifier: MIT type Scalar = string | number | boolean | null | undefined; type ScalarRow = Record; type HeaderSpec = | { mode: "default" } | { mode: "auto" } | { mode: "original" } | { mode: "list"; labels: string[] } | { mode: "map"; map: Record }; function formatCell(value: unknown): string { const text = value == null ? "" : String(value); return text.replaceAll("|", "\\|").replaceAll("\n", "
"); } function isGuid(value: unknown): value is string { return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value); } function toAutoHeaderLabel(key: string): string { const withSpaces = String(key) .replace(/[_-]+/g, " ") .replace(/([a-z0-9])([A-Z])/g, "$1 $2") .replace(/\s+/g, " ") .trim(); return withSpaces .split(" ") .filter(Boolean) .map((part) => part[0].toUpperCase() + part.slice(1)) .join(" "); } function isScalar(value: unknown): value is Scalar { return value == null || typeof value !== "object"; } function getScalarRowsAndHeaders(value: unknown): { headers: string[]; rows: ScalarRow[] } { let rows: Array>; if (Array.isArray(value)) { rows = value.map((item) => item && typeof item === "object" && !Array.isArray(item) ? item as Record : { value: item }, ); } else if (value && typeof value === "object") { rows = [value as Record]; } else { rows = [{ value }]; } if (rows.length === 0) { return { headers: ["result"], rows: [{ result: "" }], }; } const headers = [...new Set(rows.flatMap((row) => Object.keys(row)))] .filter((key) => rows.every((row) => isScalar(row[key])), ); if (headers.length === 0) { return { headers: ["result"], rows: [{ result: "" }], }; } const scalarRows: ScalarRow[] = rows.map((row) => { const result: ScalarRow = {}; for (const [key, rowValue] of Object.entries(row)) { if (isScalar(rowValue)) { result[key] = rowValue; } } return result; }); return { headers, rows: scalarRows }; } export function toMarkdownTable( value: unknown, pretty = false, quoteGuids = false, headerSpec: HeaderSpec = { mode: "default" }, ): string { const { headers, rows } = getScalarRowsAndHeaders(value); const headerDefinitions = headers.map((key, idx) => { let label = key; if (headerSpec.mode === "auto") { label = toAutoHeaderLabel(key); } else if (headerSpec.mode === "list" && headerSpec.labels[idx]) { label = headerSpec.labels[idx]; } else if (headerSpec.mode === "map" && headerSpec.map[key]) { label = headerSpec.map[key]; } return { key, label }; }); const renderCell = (raw: Scalar): string => { const text = formatCell(raw); return quoteGuids && isGuid(raw) ? `\`${text}\`` : text; }; if (!pretty) { const headerLine = `| ${headerDefinitions.map((h) => h.label).join(" | ")} |`; const separatorLine = `| ${headerDefinitions.map(() => "---").join(" | ")} |`; const rowLines = rows.map((row) => `| ${headerDefinitions.map((h) => formatCell(row[h.key])).join(" | ")} |`, ); return [headerLine, separatorLine, ...rowLines].join("\n"); } const widths = headerDefinitions.map((header, idx) => Math.max( header.label.length, ...rows.map((row) => renderCell(row[headerDefinitions[idx].key]).length), ) ); const renderRow = (values: string[]): string => `| ${values.map((v, idx) => v.padEnd(widths[idx], " ")).join(" | ")} |`; const headerLine = renderRow(headerDefinitions.map((h) => h.label)); const separatorLine = `|-${widths.map((w) => "-".repeat(w)).join("-|-")}-|`; const rowLines = rows.map((row) => renderRow(headerDefinitions.map((header) => renderCell(row[header.key]))), ); return [headerLine, separatorLine, ...rowLines].join("\n"); }