UNPKG

bytefun

Version:

一个打通了原型设计、UI设计与代码转换、跨平台原生代码开发等的平台

350 lines (288 loc) 11.2 kB
export function gen(filePath: string) { // 输出目录 // const outputPath = 'F:\\project\\alice\\extract-ast\\src\\test\\other\\backendApi'; const outputPath = 'D:\\project\\alice\\extract-ast2\\src\\test\\other\\backendApi'; execGen(filePath, outputPath); } export function execGen(filePath: string, outputPath: string) { let jsonAry: any[] = []; try { jsonAry = extractJsonFromFile(filePath); } catch (e) { console.error('解析JSON文件失败:', e); jsonAry = []; } if (jsonAry.length < 1) { return; } // 确保输出目录存在且包含 BaseApi.ts 文件 ensureDirAndBaseApi(outputPath); // 创建或更新后端API使用说明.md文件 createOrUpdateApiDoc(outputPath, jsonAry); // api ts 文件 processJsonArray(outputPath, jsonAry); } /** * 确保目录存在并在其中创建 BaseApi.ts 文件(如果不存在) * @param dirPath 文件夹路径 */ export function ensureDirAndBaseApi(dirPath: string): void { const fs = require('fs'); const path = require('path'); // 如果传入的文件夹路径对应的目录不存在,则创建对应的目录 if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } // 检查 BaseApi.ts 文件是否存在,如果不存在则创建 const baseApiFilePath = path.join(dirPath, 'BaseApi.ts'); if (!fs.existsSync(baseApiFilePath)) { const baseApiContent = 'export default class BaseApi {}\n'; fs.writeFileSync(baseApiFilePath, baseApiContent); } } /** * 处理文件夹路径和 jsonArray,生成对应的 TypeScript 文件 * @param dirPath 文件夹路径 * @param jsonArray extractJsonFromFile 函数的返回结果 */ export function processJsonArray(dirPath: string, jsonArray: any[]): void { const fs = require('fs'); const path = require('path'); // 如果传入的文件夹路径对应的目录不存在,则创建对应的目录 if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } // 遍历 jsonArray 中的每个元素 jsonArray.forEach(jsonObj => { // 获取 moduleEnName 作为子文件夹名称 const moduleEnName = jsonObj.moduleEnName; const moduleDirPath = path.join(dirPath, moduleEnName); // 创建子文件夹 if (!fs.existsSync(moduleDirPath)) { fs.mkdirSync(moduleDirPath, { recursive: true }); } // 生成 ts 文件内容 const tsContent = generateTsContent(jsonObj); // 写入文件 const fileName = `${jsonObj.apiEnName}.ts`; const filePath = path.join(moduleDirPath, fileName); fs.writeFileSync(filePath, tsContent); }); } /** * 创建或更新“后端API使用说明.md”文件 * @param dirPath 文件夹路径 * @param jsonArray extractJsonFromFile 函数的返回结果 */ export function createOrUpdateApiDoc(dirPath: string, jsonArray: any[]): void { const fs = require('fs'); const path = require('path'); // 如果传入的文件夹路径对应的目录不存在,则创建对应的目录 if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } // 定义 md 文件路径 后端API使用说明.md->backendApiInfo.md const mdFilePath = path.join(dirPath, 'backendApiInfo.md'); // 初始化 md 文件内容 let mdContent = '# 后端API使用说明\n\n'; // 按 moduleEnName 分组 const moduleGroups: { [key: string]: any[] } = {}; jsonArray.forEach(jsonObj => { const moduleEnName = jsonObj.moduleEnName || '未命名模块'; if (!moduleGroups[moduleEnName]) { moduleGroups[moduleEnName] = []; } moduleGroups[moduleEnName].push(jsonObj); }); // 生成每个模块的内容 Object.keys(moduleGroups).forEach(moduleEnName => { const moduleItems = moduleGroups[moduleEnName]; const firstItem = moduleItems[0]; // 添加模块标题 if (firstItem.moduleName) { mdContent += `## src/backendApi/${moduleEnName}文件夹(${firstItem.moduleName})里面的\n`; } else { mdContent += `## src/backendApi/${moduleEnName}文件夹里面的\n`; } // 添加每个接口项 moduleItems.forEach((jsonObj, index) => { const idx = index + 1; mdContent += `${idx}. ${jsonObj.apiEnName}.ts: ${jsonObj.name}接口\n`; }); mdContent += '\n'; }); // 写入文件 fs.writeFileSync(mdFilePath, mdContent); } /** * 递归处理类型转换,包括array类型的元素处理 * @param typeInfo 类型信息对象 * @returns 转换后的类型字符串 */ function processTypeRecursively(typeInfo: any): string { if (typeof typeInfo === 'string') { return typeInfo === 'integer' ? 'number' : typeInfo; } if (!typeInfo || !typeInfo.type) { return 'any'; } const baseType = typeInfo.type === 'integer' ? 'number' : typeInfo.type; if (baseType === 'array') { // 处理数组类型,递归处理元素类型 if (typeInfo.items) { const itemType = processTypeRecursively(typeInfo.items); if (typeInfo.items.type === 'object' && typeInfo.items.properties) { // 对象数组使用 [{ ... }] 格式 return `[ ${itemType} ]`; } else { // 基础类型数组使用 type[] 格式 return `${itemType}[]`; } } return 'any[]'; } if (baseType === 'object' && typeInfo.properties) { // 处理对象类型,递归处理属性 let objectType = '{\n'; Object.keys(typeInfo.properties).forEach(key => { const prop = typeInfo.properties[key]; const propType = processTypeRecursively(prop); const description = prop.description || ''; objectType += ` ${key}: ${propType} // ${description}\n`; }); objectType += ' }'; return objectType; } return baseType; } /** * 将 integer 类型转换为 number 类型(保持向后兼容) * @param type 原始类型 * @returns 转换后的类型 */ function convertIntegerToNumber(type: string): string { return type === 'integer' ? 'number' : type; } /** * 根据 jsonObj 生成 ts 文件内容 * @param jsonObj JSON 对象 * @returns 生成的 ts 文件内容 */ function generateTsContent(jsonObj: any): string { const { moduleEnName, apiEnName, name, parameters, responses } = jsonObj; // 生成请求数据接口 let requestInterface = `// ${moduleEnName}-${name}接口请求数据 export interface ${apiEnName}Request { `; if (parameters && Array.isArray(parameters)) { parameters.forEach(param => { const optional = param.required === 'true' ? '' : '?'; const processedType = processTypeRecursively(param); const description = param.description || ''; requestInterface += ` ${param.name}${optional}: ${processedType} // ${description} `; }); } requestInterface += `} `; // 生成返回数据接口 let responseInterface = `// ${moduleEnName}-${name}接口返回数据 export interface ${apiEnName}Response { code: number msg: string data: `; // 处理 data 属性 if (responses && responses.properties && responses.properties.data) { const dataProp = responses.properties.data; const processedType = processTypeRecursively(dataProp); const description = dataProp.description || ''; if (dataProp.type === 'object' || dataProp.type === 'array') { // 对象或数组类型,直接使用递归处理的结果 responseInterface += `${processedType} `; } else { // 基础类型,添加注释 responseInterface += `${processedType} // ${description} `; } } else { responseInterface += `any `; } responseInterface += `} `; // 生成失败返回数据接口 const failInterface = `// ${moduleEnName}-${name}接口失败返回数据 export interface apiFailInfo { msg: string code: number } `; // 生成类定义 const classDefinition = `// ${moduleEnName}-${name}接口 export default class ${apiEnName} extends BaseApi { public static request_ArtuX1d8a6A( request: ${apiEnName}Request, success: (res: ${apiEnName}Response) => void, fail: (error: apiFailInfo) => void ): void { } } `; // 组合所有内容 return `import BaseApi from '../BaseApi' ${requestInterface}${responseInterface}${failInterface}${classDefinition}`; } /** * 从JSON配置文件中提取接口列表 * @param filePath JSON文件路径 * @returns 返回解析后的API数组,每个API包含模块信息 */ export function extractJsonFromFile(filePath: string): any[] { const fs = require('fs'); if (!fs.existsSync(filePath)) { throw new Error(`文件不存在: ${filePath}`); } const content = fs.readFileSync(filePath, 'utf-8'); if (!content || content.length < 10) { throw new Error(`文件内容为空: ${filePath}`); } try { const configData = JSON.parse(content); if (!configData.moduleList || !Array.isArray(configData.moduleList)) { throw new Error('配置文件格式错误:缺少 moduleList 或 moduleList 不是数组'); } const apiArray: any[] = []; // 遍历每个模块 configData.moduleList.forEach((module: any) => { const { moduleFolder, moduleEnName, moduleCnName, description: moduleDescription, apiList } = module; if (!apiList || !Array.isArray(apiList)) { console.warn(`模块 ${moduleEnName} 没有 apiList 或 apiList 不是数组`); return; } // 遍历模块下的每个API apiList.forEach((api: any) => { // 将模块信息合并到API对象中 const apiWithModuleInfo = { ...api, moduleFolder, moduleEnName, moduleName: moduleCnName, // 保持兼容性,使用 moduleName 字段 moduleCnName, moduleDescription }; apiArray.push(apiWithModuleInfo); }); }); return apiArray; } catch (e) { throw new Error(`JSON解析失败: ${filePath}, error: ${(e as Error).message}`); } }