Files
18xchat/Tools/Proto/build-proto.js
T

104 lines
2.9 KiB
JavaScript
Raw Normal View History

2025-08-14 00:16:28 +08:00
// Tools/Proto/build-proto.js
2025-08-13 17:23:45 +08:00
const { execSync } = require('child_process');
2025-08-14 00:16:28 +08:00
const fs = require('fs-extra');
2025-08-13 17:23:45 +08:00
const path = require('path');
const SRC = path.join(__dirname, '..', '..', 'proto_cs'); // 源 proto 文件目录
2025-08-14 00:16:28 +08:00
const OUT_DIR = path.join(__dirname, '..', '..', 'assets', 'Scripts', 'proto');
const OUT_JS = path.join(OUT_DIR, 'proto.pb.js');
const OUT_DTS = path.join(OUT_DIR, 'proto.pb.d.ts');
const NAMESPACE = 'proto';
2025-08-13 17:23:45 +08:00
2025-08-14 00:16:28 +08:00
/** 递归收集所有 .proto 文件 */
2025-08-13 17:23:45 +08:00
function walk(dir) {
const files = [];
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name);
const stat = fs.statSync(p);
if (stat.isDirectory()) files.push(...walk(p));
else if (name.endsWith('.proto')) files.push(p);
}
return files;
}
2025-08-14 00:16:28 +08:00
/** 清空输出目录 */
function clearOutput() {
fs.emptyDirSync(OUT_DIR);
console.log(`已清空目录: ${OUT_DIR}`);
2025-08-13 17:23:45 +08:00
}
2025-08-14 00:16:28 +08:00
/** 给 CJS 文件添加 default 导出 */
function addDefaultExport(jsFile) {
let code = fs.readFileSync(jsFile, 'utf8');
if (/module\.exports\s*=/.test(code) && !/module\.exports\.default\s*=/.test(code)) {
code += `\nmodule.exports.default = module.exports;`;
fs.writeFileSync(jsFile, code, 'utf8');
console.log(`已为 ${path.basename(jsFile)} 添加 default 导出`);
}
}
2025-08-13 17:23:45 +08:00
2025-08-14 00:16:28 +08:00
/** 包装 d.ts 文件,修复 $protobuf & public 报错 */
function wrapDTS(filePath) {
let original = fs.readFileSync(filePath, 'utf8');
2025-08-13 17:23:45 +08:00
2025-08-14 00:16:28 +08:00
// 1. 提取顶层 import(避免包进 namespace
const importLines = [];
original = original.replace(/^(import\s+.*?;)\s*$/gm, (_, imp) => {
importLines.push(imp);
return '';
});
2025-08-13 17:23:45 +08:00
2025-08-14 00:16:28 +08:00
// 2. 去掉 public 修饰符
original = original.replace(/^\s*public\s+/gm, '');
// 3. 包装 namespace
const wrapped = `${importLines.join('\n')}\n\ndeclare namespace ${NAMESPACE} {\n${original}\n}\nexport default ${NAMESPACE};\n`;
fs.writeFileSync(filePath, wrapped, 'utf8');
console.log(`已包装文件: ${filePath}`);
}
/** 主构建流程 */
function build() {
clearOutput();
const allProtoFiles = walk(SRC);
if (allProtoFiles.length === 0) {
console.error('没有找到任何 .proto 文件!');
process.exit(1);
}
fs.mkdirpSync(OUT_DIR);
// 1) 生成 JSCJS 格式,方便加 default
execSync([
'pbjs',
'-t static-module',
'-w commonjs', // 用 commonjs 避免 ESM 重复 default
'--dependency protobufjs/minimal.js',
`-o "${OUT_JS}"`,
`-p "${SRC}"`,
...allProtoFiles.map(f => `"${f}"`)
].join(' '), { stdio: 'inherit' });
// 2) 添加 default 导出
addDefaultExport(OUT_JS);
// 3) 生成 d.ts
execSync([
'pbts',
'--main',
`-o "${OUT_DTS}"`,
`"${OUT_JS}"`
].join(' '), { stdio: 'inherit' });
// 4) wrap d.ts
wrapDTS(OUT_DTS);
console.log(`\nProto 生成完成!
JS 文件: ${OUT_JS}
TS 文件: ${OUT_DTS}
共处理 ${allProtoFiles.length} 个 .proto 文件`);
}
build();