hyapp-admin-platform/scripts/generate-api-client.mjs
2026-05-02 13:02:57 +08:00

103 lines
3.6 KiB
JavaScript

import { mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const contractPath = path.join(rootDir, "contracts/admin-openapi.json");
const outputPath = path.join(rootDir, "src/shared/api/generated/endpoints.ts");
const methods = ["get", "post", "put", "patch", "delete"];
const contract = JSON.parse(await readFile(contractPath, "utf8"));
const serverUrl = contract.servers?.[0]?.url || "";
const apiPathPrefix = serverUrl.startsWith("/api") ? serverUrl.slice("/api".length) : serverUrl;
const endpoints = [];
for (const [openapiPath, pathItem] of Object.entries(contract.paths || {})) {
for (const method of methods) {
const operation = pathItem[method];
if (!operation?.operationId) {
continue;
}
const permissions = Array.isArray(operation["x-permissions"])
? operation["x-permissions"]
: operation["x-permission"]
? [operation["x-permission"]]
: [];
endpoints.push({
method: method.toUpperCase(),
operationId: operation.operationId,
path: `${apiPathPrefix}${openapiPath}`,
permission: operation["x-permission"] || permissions[0],
permissions
});
}
}
endpoints.sort((left, right) => left.operationId.localeCompare(right.operationId));
const operationLines = endpoints.map((endpoint) => {
return ` ${endpoint.operationId}: ${JSON.stringify(endpoint.operationId)}`;
});
const endpointLines = endpoints.map((endpoint) => {
const permission = endpoint.permission ? `,\n permission: ${JSON.stringify(endpoint.permission)}` : "";
const permissions = endpoint.permissions.length ? `,\n permissions: ${JSON.stringify(endpoint.permissions)}` : "";
return ` ${endpoint.operationId}: {
method: ${JSON.stringify(endpoint.method)},
operationId: API_OPERATIONS.${endpoint.operationId},
path: ${JSON.stringify(endpoint.path)}${permission}${permissions}
}`;
});
const output = `/* eslint-disable */
// Generated by scripts/generate-api-client.mjs. Do not edit manually.
import type { PermissionCode } from "@/app/permissions";
export type ApiHttpMethod = "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
export interface ApiEndpoint {
method: ApiHttpMethod;
operationId: string;
path: string;
permission?: PermissionCode;
permissions?: PermissionCode[];
}
export const API_OPERATIONS = {
${operationLines.join(",\n")}
} as const;
export type ApiOperationId = (typeof API_OPERATIONS)[keyof typeof API_OPERATIONS];
export const API_ENDPOINTS: Record<ApiOperationId, ApiEndpoint> = {
${endpointLines.join(",\n")}
};
export const API_OPERATION_IDS = Object.values(API_OPERATIONS);
export const API_PERMISSION_CODES = Array.from(
new Set(
Object.values(API_ENDPOINTS)
.flatMap((endpoint) => endpoint.permissions || (endpoint.permission ? [endpoint.permission] : []))
.filter((permission): permission is PermissionCode => Boolean(permission))
)
);
export type ApiPathParams = Record<string, number | string>;
export function apiEndpointPath(operationId: ApiOperationId, params: ApiPathParams = {}) {
let endpointPath = API_ENDPOINTS[operationId].path;
for (const [key, value] of Object.entries(params)) {
endpointPath = endpointPath.replace(\`{\${key}}\`, encodeURIComponent(String(value)));
}
return endpointPath;
}
`;
await mkdir(path.dirname(outputPath), { recursive: true });
await writeFile(outputPath, output);
console.log(`Generated ${path.relative(rootDir, outputPath)} from ${path.relative(rootDir, contractPath)}`);