Migrated to TypeScript.
This commit is contained in:
@@ -2,32 +2,55 @@
|
||||
|
||||
import { minimatch } from "minimatch";
|
||||
|
||||
import { loadPublicConfig } from "../index.js";
|
||||
import { getGraphClient } from "../graph/auth.js";
|
||||
import { login, logout } from "../azure/index.js";
|
||||
import { loadPublicConfig } from "../index.ts";
|
||||
import { getGraphClient } from "../graph/auth.ts";
|
||||
import { login, logout } from "../azure/index.ts";
|
||||
import {
|
||||
listApps,
|
||||
listAppPermissions,
|
||||
listAppPermissionsResolved,
|
||||
listAppGrants,
|
||||
listResourcePermissions,
|
||||
} from "../graph/app.js";
|
||||
import { readJsonFromStdin } from "./utils.js";
|
||||
} from "../graph/app.ts";
|
||||
import { readJsonFromStdin } from "./utils.ts";
|
||||
|
||||
function filterByPermissionName(rows, pattern) {
|
||||
type CommandValues = {
|
||||
[key: string]: string | boolean | undefined;
|
||||
resources?: string;
|
||||
"use-device-code"?: boolean;
|
||||
"no-browser"?: boolean;
|
||||
browser?: string;
|
||||
"browser-profile"?: string;
|
||||
all?: boolean;
|
||||
"display-name"?: string;
|
||||
"app-id"?: string;
|
||||
filter?: string;
|
||||
resolve?: boolean;
|
||||
};
|
||||
|
||||
type PermissionRow = {
|
||||
permissionValue?: string | null;
|
||||
permissionDisplayName?: string | null;
|
||||
};
|
||||
|
||||
type DisplayNameRow = {
|
||||
displayName?: string | null;
|
||||
};
|
||||
|
||||
function filterByPermissionName<T extends PermissionRow>(rows: T[], pattern: string): T[] {
|
||||
return rows.filter((item) =>
|
||||
minimatch(item.permissionValue ?? "", pattern, { nocase: true })
|
||||
|| minimatch(item.permissionDisplayName ?? "", pattern, { nocase: true })
|
||||
|| minimatch(item.permissionDisplayName ?? "", pattern, { nocase: true }),
|
||||
);
|
||||
}
|
||||
|
||||
function filterByDisplayName(rows, pattern) {
|
||||
function filterByDisplayName<T extends DisplayNameRow>(rows: T[], pattern: string): T[] {
|
||||
return rows.filter((item) =>
|
||||
minimatch(item.displayName ?? "", pattern, { nocase: true })
|
||||
minimatch(item.displayName ?? "", pattern, { nocase: true }),
|
||||
);
|
||||
}
|
||||
|
||||
async function getGraphClientFromPublicConfig() {
|
||||
async function getGraphClientFromPublicConfig(): Promise<{ client: any }> {
|
||||
const config = await loadPublicConfig();
|
||||
return getGraphClient({
|
||||
tenantId: config.tenantId,
|
||||
@@ -35,11 +58,11 @@ async function getGraphClientFromPublicConfig() {
|
||||
});
|
||||
}
|
||||
|
||||
async function runTableCommand() {
|
||||
async function runTableCommand(): Promise<unknown> {
|
||||
return readJsonFromStdin();
|
||||
}
|
||||
|
||||
async function runLoginCommand(values) {
|
||||
async function runLoginCommand(values: CommandValues): Promise<unknown> {
|
||||
const config = await loadPublicConfig();
|
||||
return login({
|
||||
tenantId: config.tenantId,
|
||||
@@ -52,7 +75,7 @@ async function runLoginCommand(values) {
|
||||
});
|
||||
}
|
||||
|
||||
async function runLogoutCommand(values) {
|
||||
async function runLogoutCommand(values: CommandValues): Promise<unknown> {
|
||||
const config = await loadPublicConfig();
|
||||
return logout({
|
||||
tenantId: config.tenantId,
|
||||
@@ -61,7 +84,7 @@ async function runLogoutCommand(values) {
|
||||
});
|
||||
}
|
||||
|
||||
async function runListAppsCommand(values) {
|
||||
async function runListAppsCommand(values: CommandValues): Promise<unknown> {
|
||||
const { client } = await getGraphClientFromPublicConfig();
|
||||
let result = await listApps(client, {
|
||||
displayName: values["display-name"],
|
||||
@@ -76,7 +99,7 @@ async function runListAppsCommand(values) {
|
||||
return result;
|
||||
}
|
||||
|
||||
async function runListAppPermissionsCommand(values) {
|
||||
async function runListAppPermissionsCommand(values: CommandValues): Promise<unknown> {
|
||||
if (!values["app-id"]) {
|
||||
throw new Error("--app-id is required for list-app-permissions");
|
||||
}
|
||||
@@ -91,7 +114,7 @@ async function runListAppPermissionsCommand(values) {
|
||||
return result;
|
||||
}
|
||||
|
||||
async function runListAppGrantsCommand(values) {
|
||||
async function runListAppGrantsCommand(values: CommandValues): Promise<unknown> {
|
||||
if (!values["app-id"]) {
|
||||
throw new Error("--app-id is required for list-app-grants");
|
||||
}
|
||||
@@ -100,7 +123,7 @@ async function runListAppGrantsCommand(values) {
|
||||
return listAppGrants(client, values["app-id"]);
|
||||
}
|
||||
|
||||
async function runListResourcePermissionsCommand(values) {
|
||||
async function runListResourcePermissionsCommand(values: CommandValues): Promise<unknown> {
|
||||
if (!values["app-id"] && !values["display-name"]) {
|
||||
throw new Error("--app-id or --display-name is required for list-resource-permissions");
|
||||
}
|
||||
@@ -119,7 +142,7 @@ async function runListResourcePermissionsCommand(values) {
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function runCommand(command, values) {
|
||||
export async function runCommand(command: string, values: CommandValues): Promise<unknown> {
|
||||
switch (command) {
|
||||
case "login":
|
||||
return runLoginCommand(values);
|
||||
@@ -2,15 +2,26 @@
|
||||
|
||||
import jmespath from "jmespath";
|
||||
|
||||
import { toMarkdownTable } from "../markdown.js";
|
||||
import { toMarkdownTable } from "../markdown.ts";
|
||||
|
||||
export function outputFiltered(object, query) {
|
||||
type HeaderSpec =
|
||||
| { mode: "auto" }
|
||||
| { mode: "original" }
|
||||
| { mode: "list"; labels: string[] }
|
||||
| { mode: "map"; map: Record<string, string> };
|
||||
|
||||
type OutputFormat = "json" | "table" | "alignedtable" | "prettytable" | "tsv";
|
||||
|
||||
type Scalar = string | number | boolean | null | undefined;
|
||||
type ScalarRow = Record<string, Scalar>;
|
||||
|
||||
export function outputFiltered(object: unknown, query?: string): unknown {
|
||||
return query
|
||||
? jmespath.search(object, query)
|
||||
: object;
|
||||
}
|
||||
|
||||
export function parseHeaderSpec(headerValue) {
|
||||
export function parseHeaderSpec(headerValue?: string): HeaderSpec {
|
||||
if (!headerValue) {
|
||||
return { mode: "auto" };
|
||||
}
|
||||
@@ -30,7 +41,7 @@ export function parseHeaderSpec(headerValue) {
|
||||
return { mode: "list", labels: parts };
|
||||
}
|
||||
|
||||
const map = {};
|
||||
const map: Record<string, string> = {};
|
||||
for (const part of parts) {
|
||||
const idx = part.indexOf(":");
|
||||
if (idx < 0) {
|
||||
@@ -47,7 +58,7 @@ export function parseHeaderSpec(headerValue) {
|
||||
return { mode: "map", map };
|
||||
}
|
||||
|
||||
export function normalizeOutputFormat(outputValue) {
|
||||
export function normalizeOutputFormat(outputValue?: string): OutputFormat {
|
||||
if (outputValue == null) {
|
||||
return "json";
|
||||
}
|
||||
@@ -66,16 +77,20 @@ export function normalizeOutputFormat(outputValue) {
|
||||
throw new Error("--output must be one of: table|t, alignedtable|at, prettytable|pt, tsv");
|
||||
}
|
||||
|
||||
function getScalarRowsAndHeaders(value) {
|
||||
let rows;
|
||||
function isScalar(value: unknown): value is Scalar {
|
||||
return value == null || typeof value !== "object";
|
||||
}
|
||||
|
||||
function getScalarRowsAndHeaders(value: unknown): { headers: string[]; rows: ScalarRow[] } {
|
||||
let rows: Array<Record<string, unknown>>;
|
||||
if (Array.isArray(value)) {
|
||||
rows = value.map((item) =>
|
||||
item && typeof item === "object" && !Array.isArray(item)
|
||||
? item
|
||||
? item as Record<string, unknown>
|
||||
: { value: item },
|
||||
);
|
||||
} else if (value && typeof value === "object") {
|
||||
rows = [value];
|
||||
rows = [value as Record<string, unknown>];
|
||||
} else {
|
||||
rows = [{ value }];
|
||||
}
|
||||
@@ -89,10 +104,7 @@ function getScalarRowsAndHeaders(value) {
|
||||
|
||||
const headers = [...new Set(rows.flatMap((row) => Object.keys(row)))]
|
||||
.filter((key) =>
|
||||
rows.every((row) => {
|
||||
const v = row[key];
|
||||
return v == null || typeof v !== "object";
|
||||
}),
|
||||
rows.every((row) => isScalar(row[key])),
|
||||
);
|
||||
|
||||
if (headers.length === 0) {
|
||||
@@ -102,10 +114,20 @@ function getScalarRowsAndHeaders(value) {
|
||||
};
|
||||
}
|
||||
|
||||
return { headers, rows };
|
||||
const scalarRows: ScalarRow[] = rows.map((row) => {
|
||||
const result: ScalarRow = {};
|
||||
for (const [key, rowValue] of Object.entries(row)) {
|
||||
if (isScalar(rowValue)) {
|
||||
result[key] = rowValue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
return { headers, rows: scalarRows };
|
||||
}
|
||||
|
||||
function toTsv(value) {
|
||||
function toTsv(value: unknown): string {
|
||||
const { headers, rows } = getScalarRowsAndHeaders(value);
|
||||
const lines = rows.map((row) =>
|
||||
headers
|
||||
@@ -115,22 +137,24 @@ function toTsv(value) {
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
export function omitPermissionGuidColumns(value) {
|
||||
export function omitPermissionGuidColumns(value: unknown): unknown {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((item) => omitPermissionGuidColumns(item));
|
||||
}
|
||||
if (!value || typeof value !== "object") {
|
||||
return value;
|
||||
}
|
||||
const { resourceAppId, permissionId, ...rest } = value;
|
||||
const { resourceAppId, permissionId, ...rest } = value as Record<string, unknown>;
|
||||
void resourceAppId;
|
||||
void permissionId;
|
||||
return rest;
|
||||
}
|
||||
|
||||
export async function readJsonFromStdin() {
|
||||
const input = await new Promise((resolve, reject) => {
|
||||
export async function readJsonFromStdin(): Promise<unknown> {
|
||||
const input = await new Promise<string>((resolve, reject) => {
|
||||
let data = "";
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", (chunk) => {
|
||||
process.stdin.on("data", (chunk: string) => {
|
||||
data += chunk;
|
||||
});
|
||||
process.stdin.on("end", () => {
|
||||
@@ -145,13 +169,18 @@ export async function readJsonFromStdin() {
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(input);
|
||||
return JSON.parse(input) as unknown;
|
||||
} catch (err) {
|
||||
throw new Error(`Invalid JSON input on stdin: ${err.message}`);
|
||||
throw new Error(`Invalid JSON input on stdin: ${(err as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function renderOutput(command, output, outputFormat, headerSpec) {
|
||||
export function renderOutput(
|
||||
command: string,
|
||||
output: unknown,
|
||||
outputFormat: OutputFormat,
|
||||
headerSpec: HeaderSpec,
|
||||
): void {
|
||||
if (outputFormat === "tsv") {
|
||||
console.log(toTsv(output));
|
||||
return;
|
||||
Reference in New Issue
Block a user