JisolGame/JisolGameCocos/.protobufjs.js

187 lines
5.6 KiB
JavaScript
Raw Normal View History

2023-11-13 02:37:29 +08:00
const path = require("path");
const child_process = require("child_process");
const fs = require("fs");
/**
* @typedef {Object} proto_list
* @property {string | undefined} namespace_s 命名空间
* @property {string[]} proto_ss 协议文件(生成为脚本的协议文件)
* @property {string} ts_output_path_s ts 输出路径(带脚本名)
* @property {string} dts_output_path_s d.ts 输出路径(带脚本名)
* @property {string[] | undefined} pbjs_parameters_ss pbjs 生成时参数(可用于裁剪代码, 命令行`npx pbjs`查看具体参数)
*/
module.exports = {
/**
* 协议列表
* @type {proto_list[]}
*/
proto_list: [],
/**
自动构建开关
- true: 递归监听 dir_path_ss 内的文件添加/删除/修改并触发构建指令
- false需要手动点击 `protobuf/构建` 才会触发构建菜单
*/
automatic_build_b: false,
/** 自动构建延迟(秒),防止短时间内频繁触发构建 */
automatic_build_delay_s_n: 2,
/**
* 构建函数
* @param {proto_list} config_ proto 配置
* @returns {boolean} 成功状态
*/
async build_f(config_) {
// 生成消息头
child_process.execSync("npx ts-node ./protobuf/main.ts", {
"cwd": "./tool"
})
/** ts 输出路径 */
let ts_output_path_s = config_.ts_output_path_s[0] !== "." ? config_.ts_output_path_s : path.join(__dirname, config_.ts_output_path_s);
/** js 输出路径 */
let js_output_path_s = path.join(path.dirname(ts_output_path_s), path.basename(ts_output_path_s, path.extname(ts_output_path_s)) + ".js");
/** 声明文件路径 */
let dts_path_s = config_.dts_output_path_s[0] !== "." ? config_.dts_output_path_s : path.join(__dirname, config_.dts_output_path_s);
// 确保文件夹存在
{
if (!fs.existsSync(path.dirname(ts_output_path_s))) {
fs.mkdirSync(path.dirname(ts_output_path_s));
}
if (!fs.existsSync(path.dirname(dts_path_s))) {
fs.mkdirSync(path.dirname(dts_path_s));
}
}
let result = await Promise.resolve()
// 生成 js 文件
.then(() => {
return new Promise((resolve_f, reject_t) => {
// 使用 es6 的生成类型
child_process.exec(
`npx pbjs -t static-module -w es6 -l eslint-disable --es6 --keep-case ${!config_.pbjs_parameters_ss ? "" : config_.pbjs_parameters_ss.join(" ")
} ${!config_.namespace_s ? "" : `--root ${config_.namespace_s}`} -o ${js_output_path_s} ${config_.proto_ss.join(" ")}`,
{
cwd: __dirname,
},
(error, stdout, stderr) => {
if (stderr) {
reject_t(stderr);
return;
}
resolve_f();
}
);
});
})
// 生成 d.ts 文件
.then(() => {
// 生成 d.ts
return new Promise((resolve_f, reject_t) => {
child_process.exec(
`npx pbts -m ${config_.namespace_s ? `--root ${config_.namespace_s}` : ""} -o ${dts_path_s} ${js_output_path_s}`,
{
cwd: __dirname,
},
(error, stdout, stderr) => {
if (stderr) {
reject_t(stderr);
return;
}
resolve_f();
}
);
});
})
// js 后处理
.then(() => {
let file_s = fs.readFileSync(js_output_path_s, "utf-8");
file_s = file_s
// 替换 import
.replace('import * as $protobuf from "protobufjs/minimal";', 'import $protobuf from "protobufjs/minimal.js";')
// 替换 root
.replace(/const \$root = ([^]+?);/, "const $root = {};");
// 存在命名空间
if (config_.namespace_s) {
file_s = file_s.replace(/export const /g, "const ");
}
// 更新协议文件
fs.writeFileSync(js_output_path_s, file_s);
})
// d.ts 文件后处理
.then(() => {
let file_s = fs.readFileSync(dts_path_s, "utf-8");
if (config_.namespace_s) {
file_s = `export namespace ${config_.namespace_s} {\n${file_s}\n}`;
}
// 添加类型声明
file_s = `import type { Long } from "protobufjs";\n` + file_s;
// 后处理
file_s = file_s.replace(/\$protobuf/g, "protobuf");
// 更新协议文件
fs.writeFileSync(dts_path_s, file_s);
})
// 将 js 协议脚本转换为 ts
.then(() => {
let js_file_s = fs.readFileSync(js_output_path_s, "utf-8");
/** ts 文件路径 */
let ts_script_path_s = path.join(
path.dirname(ts_output_path_s),
path.basename(ts_output_path_s, path.extname(ts_output_path_s)) + ".ts"
);
/** d.ts 相对路径 */
let dts_relative_path_s = path.relative(path.dirname(ts_output_path_s), path.dirname(dts_path_s)).replace(/\\/g, "/");
/** d.ts 导入路径 */
let dts_import_path_s = (dts_relative_path_s || "./") + path.basename(dts_path_s, ".ts");
// 后处理
js_file_s = js_file_s
// 对象类型const $root: typeof import("./test.d").pb
.replace(
"const $root = ",
`const $root: typeof import("${dts_import_path_s}")${config_.namespace_s ? `.${config_.namespace_s}` : ""} = `
)
// 修复对象类型错误
.replace(
/export const ([^ ]+?) = ([^ ]+?) =/g,
function (...args_as) {
return `export const ${args_as[1]}: typeof ${args_as[2]} = ${args_as[2]} =`;
}
);
if (config_.namespace_s) {
js_file_s = js_file_s
// module.exports
.replace(
"export { $root as default }",
`export ${config_.namespace_s ? `const ${config_.namespace_s} = ` : ""}{ ...$root }`);
}
fs.writeFileSync(js_output_path_s, "// @ts-nocheck\n" + js_file_s);
fs.renameSync(js_output_path_s, ts_script_path_s);
})
// 捕获错误
.catch((error) => {
console.error("生成错误:", error);
return false;
})
// 任务完成
.then((v) => {
return v ?? true;
});
return result;
},
};