1// do the XML parsing and fs access in a build step 2 3import { promises as fs } from "node:fs"; 4import * as path from "node:path"; 5import { XMLParser } from "fast-xml-parser"; 6 7const KEYBOARD_PATH = "../../../keyboards/3.0"; 8const IMPORT_PATH = "../../../keyboards/import"; 9const DATA_PATH = "static/data"; 10 11async function xmlList(basepath) { 12 const dir = await fs.opendir(basepath); 13 const xmls = []; 14 for await (const ent of dir) { 15 if (!ent.isFile() || !/\.xml$/.test(ent.name)) { 16 continue; 17 } 18 xmls.push(ent.name); 19 } 20 return xmls; 21} 22 23/** 24 * List of elements that are always arrays 25 */ 26const alwaysArray = [ 27 "keyboard3.transforms", 28 "keyboard3.transforms.transformGroup", 29 "keyboard3.transforms.transformGroup.transform", 30]; 31 32/** 33 * Loading helper for isArray 34 * @param name 35 * @param jpath 36 * @param isLeafNode 37 * @param isAttribute 38 * @returns 39 */ 40// eslint-disable-next-line @typescript-eslint/no-unused-vars 41const isArray = (name, jpath, isLeafNode, isAttribute) => { 42 if (alwaysArray.indexOf(jpath) !== -1) return true; 43 return false; 44}; 45 46/** 47 * Do the XML Transform given raw XML source 48 * @param xml XML source for transforms. entire keyboard file. 49 * @param source source text 50 * @returns target text 51 */ 52export function parseXml(xml) { 53 const parser = new XMLParser({ 54 ignoreAttributes: false, 55 isArray, 56 }); 57 const j = parser.parse(xml); 58 return j; 59} 60 61async function readFile(path) { 62 return fs.readFile(path, "utf-8"); 63} 64 65async function main() { 66 const xmls = await xmlList(KEYBOARD_PATH); 67 const keyboards = await packXmls(KEYBOARD_PATH, xmls); 68 const importFiles = await xmlList(IMPORT_PATH); 69 const imports = await packXmls(IMPORT_PATH, importFiles); 70 71 const allData = { 72 keyboards, 73 imports, 74 }; 75 76 const outPath = path.join(DATA_PATH, "keyboard-data.json"); 77 const outJsPath = path.join(DATA_PATH, "keyboard-data.js"); 78 await fs.mkdir(DATA_PATH, { recursive: true }); 79 const json = JSON.stringify(allData, null, " "); // indent, in case we need to read it 80 await fs.writeFile(outPath, json, "utf-8"); 81 await fs.writeFile(outJsPath, `const _KeyboardData = \n` + json); 82 return { xmls, importFiles, outPath, outJsPath }; 83} 84 85main().then( 86 (done) => console.dir({ done }), 87 (err) => { 88 console.error(err); 89 process.exitCode = 1; 90 } 91); 92 93async function packXmls(basepath, xmls) { 94 const allData = {}; 95 for (const fn of xmls) { 96 const fp = path.join(basepath, fn); 97 const data = await readFile(fp); 98 const parsed = parseXml(data); 99 allData[fn] = parsed; 100 } 101 return allData; 102} 103