import fs from "node:fs"; import path from "node:path"; const inputDirectory = process.argv[2]; const outputFile = process.argv[3] ?? path.resolve("schemas", "12340.json"); const sourceCommit = process.argv[4]; if (!inputDirectory) { throw new Error( "Usage: node scripts/build-schema-bundle.mjs [output file] [source commit]" ); } const target = { expansion: 3, major: 3, minor: 5, build: 12340 }; const locales = [ "enUS", "enGB", "koKR", "frFR", "deDE", "enCN", "zhCN", "enTW", "zhTW", "esES", "esMX", "ruRU", "ptPT", "ptBR", "itIT", "Unk" ]; const bundle = { build: 12340, version: "3.3.5.12340", source: { project: "WoWDBDefs", url: "https://github.com/wowdev/WoWDBDefs", license: "CC BY-SA 4.0", ...(sourceCommit ? { commit: sourceCommit } : {}) }, tables: {} }; for (const fileName of fs.readdirSync(inputDirectory).filter((name) => name.endsWith(".json"))) { const definition = JSON.parse(fs.readFileSync(path.join(inputDirectory, fileName), "utf8")); const version = definition.versionDefinitions.find((entry) => matches(entry, target)); if (!version) continue; const tableName = path.basename(fileName, ".json"); const columns = []; let offset = 0; for (const field of version.definitions) { if (field.isNonInline) continue; const columnDefinition = definition.columnDefinitions[field.name]; if (!columnDefinition) { throw new Error(`${tableName}: missing column definition '${field.name}'.`); } const arrayLength = field.arrLength || 1; for (let arrayIndex = 0; arrayIndex < arrayLength; arrayIndex += 1) { const baseName = arrayLength > 1 ? `${field.name}_${arrayIndex + 1}` : field.name; if (columnDefinition.type === "locstring") { for (const locale of locales) { columns.push({ name: `${baseName}_${locale}`, kind: "string", bits: 32, offset, locale }); offset += 4; } columns.push({ name: `${baseName}_Mask`, kind: "uint", bits: 32, offset }); offset += 4; continue; } const column = makeColumn(baseName, columnDefinition.type, field, offset); if (field.isID) column.isId = true; columns.push(column); offset += column.bits / 8; } } bundle.tables[tableName.toLowerCase()] = { name: tableName, build: 12340, recordSize: offset, columns, source: "WoWDBDefs" }; } fs.mkdirSync(path.dirname(outputFile), { recursive: true }); fs.writeFileSync(outputFile, `${JSON.stringify(bundle)}\n`); process.stdout.write(`Wrote ${Object.keys(bundle.tables).length} schemas to ${outputFile}\n`); function makeColumn(name, type, field, offset) { if (type === "string") return { name, kind: "string", bits: 32, offset }; if (type === "float") return { name, kind: "float", bits: 32, offset }; if (type !== "int") throw new Error(`Unsupported DBD type '${type}' for '${name}'.`); const bits = field.size || 32; if (![8, 16, 32, 64].includes(bits)) { throw new Error(`Unsupported integer size ${bits} for '${name}'.`); } return { name, kind: field.isSigned ? "int" : "uint", bits, offset }; } function matches(version, build) { if (version.builds.some((candidate) => compareBuilds(candidate, build) === 0)) return true; return version.buildRanges.some( (range) => compareBuilds(range.minBuild, build) <= 0 && compareBuilds(build, range.maxBuild) <= 0 ); } function compareBuilds(left, right) { for (const key of ["expansion", "major", "minor", "build"]) { const difference = left[key] - right[key]; if (difference !== 0) return difference; } return 0; }