Files
tiku-backend.net/Tiku.PlatformAdmin.Web/scripts/generate-platform-operations.mjs

56 lines
3.2 KiB
JavaScript

import { execFileSync } from 'node:child_process';
import { mkdirSync, writeFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import path from 'node:path';
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const openApiUrl = process.env.OPENAPI_URL || 'http://localhost:5090/openapi/v1.json';
const response = await fetch(openApiUrl);
if (!response.ok) throw new Error(`OpenAPI 下载失败:${response.status} ${response.statusText}`);
const document = await response.json();
const generatedDir = path.join(projectRoot, '.generated');
const apiDir = path.join(projectRoot, 'src', 'api');
mkdirSync(generatedDir, { recursive: true });
mkdirSync(apiDir, { recursive: true });
const snapshotPath = path.join(generatedDir, 'openapi.json');
writeFileSync(snapshotPath, `${JSON.stringify(document)}\n`);
const cli = path.join(projectRoot, 'node_modules', '.bin', process.platform === 'win32' ? 'openapi-typescript.cmd' : 'openapi-typescript');
execFileSync(cli, [snapshotPath, '-o', path.join(apiDir, 'schema.generated.d.ts')], { stdio: 'inherit' });
const methods = new Set(['get', 'post', 'put', 'patch', 'delete']);
const operations = [];
for (const [route, pathItem] of Object.entries(document.paths || {})) {
for (const [method, operation] of Object.entries(pathItem || {})) {
if (!methods.has(method)) continue;
const tags = operation.tags || [];
const isPlatform = (route.startsWith('/api/platform/') || route === '/api/platform') &&
!route.startsWith('/api/platform/auth/');
if (!isPlatform) continue;
const requestSchema = operation.requestBody?.content?.['application/json']?.schema || null;
const responseEntry = Object.entries(operation.responses || {}).find(([status]) => /^2/.test(status));
const responseSchema = responseEntry?.[1]?.content?.['application/json']?.schema || null;
operations.push({
id: `${method.toUpperCase()} ${route}`,
method: method.toUpperCase(),
path: route,
tag: tags[0] || '平台端',
summary: operation.summary || `${method.toUpperCase()} ${route}`,
description: operation.description || '',
parameters: [...(pathItem.parameters || []), ...(operation.parameters || [])],
requestSchema,
responseSchema,
requiredPermission: operation['x-tiku-required-permission'] || null,
riskLevel: operation['x-tiku-risk-level'] || (method === 'get' ? 'low' : 'medium'),
approvalPolicyCode: operation['x-tiku-approval-policy-code'] || null,
});
}
}
operations.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));
const schemas = document.components?.schemas || {};
const source = `/* eslint-disable */\n// 由 scripts/generate-platform-operations.mjs 根据后端 OpenAPI 自动生成,请勿手改。\nimport type { PlatformOperation } from './types';\n\nexport const platformOperations = ${JSON.stringify(operations, null, 2)} as const satisfies readonly PlatformOperation[];\nexport const openApiSchemas = ${JSON.stringify(schemas, null, 2)} as const;\n`;
writeFileSync(path.join(apiDir, 'platform-operations.generated.ts'), source);
console.log(`已生成 ${operations.length} 个平台接口契约,来源:${openApiUrl}`);