glam-web/scripts/generate-api.js

161 lines
5.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { generate } from 'openapi-typescript-codegen';
import { readFileSync, writeFileSync, existsSync, readdirSync } from 'fs';
import { join } from 'path';
import axios from 'axios';
// 配置
const config = {
// input: process.env.OPENAPI_URL || 'https://bowongai--glam-api-fastapi-app.modal.run/openapi.json', // OpenAPI规范URL
input: process.env.OPENAPI_URL || 'http://192.168.0.127:8010/openapi.json', // OpenAPI规范URL
output: './src/api', // 生成的API代码输出目录
client: 'axios', // 使用axios作为HTTP客户端
useOptions: true,
useUnionTypes: true,
exportSchemas: true,
exportServices: true,
exportCore: true,
exportModels: true,
exportClient: true,
};
async function fetchOpenApiSpec(url) {
try {
console.log(`📡 正在获取OpenAPI规范: ${url}`);
const response = await axios.get(url);
return response.data;
} catch (error) {
console.error(`❌ 获取OpenAPI规范失败: ${error.message}`);
throw error;
}
}
function createIndexFiles() {
const apiDir = config.output;
// 创建services/index.ts
const servicesDir = join(apiDir, 'services');
if (existsSync(servicesDir)) {
const serviceFiles = readdirSync(servicesDir)
.filter(file => file.endsWith('.ts') && file !== 'index.ts' && file !== 'Service.ts')
.map(file => file.replace('.ts', ''));
const servicesIndexContent = serviceFiles.map(service => `export * from './${service}';`).join('\n');
writeFileSync(join(servicesDir, 'index.ts'), servicesIndexContent);
console.log('📝 创建services/index.ts完成');
}
// 创建models/index.ts
const modelsDir = join(apiDir, 'models');
if (existsSync(modelsDir)) {
const modelFiles = readdirSync(modelsDir)
.filter(file => file.endsWith('.ts') && file !== 'index.ts')
.map(file => file.replace('.ts', ''));
const modelsIndexContent = modelFiles.map(model => `export * from './${model}';`).join('\n');
writeFileSync(join(modelsDir, 'index.ts'), modelsIndexContent);
console.log('📝 创建models/index.ts完成');
}
}
function createApiEntry() {
const servicesDir = join(config.output, 'services');
const modelsDir = join(config.output, 'models');
const apiDir = join('src', 'api');
const apiFile = join(apiDir, 'index.ts');
// 读取 service 文件
let serviceFiles = [];
if (existsSync(servicesDir)) {
serviceFiles = readdirSync(servicesDir)
.filter(file => file.endsWith('.ts') && file !== 'index.ts' && file !== 'Service.ts')
.map(file => file.replace('.ts', ''));
}
// 读取 model 文件
let modelFiles = [];
if (existsSync(modelsDir)) {
modelFiles = readdirSync(modelsDir)
.filter(file => file.endsWith('.ts') && file !== 'index.ts')
.map(file => file.replace('.ts', ''));
}
// 生成 import 语句
const importStatements = [
`import { OpenAPI } from '@/api/core/OpenAPI';`,
...serviceFiles.map(name => `import * as ${name} from '@/api/services/${name}';`),
].join('\n');
// 生成 api 对象
const apiObject = ['export const api = {', ...serviceFiles.map(name => ` ...${name},`), ' OpenAPI,', '};'].join('\n');
// 生成 baseURL 逻辑
const baseUrlLogic = `\nconst baseURL = (() => {\n const url = import.meta.env.VITE_API_BASE_URL || '';
return url;\n})();\nOpenAPI.BASE = baseURL;\n`;
// 生成类型 re-export
const typeExports = modelFiles.map(name => `export type { ${name} } from '@/api/models/${name}';`).join('\n');
// 合成文件内容
const content = `${importStatements}\n${baseUrlLogic}\n${apiObject}\n\n${typeExports}\n`;
// 确保 api 目录存在
if (!existsSync(apiDir)) {
require('fs').mkdirSync(apiDir, { recursive: true });
}
// 写入文件
writeFileSync(apiFile, content);
console.log('📝 自动生成 src/api/index.ts 完成');
}
async function generateApi() {
try {
console.log('🚀 开始生成API代码...');
let openApiSpec;
// 检查输入是URL还是本地文件
if (config.input.startsWith('http://') || config.input.startsWith('https://')) {
// 从URL获取OpenAPI规范
openApiSpec = await fetchOpenApiSpec(config.input);
} else {
// 从本地文件读取
if (!existsSync(config.input)) {
console.error(`❌ OpenAPI文件不存在: ${config.input}`);
console.log('请确保openapi.json文件存在于项目根目录或设置OPENAPI_URL环境变量');
return;
}
openApiSpec = JSON.parse(readFileSync(config.input, 'utf8'));
}
// 生成API代码
await generate({
input: openApiSpec, // 直接传入规范对象
output: config.output,
client: config.client,
useOptions: config.useOptions,
useUnionTypes: config.useUnionTypes,
exportSchemas: config.exportSchemas,
exportServices: config.exportServices,
exportCore: config.exportCore,
exportModels: config.exportModels,
exportClient: config.exportClient,
});
console.log('✅ API代码生成完成');
console.log(`📁 输出目录: ${config.output}`);
// 创建索引文件
createIndexFiles();
// 自动生成 api/index.ts包含 api 和 ApiModel
createApiEntry();
} catch (error) {
console.error('❌ 生成API代码时出错:', error);
}
}
// 运行生成器
generateApi();