All files / owid-grapher/coreTable CoreTablePrinters.ts

94.29% Statements 66/70
46.67% Branches 7/15
100% Functions 3/3
94.29% Lines 66/70

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 1101x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x   3x 1x 1x 1x 1x 3x 9x 9x 9x 9x 9x 9x 9x 9x 9x 3x 1x 1x 1x 1x 3x 3x     1x 1x 12x 12x 12x 12x 12x 12x 12x 12x 12x 1x 1x   1x 1x 1x 1x 1x 1x 1x 1x                                                                                
type CellFormatter = (str: string, rowIndex: number, colIndex: number) => any
 
export interface AlignedTextTableOptions {
    alignRight?: boolean
    maxCharactersPerColumn?: number
    maxCharactersPerLine?: number
}
 
// Output a pretty table for consles
export const toAlignedTextTable = (
    headerSlugs: string[],
    rows: any[],
    options: AlignedTextTableOptions = {}
): string => {
    const {
        alignRight = true,
        maxCharactersPerColumn = 20,
        maxCharactersPerLine = 80,
    } = options
 
    // Set initial column widths
    const colWidths = headerSlugs.map((slug) =>
        slug.length > maxCharactersPerColumn
            ? maxCharactersPerColumn
            : slug.length
    )
 
    // Expand column widths if needed
    rows.forEach((row) => {
        headerSlugs.forEach((slug, index) => {
            const cellValue = row[slug]
            if (!cellValue) return
            const length = cellValue.toString().length
            if (length > colWidths[index])
                colWidths[index] =
                    length > maxCharactersPerColumn
                        ? maxCharactersPerColumn
                        : length
        })
    })
 
    // Drop columns if they exceed the max line width
    let runningWidth = 0
    const finalHeaderSlugs = headerSlugs.filter((slug, index) => {
        runningWidth = runningWidth + colWidths[index]
        if (runningWidth <= maxCharactersPerLine) return true
        return false
    })
 
    const cellFn = (cellText = "", row: number, col: number) => {
        const width = colWidths[col]
        // Strip newlines in fixedWidth output
        const cellValue = cellText?.toString().replace(/\n/g, "\\n") || ""
        const cellLength = cellValue.length
        if (cellLength > width) return cellValue.substr(0, width - 3) + "..."
 
        const padding = " ".repeat(width - cellLength)
        return alignRight ? padding + cellValue : cellValue + padding
    }
    return (
        (finalHeaderSlugs.length !== headerSlugs.length
            ? `Showing ${finalHeaderSlugs.length} of ${headerSlugs.length} columns\n`
            : "") + toDelimited(" ", finalHeaderSlugs, rows, cellFn)
    )
}
 
export const toMarkdownTable = (
    slugs: string[],
    rows: any[],
    formatFn?: CellFormatter
): string =>
    [
        slugs,
        slugs.map(() => "-"),
        ...rows.map((row) => slugs.map((slug) => row[slug])),
    ]
        .map((row, rowIndex) => {
            const formattedValues = row.map((val, colIndex) =>
                formatFn ? formatFn(val, rowIndex, colIndex) : val
            )
            return `|${formattedValues.join("|")}|`
        })
        .join("\n")
 
export const toDelimited = (
    delimiter: string,
    columnSlugs: string[],
    rows: any[],
    cellFn?: CellFormatter,
    rowDelimiter = "\n"
): string => {
    const skipHeaderRow = 1
    const header = columnSlugs.map((columnName, index) =>
        cellFn ? cellFn(columnName, 0, index) : columnName
    )
    const formattedRows = rows.map((row, rowNumber) =>
        columnSlugs.map((slug, columnIndex) =>
            cellFn
                ? cellFn(row[slug], rowNumber + skipHeaderRow, columnIndex)
                : row[slug]
        )
    )
 
    return (
        header.join(delimiter) +
        rowDelimiter +
        formattedRows.map((row) => row.join(delimiter)).join(rowDelimiter)
    )
}