Files
moonwell-client/vscode-dbc-editor/scripts/build-schema-bundle.mjs

122 lines
3.6 KiB
JavaScript

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 <DBDefsConverter JSON directory> [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;
}