gameClient/tools/pb_exports.js

139 lines
4.0 KiB
JavaScript

const fs = require('fs')
const path = require('path')
/**
* PB 模块导入导出代码生成器
* @param {string} pbDir - PB 文件所在的目录路径
* @param {string} outputFile - 生成的代码输出文件路径
* @param {string} [relativePath='../pb'] - 导入语句中的相对路径
*/
function generatePbImportsAndExports(pbDir, outputFile, relativePath = '../pb') {
try {
// 读取 PB 目录下的所有文件
const files = fs.readdirSync(pbDir)
// 过滤出 .js 文件并去除扩展名
const jsFiles = files.filter((file) => file.endsWith('.js'))
if (jsFiles.length === 0) {
console.warn(`警告: 在目录 ${pbDir} 中没有找到任何 .js 文件`)
return
}
// 生成导入语句
const importStatements = jsFiles
.map((file) => {
const moduleName = file.replace('.js', '')
return `import ${moduleName} from '${relativePath}/${moduleName}.js'`
})
.join('\n')
// 为每个文件生成导出内容
const moduleExports = {}
const allExports = new Set()
const exportSources = {} // 记录每个导出项的来源
jsFiles.forEach((file) => {
const filePath = path.join(pbDir, file)
const code = fs.readFileSync(filePath, 'utf-8')
const moduleName = file.replace('.js', '')
// 提取 $root.X 形式的导出
const rootExports = extractRootExports(code)
// 提取 enum 定义
const enumExports = extractEnumExports(code)
// 合并所有导出
const exports = [...rootExports, ...enumExports]
if (exports.length > 0) {
moduleExports[moduleName] = exports
// 记录导出项的来源
exports.forEach((exp) => {
if (!exportSources[exp]) {
exportSources[exp] = moduleName
allExports.add(exp)
}
})
}
})
if (allExports.size === 0) {
console.warn(`警告: 没有找到任何可导出的类或枚举`)
return
}
// 生成解构赋值语句(只包含首次出现的导出项)
const destructureStatements = Object.entries(moduleExports)
.map(([moduleName, exports]) => {
// 过滤出该模块独有的导出项
const uniqueExports = exports.filter((exp) => exportSources[exp] === moduleName)
if (uniqueExports.length > 0) {
return `const { ${uniqueExports.join(', ')} } = ${moduleName}`
}
return ''
})
.filter(Boolean) // 移除空字符串
.join('\n')
// 生成导出语句(所有唯一导出项)
const exportList = Array.from(allExports)
// 完整的输出代码
const outputCode =
`// 由 pb-import-export-generator 自动生成,请勿手动修改\n\n` +
`// 导入语句\n${importStatements}\n\n` +
`// 解构赋值\n${destructureStatements}\n\n` +
`// 导出语句\nexport {\n ${exportList.join(',\n ')}\n};\n`
// 确保输出目录存在
const outputDir = path.dirname(outputFile)
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true })
}
// 写入输出文件
fs.writeFileSync(outputFile, outputCode)
console.log(`成功生成 PB 导入导出代码到 ${outputFile}`)
console.log(`共生成 ${jsFiles.length} 个导入语句和 ${exportList.length} 个导出变量`)
} catch (error) {
console.error('生成 PB 导入导出代码时出错:', error.message)
}
}
/**
* 提取 $root.X 形式的导出
*/
function extractRootExports(code) {
const exports = []
const rootExportRegex = /\$root\.([A-Za-z][A-Za-z0-9_]*)\s*=/g
let match
while ((match = rootExportRegex.exec(code)) !== null) {
exports.push(match[1])
}
return exports
}
/**
* 提取 enum 定义
*/
function extractEnumExports(code) {
const exports = []
const enumRegex = /@enum\s*{.*?}\s*\n\s*\*\s*@exports\s+([A-Za-z][A-Za-z0-9_]*)/g
let match
while ((match = enumRegex.exec(code)) !== null) {
exports.push(match[1])
}
return exports
}
// 示例用法
generatePbImportsAndExports('../assets/scripts/pb', '../assets/scripts/network/pbExport.ts')