| 2 | // SPDX-License-Identifier: GPL-3.0 |
| 3 | |
| 4 | export function jsonToTable<T extends Record<string, any>>(input: T[]): string { |
| 5 | if (!input || input.length === 0) { |
| 6 | return ''; |
| 7 | } |
| 8 | |
| 9 | // Extract all unique keys from all objects |
| 10 | const keys = Array.from(new Set(input.flatMap((item) => Object.keys(item)))); |
| 11 | |
| 12 | const toString = (value: any): string => { |
| 13 | if (value instanceof Date) { |
| 14 | return value.toLocaleString(); |
| 15 | } |
| 16 | if (typeof value === 'object') { |
| 17 | return JSON.stringify(value); |
| 18 | } |
| 19 | return String(value); |
| 20 | }; |
| 21 | |
| 22 | if (keys.length === 0) { |
| 23 | return ''; |
| 24 | } |
| 25 | |
| 26 | // Get the maximum width needed for each column |
| 27 | const columnWidths: Record<string, number> = {}; |
| 28 | keys.forEach((key) => { |
| 29 | // Initialize with header length |
| 30 | columnWidths[key] = key.length; |
| 31 | |
| 32 | // Check each value's string length and update if longer |
| 33 | input.forEach((item) => { |
| 34 | if (item[key] !== undefined && item[key] !== null) { |
| 35 | const valueLength = toString(item[key]).length; |
| 36 | if (valueLength > columnWidths[key]) { |
| 37 | columnWidths[key] = valueLength; |
| 38 | } |
| 39 | } |
| 40 | }); |
| 41 | }); |
| 42 | |
| 43 | // Create header row |
| 44 | const header = keys.map((key) => key.padEnd(columnWidths[key])).join(' | '); |
| 45 | |
| 46 | // Create separator row |
| 47 | const separator = keys.map((key) => '-'.repeat(columnWidths[key])).join('-|-'); |
| 48 | |
| 49 | // Create data rows |
| 50 | const rows = input.map((item) => { |
| 51 | return keys |
| 52 | .map((key) => { |
| 53 | const value = item[key] === undefined || item[key] === null ? '' : toString(item[key]); |
| 54 | return value.padEnd(columnWidths[key]); |
| 55 | }) |
| 56 | .join(' | '); |
| 57 | }); |
| 58 | |
| 59 | // Combine all rows into the final table |
| 60 | return [header, separator, ...rows].join('\n'); |
| 61 | } |