import * as comma from "add-commas"; import * as dotted from "dotted"; import * as markdownTable from "markdown-table"; import * as scanner from "./scanner"; export var help = "Create a summary table of requested fields"; export function args(argv) { return argv .help("help") .alias('f', 'fields') .array('fields') .default('fields', ['_basename', 'title']) .alias('t', 'titles') .array('titles') .default('table-start', '| ') .default('table-end', ' |') .default('table-delimiter', ' | ') .boolean('table-rule') .default('table-rule', true) .boolean('table-header') .default('table-header', true) .default('list-delimiter', ', ') .alias('o', 'output') .default('output', '-') .default('prefix', '') .demand(1) .argv; } export function run(argv) { var files = argv._.splice(1); var data = scanner.scanFiles(argv, files); render(argv, data); } export function render(argv, data) { // Parse out the options and fields from the sources. var columns = parse(argv, argv.titles, argv.fields); // Create the header row. var header = []; for (var column of columns) { header.push(column.header); } // Create the initial table with the header. var table = [header]; // Loop through the results and get the fields we need to display. var totals = ["Totals"]; for (var metadata of data) { // Add the row to the table. var row = []; table.push(row); // Loop through our fields and retrieve each one. for (var index = 0; index < columns.length; index++) { // Grab the value, even if nested. var column = columns[index]; var value = dotted.getNested(metadata, column.ref); // If we have a list, format it with spaces. if (Array.isArray(value)) { value = value.join(argv.listDelimiter); } // If we have totals, then add them. if (column.total) { totals[index] = totals[index] ? parseInt(totals[index]) : 0; totals[index] += parseInt(value); } // If we have commas requested, then add those. if (column.comma) { value = comma(value); } // Add the final row to the table. row.push(value); } } // If we have totals, then add it at the bottom. if (totals.length > 1) { for (var index = 0; index < columns.length && index < totals.length; index++) { var column = columns[index]; if (column.comma) { totals[index] = comma(totals[index]); } } table.push(totals); } // Format the results in a table. var formattedTable = markdownTable(table, { align: columns.map(c => c.align), delimiter: argv.tableDelimiter, start: argv.tableStart, end: argv.tableEnd, rule: argv.tableRule }); // If we don't want the header row, strip off the first line. if (!argv.tableHeader) { formattedTable = formattedTable.substring(formattedTable.indexOf("\n") + 1); } console.log(formattedTable); } class Column { ref: string; header: string; align: string = "l"; comma: boolean = false; total: boolean = false; public set(field, header) { this.ref = this.parseSpecifier(field); this.header = this.parseSpecifier(header ? header : field); } private parseSpecifier(spec): string { // See if we have options. var m = spec.match(/^(.*?):([lcr\.st]+)?$/); if (m) { // We have a match, so put the first part as the specifier. spec = m[1]; for (var s of m[2]) { switch (s) { case 'c': case 'l': case 'r': case '.': this.align = s; break; case 's': this.comma = true; break; case 't': this.total = true; break; } } } // Return the resulting specifier. return spec; } } function parse(argv, titles, fields): Column[] { var columns: Column[] = []; if (!titles) titles =[]; for (var index = 0; index < fields.length; index++) { var column = new Column(); column.set( fields[index], titles.length >= index ? titles[index] : undefined); columns.push(column); } return columns; } /* Notes Comma-separated list of lists. I like spaces. */