const builder = require('xmlbuilder'); const fs = require('fs'); const inputFilename = process.argv[2]; if (!inputFilename) { console.log('USAGE: script.js inputfile.json'); process.exit(1); } const inputString = fs.readFileSync(inputFilename, { encoding: 'UTF-8' }); const inputData = JSON.parse(inputString); const printableNumber = n => (n > 0) ? "+" + n : n; const replaceSpecialValuesInActionText = (text) => { text = text.replace(/\{@hit (\d+?)\}/g, (match, p1) => printableNumber(p1)) text = text.replace(/\{@h\}(\d+?)/g, '$1'); text = text.replace(/\{@damage (.*?)\}/g, '$1'); text = text.replace(/\{@dc (\d+?)\}/g, 'DC $1'); text = text.replace(/\{@condition (\w+)\}/g, '$1'); text = text.replace(/\{@skill (\w+)\}/g, '$1'); text = text.replace(/\{@atk (.+?)\}/g, (match, p1) => { p1 = p1.replace(/mw/g, 'Melee Weapon Attack'); p1 = p1.replace(/ms/g, 'Melee Spell Attack'); p1 = p1.replace(/rw/g, 'Ranged Weapon Attack'); p1 = p1.replace(/rs/g, 'Ranged Spell Attack'); p1 = p1.replace(/\,\s*/g, ' or '); return `${p1}:`; }); return text; }; const xml = builder.create('root') .ele('compendium', { version: '5' }) const parseToXML = (obj) => { const monster = xml.ele('monster'); monster.ele('name', obj.name) monster.ele('size', obj.size) monster.ele('type', obj.type) monster.ele('source', obj.source) monster.ele('alignment', obj.alignment && obj.alignment.length ? obj.alignment.join('') : null) monster.ele('ac', obj.ac && obj.ac.length ? obj.ac[0].ac : null) monster.ele('hp', `${obj.hp.average} (${obj.hp.formula})`) monster.ele('cr', obj.cr) monster.ele('passive', obj.passive) monster.ele('str', obj.str) monster.ele('dex', obj.dex) monster.ele('con', obj.con) monster.ele('int', obj.int) monster.ele('wis', obj.wis) monster.ele('cha', obj.cha) monster.ele('languages', obj.languages && obj.languages.length ? obj.languages.join(', ') : null ); monster.ele('senses', obj.senses && obj.senses.length ? obj.senses.join(', ') : null ); monster.ele('immune', obj.immune && obj.immune.length ? obj.immune.join(', ') : null ); monster.ele('speed', obj.speed && Object.keys(obj.speed).map((key) => { const type = key == 'walk' ? '' : key; return `${type} ${obj.speed[key]} ft.`; }).join(', ')); monster.ele('save', obj.save && Object.keys(obj.save).map((key) => { return `${type} ${obj.save[key]}`; }).join(', ')); monster.ele('skill', obj.skill && Object.keys(obj.skill).map((key) => { return `${key} ${obj.skill[key]}`; }).join(', ')); obj.trait && obj.trait.forEach((trait) => { const e = monster.ele('trait'); e.ele('name', trait.name); trait.entries.forEach((entry) => { const text = replaceSpecialValuesInActionText(entry); e.ele('text', text); }); }); obj.legendary && obj.legendary.forEach((legendary) => { const e = monster.ele('legendary'); e.ele('name', legendary.name); legendary.entries.forEach((entry) => { const text = replaceSpecialValuesInActionText(entry); e.ele('text', text); }); }); obj.action && obj.action.forEach((action) => { const e = monster.ele('action'); e.ele('name', action.name); action.entries.forEach((entry) => { const text = replaceSpecialValuesInActionText(entry); e.ele('text', text); }); }) } const processInputData = () => { if (inputData.length) { // array inputData.forEach((obj) => { parseToXML(obj); }); } else { parseToXML(inputData); } } processInputData(); xml.end({ pretty: true, newline: '\n', }); console.log(xml.toString());