feat(cli): add stdin table command and pretty rendering option
This commit is contained in:
58
src/cli.js
58
src/cli.js
@@ -15,11 +15,13 @@ Commands:
|
|||||||
list-apps [--display-name <name>]
|
list-apps [--display-name <name>]
|
||||||
list-app-permissions --app-id <appId>
|
list-app-permissions --app-id <appId>
|
||||||
list-app-grants --app-id <appId>
|
list-app-grants --app-id <appId>
|
||||||
|
table [--pretty]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--display-name <name> Filter apps by exact display name
|
--display-name <name> Filter apps by exact display name
|
||||||
--app-id <appId> Application (client) ID
|
--app-id <appId> Application (client) ID
|
||||||
--query <jmespath> Filter output JSON using JMESPath
|
--query <jmespath> Filter output JSON using JMESPath
|
||||||
|
--pretty Use normalized column widths for Markdown table output
|
||||||
--output <format> Output format: json|table|prettytable (default: json)
|
--output <format> Output format: json|table|prettytable (default: json)
|
||||||
-h, --help Show this help message`;
|
-h, --help Show this help message`;
|
||||||
}
|
}
|
||||||
@@ -30,6 +32,31 @@ function outputFiltered(object, query) {
|
|||||||
: object;
|
: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function readJsonFromStdin() {
|
||||||
|
const input = await new Promise((resolve, reject) => {
|
||||||
|
let data = "";
|
||||||
|
process.stdin.setEncoding("utf8");
|
||||||
|
process.stdin.on("data", (chunk) => {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
process.stdin.on("end", () => {
|
||||||
|
resolve(data);
|
||||||
|
});
|
||||||
|
process.stdin.on("error", (err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!input.trim()) {
|
||||||
|
throw new Error("No JSON input provided on stdin");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(input);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`Invalid JSON input on stdin: ${err.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const argv = process.argv.slice(2);
|
const argv = process.argv.slice(2);
|
||||||
const command = argv[0];
|
const command = argv[0];
|
||||||
@@ -45,6 +72,7 @@ async function main() {
|
|||||||
"display-name": { type: "string" },
|
"display-name": { type: "string" },
|
||||||
"app-id": { type: "string" },
|
"app-id": { type: "string" },
|
||||||
query: { type: "string" },
|
query: { type: "string" },
|
||||||
|
pretty: { type: "boolean" },
|
||||||
output: { type: "string" },
|
output: { type: "string" },
|
||||||
},
|
},
|
||||||
strict: true,
|
strict: true,
|
||||||
@@ -60,37 +88,57 @@ async function main() {
|
|||||||
throw new Error("--output must be one of: json, table, prettytable");
|
throw new Error("--output must be one of: json, table, prettytable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let result;
|
||||||
|
switch (command) {
|
||||||
|
case "table":
|
||||||
|
result = await readJsonFromStdin();
|
||||||
|
break;
|
||||||
|
case "list-apps":
|
||||||
|
{
|
||||||
const config = await loadPublicConfig();
|
const config = await loadPublicConfig();
|
||||||
const { client } = await getGraphClient({
|
const { client } = await getGraphClient({
|
||||||
tenantId: config.tenantId,
|
tenantId: config.tenantId,
|
||||||
clientId: config.clientId,
|
clientId: config.clientId,
|
||||||
});
|
});
|
||||||
|
|
||||||
let result;
|
|
||||||
switch (command) {
|
|
||||||
case "list-apps":
|
|
||||||
result = await listApps(client, {
|
result = await listApps(client, {
|
||||||
displayName: values["display-name"],
|
displayName: values["display-name"],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "list-app-permissions":
|
case "list-app-permissions":
|
||||||
if (!values["app-id"]) {
|
if (!values["app-id"]) {
|
||||||
throw new Error("--app-id is required for list-app-permissions");
|
throw new Error("--app-id is required for list-app-permissions");
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
const config = await loadPublicConfig();
|
||||||
|
const { client } = await getGraphClient({
|
||||||
|
tenantId: config.tenantId,
|
||||||
|
clientId: config.clientId,
|
||||||
|
});
|
||||||
result = await listAppPermissions(client, values["app-id"]);
|
result = await listAppPermissions(client, values["app-id"]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "list-app-grants":
|
case "list-app-grants":
|
||||||
if (!values["app-id"]) {
|
if (!values["app-id"]) {
|
||||||
throw new Error("--app-id is required for list-app-grants");
|
throw new Error("--app-id is required for list-app-grants");
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
const config = await loadPublicConfig();
|
||||||
|
const { client } = await getGraphClient({
|
||||||
|
tenantId: config.tenantId,
|
||||||
|
clientId: config.clientId,
|
||||||
|
});
|
||||||
result = await listAppGrants(client, values["app-id"]);
|
result = await listAppGrants(client, values["app-id"]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown command: ${command}`);
|
throw new Error(`Unknown command: ${command}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const filtered = outputFiltered(result, values.query);
|
const filtered = outputFiltered(result, values.query);
|
||||||
if (outputFormat === "prettytable") {
|
if (command === "table") {
|
||||||
|
console.log(toMarkdownTable(filtered, Boolean(values.pretty)));
|
||||||
|
} else if (outputFormat === "prettytable") {
|
||||||
console.log(toMarkdownTable(filtered, true));
|
console.log(toMarkdownTable(filtered, true));
|
||||||
} else if (outputFormat === "table") {
|
} else if (outputFormat === "table") {
|
||||||
console.log(toMarkdownTable(filtered));
|
console.log(toMarkdownTable(filtered));
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Client } from "@microsoft/microsoft-graph-client";
|
|||||||
* @param { Object } options - Options for authentication
|
* @param { Object } options - Options for authentication
|
||||||
* @param { string } options.tenantId - The Azure AD tenant ID
|
* @param { string } options.tenantId - The Azure AD tenant ID
|
||||||
* @param { string } options.clientId - The Azure AD client ID
|
* @param { string } options.clientId - The Azure AD client ID
|
||||||
* @returns { Object } An object containing the Graph API token and client
|
* @returns { Promise<{ graphApiToken: Object, client: Object }> } An object containing the Graph API token and client
|
||||||
*/
|
*/
|
||||||
export async function getGraphClient({ tenantId, clientId }) {
|
export async function getGraphClient({ tenantId, clientId }) {
|
||||||
const graphApiToken = await loginInteractive({
|
const graphApiToken = await loginInteractive({
|
||||||
|
|||||||
Reference in New Issue
Block a user