103 lines
3.6 KiB
JavaScript
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)}`);
|