// do the XML parsing and fs access in a build step import { promises as fs } from "node:fs"; import * as path from "node:path"; import { XMLParser } from "fast-xml-parser"; const KEYBOARD_PATH = "../../../keyboards/3.0"; const IMPORT_PATH = "../../../keyboards/import"; const DATA_PATH = "static/data"; async function xmlList(basepath) { const dir = await fs.opendir(basepath); const xmls = []; for await (const ent of dir) { if (!ent.isFile() || !/\.xml$/.test(ent.name)) { continue; } xmls.push(ent.name); } return xmls; } /** * List of elements that are always arrays */ const alwaysArray = [ "keyboard3.transforms", "keyboard3.transforms.transformGroup", "keyboard3.transforms.transformGroup.transform", ]; /** * Loading helper for isArray * @param name * @param jpath * @param isLeafNode * @param isAttribute * @returns */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const isArray = (name, jpath, isLeafNode, isAttribute) => { if (alwaysArray.indexOf(jpath) !== -1) return true; return false; }; /** * Do the XML Transform given raw XML source * @param xml XML source for transforms. entire keyboard file. * @param source source text * @returns target text */ export function parseXml(xml) { const parser = new XMLParser({ ignoreAttributes: false, isArray, }); const j = parser.parse(xml); return j; } async function readFile(path) { return fs.readFile(path, "utf-8"); } async function main() { const xmls = await xmlList(KEYBOARD_PATH); const keyboards = await packXmls(KEYBOARD_PATH, xmls); const importFiles = await xmlList(IMPORT_PATH); const imports = await packXmls(IMPORT_PATH, importFiles); const allData = { keyboards, imports, }; const outPath = path.join(DATA_PATH, "keyboard-data.json"); const outJsPath = path.join(DATA_PATH, "keyboard-data.js"); await fs.mkdir(DATA_PATH, { recursive: true }); const json = JSON.stringify(allData, null, " "); // indent, in case we need to read it await fs.writeFile(outPath, json, "utf-8"); await fs.writeFile(outJsPath, `const _KeyboardData = \n` + json); return { xmls, importFiles, outPath, outJsPath }; } main().then( (done) => console.dir({ done }), (err) => { console.error(err); process.exitCode = 1; } ); async function packXmls(basepath, xmls) { const allData = {}; for (const fn of xmls) { const fp = path.join(basepath, fn); const data = await readFile(fp); const parsed = parseXml(data); allData[fn] = parsed; } return allData; }