feat(cli): add resolve output and improve table formatting options

This commit is contained in:
2026-02-08 13:44:52 +01:00
parent 61111cc082
commit a03af7d5f3
2 changed files with 33 additions and 21 deletions

View File

@@ -19,18 +19,19 @@ function usage() {
return `Usage: sk-az-tools <command> [options] return `Usage: sk-az-tools <command> [options]
Commands: Commands:
list-apps [--display-name <name>] list-apps [--display-name|-n <name>]
list-app-permissions --app-id <appId> [--resolve] list-app-permissions --app-id|-i <appId> [--resolve|-r]
list-app-grants --app-id <appId> list-app-grants --app-id|-i <appId>
table [--pretty] table [--pretty|-p] [--quote-guids|-g]
Options: Options:
--display-name <name> Filter apps by exact display name -n, --display-name <name> Filter apps by exact display name
--app-id <appId> Application (client) ID -i, --app-id <appId> Application (client) ID
--resolve Resolve permission GUIDs to human-readable values -r, --resolve Resolve permission GUIDs to human-readable values
--query <jmespath> Filter output JSON using JMESPath -q, --query <jmespath> Filter output JSON using JMESPath
--pretty Use normalized column widths for Markdown table output -p, --pretty Use normalized column widths for Markdown table output
--output <format> Output format: json|table|prettytable (default: json) -g, --quote-guids In pretty tables, wrap GUID values in backticks
-o, --output <format> Output format: json|table|prettytable (default: json)
-h, --help Show this help message`; -h, --help Show this help message`;
} }
@@ -77,12 +78,13 @@ async function main() {
args: argv.slice(1), args: argv.slice(1),
options: { options: {
help: { type: "boolean", short: "h" }, help: { type: "boolean", short: "h" },
"display-name": { type: "string" }, "display-name": { type: "string", short: "n" },
"app-id": { type: "string" }, "app-id": { type: "string", short: "i" },
resolve: { type: "boolean" }, resolve: { type: "boolean", short: "r" },
query: { type: "string" }, query: { type: "string", short: "q" },
pretty: { type: "boolean" }, pretty: { type: "boolean", short: "p" },
output: { type: "string" }, "quote-guids": { type: "boolean", short: "g" },
output: { type: "string", short: "o" },
}, },
strict: true, strict: true,
allowPositionals: false, allowPositionals: false,
@@ -148,9 +150,9 @@ async function main() {
const filtered = outputFiltered(result, values.query); const filtered = outputFiltered(result, values.query);
if (command === "table") { if (command === "table") {
console.log(toMarkdownTable(filtered, Boolean(values.pretty))); console.log(toMarkdownTable(filtered, Boolean(values.pretty), Boolean(values["quote-guids"])));
} else if (outputFormat === "prettytable") { } else if (outputFormat === "prettytable") {
console.log(toMarkdownTable(filtered, true)); console.log(toMarkdownTable(filtered, true, Boolean(values["quote-guids"])));
} else if (outputFormat === "table") { } else if (outputFormat === "table") {
console.log(toMarkdownTable(filtered)); console.log(toMarkdownTable(filtered));
} else { } else {

View File

@@ -7,6 +7,11 @@ function formatCell(value) {
return text.replaceAll("|", "\\|").replaceAll("\n", "<br>"); return text.replaceAll("|", "\\|").replaceAll("\n", "<br>");
} }
function isGuid(value) {
return typeof value === "string"
&& /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
}
function getScalarRowsAndHeaders(value) { function getScalarRowsAndHeaders(value) {
let rows; let rows;
if (Array.isArray(value)) { if (Array.isArray(value)) {
@@ -46,8 +51,13 @@ function getScalarRowsAndHeaders(value) {
return { headers, rows }; return { headers, rows };
} }
export function toMarkdownTable(value, pretty = false) { export function toMarkdownTable(value, pretty = false, quoteGuids = false) {
const { headers, rows } = getScalarRowsAndHeaders(value); const { headers, rows } = getScalarRowsAndHeaders(value);
const renderCell = (raw) => {
const text = formatCell(raw);
return quoteGuids && isGuid(raw) ? `\`${text}\`` : text;
};
if (!pretty) { if (!pretty) {
const headerLine = `| ${headers.join(" | ")} |`; const headerLine = `| ${headers.join(" | ")} |`;
const separatorLine = `| ${headers.map(() => "---").join(" | ")} |`; const separatorLine = `| ${headers.map(() => "---").join(" | ")} |`;
@@ -60,7 +70,7 @@ export function toMarkdownTable(value, pretty = false) {
const widths = headers.map((header, idx) => const widths = headers.map((header, idx) =>
Math.max( Math.max(
header.length, header.length,
...rows.map((row) => formatCell(row[headers[idx]]).length), ...rows.map((row) => renderCell(row[headers[idx]]).length),
) )
); );
@@ -70,7 +80,7 @@ export function toMarkdownTable(value, pretty = false) {
const headerLine = renderRow(headers); const headerLine = renderRow(headers);
const separatorLine = `|-${widths.map((w) => "-".repeat(w)).join("-|-")}-|`; const separatorLine = `|-${widths.map((w) => "-".repeat(w)).join("-|-")}-|`;
const rowLines = rows.map((row) => const rowLines = rows.map((row) =>
renderRow(headers.map((header) => formatCell(row[header]))) renderRow(headers.map((header) => renderCell(row[header])))
); );
return [headerLine, separatorLine, ...rowLines].join("\n"); return [headerLine, separatorLine, ...rowLines].join("\n");