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