feat(table): add header spec support and explicit auto mode

This commit is contained in:
2026-02-08 14:17:20 +01:00
parent 861b509b15
commit 2661e4dc5b
2 changed files with 85 additions and 12 deletions

View File

@@ -22,7 +22,7 @@ Commands:
list-apps [--display-name|-n <name>]
list-app-permissions --app-id|-i <appId> [--resolve|-r] [--short|-s]
list-app-grants --app-id|-i <appId>
table [--pretty|-p] [--quote-guids|-g]
table [--pretty|-p] [--quote-guids|-g] [--header|-H <spec|auto|a>]
Options:
-n, --display-name <name> Filter apps by exact display name
@@ -32,6 +32,7 @@ Options:
-q, --query <jmespath> Filter output JSON using JMESPath
-p, --pretty Use normalized column widths for Markdown table output
-g, --quote-guids In pretty tables, wrap GUID values in backticks
-H, --header <value> Header mode/spec: auto|a OR "col1, col2" OR "key1: Label 1, key2: Label 2"
-o, --output <format> Output format: json|table|prettytable (default: json)
-h, --help Show this help message`;
}
@@ -42,6 +43,40 @@ function outputFiltered(object, query) {
: object;
}
function parseHeaderSpec(headerValue) {
if (!headerValue) {
return { mode: "default" };
}
const raw = headerValue.trim();
if (raw === "" || raw.toLowerCase() === "auto" || raw.toLowerCase() === "a") {
return { mode: "auto" };
}
const parts = raw.split(",").map((p) => p.trim()).filter(Boolean);
const isMap = parts.some((p) => p.includes(":"));
if (!isMap) {
return { mode: "list", labels: parts };
}
const map = {};
for (const part of parts) {
const idx = part.indexOf(":");
if (idx < 0) {
throw new Error(`Invalid --header mapping segment: '${part}'`);
}
const key = part.slice(0, idx).trim();
const label = part.slice(idx + 1).trim();
if (!key || !label) {
throw new Error(`Invalid --header mapping segment: '${part}'`);
}
map[key] = label;
}
return { mode: "map", map };
}
function omitPermissionGuidColumns(value) {
if (Array.isArray(value)) {
return value.map((item) => omitPermissionGuidColumns(item));
@@ -97,6 +132,7 @@ async function main() {
query: { type: "string", short: "q" },
pretty: { type: "boolean", short: "p" },
"quote-guids": { type: "boolean", short: "g" },
header: { type: "string", short: "H" },
output: { type: "string", short: "o" },
},
strict: true,
@@ -165,12 +201,23 @@ async function main() {
const output = command === "list-app-permissions" && values.short
? omitPermissionGuidColumns(filtered)
: filtered;
const headerSpec = parseHeaderSpec(values.header);
if (command === "table") {
console.log(toMarkdownTable(output, Boolean(values.pretty), Boolean(values["quote-guids"])));
console.log(toMarkdownTable(
output,
Boolean(values.pretty),
Boolean(values["quote-guids"]),
headerSpec,
));
} else if (outputFormat === "prettytable") {
console.log(toMarkdownTable(output, true, Boolean(values["quote-guids"])));
console.log(toMarkdownTable(
output,
true,
Boolean(values["quote-guids"]),
headerSpec,
));
} else if (outputFormat === "table") {
console.log(toMarkdownTable(output));
console.log(toMarkdownTable(output, false, false, headerSpec));
} else {
console.log(JSON.stringify(output, null, 2));
}