UNPKG

fy-convertor

Version:

Convert excel/xml/json/bin/protocl/ts/as ...

147 lines 6.75 kB
import fs from "fs-extra"; import path from "path"; import { toolchain } from "../tools/toolchain.js"; import { runCommand } from "../tools/vendor.js"; import { GitHelper } from "./GitHelper.js"; import { RepoHolder } from "./RepoHolder.js"; const Proto_Git_URL = 'http://192.168.8.72:30000/ppgame/gamedata.git'; export class ProtobufGen { static ins; static get Instance() { if (!ProtobufGen.ins) ProtobufGen.ins = new ProtobufGen(); return ProtobufGen.ins; } async execute() { const cfg = toolchain.projCfg.protobufgen; if (!cfg) { console.error('protobufgen config not found'); return; } // 更新proto目录 const protoRepoPath = path.join(toolchain.options.workspace, 'ppgame_gamedata'); const protoPath = path.join(protoRepoPath, 'proto'); await GitHelper.Instance.partialCloneDirectory({ gitUrl: Proto_Git_URL, sparsePath: 'proto', localPath: protoRepoPath }); // 更新svn目录 const temp = path.join(toolchain.options.workspace, toolchain.options.project); const outputJSRepoPath = path.join(temp, 'proto_js'); const outputJsSubDir = cfg.outputJsSvnDir ?? 'js'; const useGitClientRepo = !toolchain.projCfg.Svn.ClientSvn.startsWith('svn://'); RepoHolder.Instance.setAsType(useGitClientRepo ? 'git' : 'svn'); const outputJSPath = useGitClientRepo ? path.join(outputJSRepoPath, outputJsSubDir) : outputJSRepoPath; const useDiffTsPath = cfg.outputTsSvnDir && cfg.outputTsSvnDir != cfg.outputJsSvnDir; const outputTSRepoPath = useDiffTsPath ? path.join(temp, 'proto_ts') : outputJSRepoPath; const outputTSPath = useDiffTsPath ? (useGitClientRepo ? path.join(outputTSRepoPath, cfg.outputTsSvnDir) : outputTSRepoPath) : outputJSPath; await RepoHolder.Instance.checkOutSubDir(!toolchain.options.debug, outputJSRepoPath, toolchain.projCfg.Svn.ClientSvn, outputJsSubDir, cfg.outputGitBranch); if (useDiffTsPath) { await RepoHolder.Instance.checkOutSubDir(!toolchain.options.debug, outputTSRepoPath, toolchain.projCfg.Svn.ClientSvn, cfg.outputTsSvnDir, cfg.outputGitBranch); } // 转换proto文件为js文件 await this.convertProto(cfg, protoPath, outputJSPath, outputTSPath, 'minigame_client_message'); // 修改js文件,适配Browser if (cfg.wrap != 'commonjs') { await this.modifyJsFile(path.join(outputJSPath, 'minigame_client_message.js')); } // 再使用msg_ids来生成.d.ts文件 await this.convertProto(cfg, protoPath, outputJSPath, outputTSPath, 'msg_ids'); // 删除生成的js文件 await fs.unlink(path.join(outputJSPath, 'msg_ids.js')); if (cfg.genTds) { // 修改msg_ids.d.ts文件,只保留msg_ids的定义 await this.modifyMsgIdsDTS(path.join(outputTSPath, 'msg_ids.d.ts')); } // 提交svn if (!toolchain.options.debug) { const commitPaths = [outputJSPath]; if (cfg.genTds && useDiffTsPath) { commitPaths.push(outputTSPath); } await RepoHolder.Instance.commit('protobufgen@fy-convertor~', ...commitPaths); } } async convertProto(cfg, protoPath, outputJSPath, outputTSPath, protoFileName) { // 调用pbjs生成js文件 const jsFile = path.join(outputJSPath, `${protoFileName}.js`); await runCommand('pbjs.cmd', [ '-p', protoPath, '-t', 'static-module', '-w', cfg.wrap ?? 'default', '--no-create', '--no-verify', '--no-convert', '--no-delimited', '--no-typeurl', '--no-service', '-o', jsFile, path.join(protoPath, `proto_game_base/msg_def/${protoFileName}.proto`) ]); // 调用pbts生成ts文件 if (cfg.genTds) { const tsFile = path.join(outputTSPath, `${protoFileName}.d.ts`); await runCommand('pbts.cmd', [ '-o', tsFile, jsFile ]); } } async modifyJsFile(jsFile) { const content = await fs.promises.readFile(jsFile, 'utf-8'); const lines = content.split(/\r?\n/); const index = lines.findIndex(v => v.includes('module.exports = factory(require("protobufjs/minimal"));')); const codes = ` /* Browser */ else global.minigame_client_message = factory(global.protobuf); `; lines.splice(index + 1, 0, codes); const newContent = lines.join('\n'); await fs.writeFile(jsFile, newContent, 'utf-8'); } async modifyMsgIdsDTS(msgIdsJsFile) { const content = await fs.readFile(msgIdsJsFile, 'utf-8'); const lines = content.split(/\r?\n/); // 只保留msg_def部分 let start = -1; let end = -1; for (let i = 0; i < lines.length; i++) { if (!lines[i].startsWith('/** Namespace ') || !lines[i + 1]?.startsWith('export namespace ')) continue; let depth = 0; for (let j = i; j < lines.length; j++) { const line = lines[j]; depth += (line.match(/{/g) ?? []).length; depth -= (line.match(/}/g) ?? []).length; if (depth == 0 && j > i) { const namespaceLines = lines.slice(i, j + 1); if (namespaceLines.some(v => v.includes('enum MSG_DIR')) && namespaceLines.some(v => v.includes('enum MSG_ID'))) { start = i; end = j; } break; } } if (start >= 0) { break; } } if (start < 0 || end < 0) { throw new Error(`msg ids namespace not found in ${msgIdsJsFile}`); } const reservedLines = lines.slice(start, end + 1); let newContent = reservedLines.join('\n'); // 再把enum MSG_DIR和enum MSG_ID改成const enum newContent = newContent.replace(/enum MSG_DIR/g, 'const enum MSG_DIR').replace(/enum MSG_ID/g, 'const enum MSG_ID'); // 把export namespace改为declare namespace newContent = newContent.replace(/export namespace/g, 'declare namespace'); await fs.writeFile(msgIdsJsFile, newContent, 'utf-8'); } } //# sourceMappingURL=ProtobufGen.js.map