mirror of
https://github.com/Nighthawk42/roll20-character-sheets.git
synced 2026-08-30 19:52:29 +00:00
148 lines
5.2 KiB
JavaScript
148 lines
5.2 KiB
JavaScript
const path = require('path');
|
|
const {pathToFileURL} = require('url');
|
|
const fs = require('fs/promises');
|
|
const jsdom = require('jsdom');
|
|
const { JSDOM } = jsdom;
|
|
|
|
const pug = require('pug');
|
|
const sass = require('sass-embedded');
|
|
// Object to hold the last edited times of each file to prevent extraneous renders
|
|
|
|
const getTemplate = (filePath) => fs.readFile(filePath,'utf8')
|
|
.then(text => text.replace(/include k-scaffold/g,'include /node_modules/k-scaffold/_k.pug'));
|
|
|
|
const outputPug = async (html,destination) => {
|
|
if(!destination) return;
|
|
const destDir = path.dirname(destination);
|
|
await fs.mkdir(destDir,{recursive:true});
|
|
await fs.writeFile(destination,html);
|
|
console.log(`HTML written to ${destination}`);
|
|
const dom = new JSDOM(html);
|
|
const { window } = dom;
|
|
const { document } = window;
|
|
|
|
const transArr = [...document.querySelectorAll('[data-i18n]')];
|
|
const attrTransKeys = ['title','placeholder','label','aria-label','alt','list']
|
|
const attrTransArr = attrTransKeys.reduce((memo,key) => [...new Set([
|
|
...memo,
|
|
...document.querySelectorAll(`[data-i18n-${key}]`)
|
|
])] ,[]);
|
|
const translations = transArr.reduce((memo,el)=>{
|
|
memo[el.dataset.i18n] = el.textContent?.trim() || el.dataset.i18n;
|
|
return memo;
|
|
},{});
|
|
const capitalizeI18n = string => string.replace(/(?:^|\s+|\/|-)[a-z]/ig,(letter)=>letter.toUpperCase()).replace(/-/g,'');
|
|
attrTransArr.forEach(el => {
|
|
attrTransKeys.forEach(key => {
|
|
if(el.dataset[`i18n${capitalizeI18n(key)}`]){
|
|
translations[el.dataset[`i18n${capitalizeI18n(key)}`]] = el[key] || el.dataset[`i18n${capitalizeI18n(key)}`];
|
|
}
|
|
});
|
|
});
|
|
if(translations){
|
|
const transPath = path.resolve(path.dirname(destination),'translation.json');
|
|
const currTranslation = await fs.readFile(transPath,'utf8')
|
|
.then(t => JSON.parse(t))
|
|
.catch( e => {return {}});
|
|
Object.entries(translations)
|
|
.forEach(([key,val]) => {
|
|
if(!currTranslation[key]){
|
|
currTranslation[key] = val;
|
|
}
|
|
});
|
|
await fs.writeFile(transPath,JSON.stringify(currTranslation,null,2));
|
|
console.log(`${transPath} updated`);
|
|
}
|
|
|
|
};
|
|
|
|
const renderPug = async ({source,destination,options={suppressStack:true}}) => {
|
|
const template = await getTemplate(source);
|
|
try{
|
|
console.log('original source',source);
|
|
console.log('manipulated filename',source);
|
|
const html = pug.render(template,{pretty:true,...options,filename:source,basedir:path.dirname(process.argv[1])})
|
|
await outputPug(html,destination);
|
|
return html;
|
|
}catch(err){
|
|
if(err.message.endsWith('kScript mixin already used. Kscript should be the final mixin used in the sheet code.')){
|
|
console.log('\x1b[31m%s\x1b[0m',
|
|
'================================\n==== K-scaffold PARSE ERROR ====\n================================');
|
|
console.log('kScript mixin already used. Kscript should be the final mixin used in the sheet code.');
|
|
}else{
|
|
console.log('\x1b[31m%s\x1b[0m',
|
|
'=========================\n==== PUG PARSE ERROR ====\n=========================');
|
|
if(options.suppressStack){
|
|
console.error(err.message)
|
|
}else{
|
|
console.log('showing full err');
|
|
console.error(err);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const renderSASS = async ({source,destination,options={}}) => {
|
|
const dirname = path.dirname(process.argv[1]);
|
|
const compileOptions = {
|
|
charset:false,
|
|
importers: [
|
|
{
|
|
findFileUrl(url) {
|
|
if(!url.startsWith('k/')) return null;
|
|
const sub = url.substring(2);
|
|
const fileURL = pathToFileURL('node_modules/k-scaffold');
|
|
const newURL = new URL(sub, pathToFileURL('node_modules/k-scaffold/'));
|
|
return newURL;
|
|
}
|
|
}
|
|
]
|
|
};
|
|
const currOptions = {...options};
|
|
if(currOptions.importers){
|
|
compileOptions.importers.push(...currOptions.importers);
|
|
delete currOptions.importers;
|
|
}
|
|
Object.assign(compileOptions,currOptions);
|
|
|
|
const {css} = await sass.compileAsync(source,compileOptions);
|
|
if(destination){
|
|
await fs.writeFile(destination,css);
|
|
console.log(`CSS written to ${destination}`);
|
|
}
|
|
|
|
return css
|
|
};
|
|
|
|
const renderAll = async ({source ='./',destination,pugOptions={suppressStack:true},scssOptions={}}) => {
|
|
const sourceDir = path.dirname(source);
|
|
const destDir = path.dirname(destination);
|
|
const files = await fs.opendir(source);
|
|
const pugOutput = [];
|
|
const scssOutput = [];
|
|
for await (entry of files){
|
|
if(entry.isFile()){
|
|
const resSource = path.resolve(source,entry.name);
|
|
const resDest = destination ?
|
|
path.resolve(destination,entry.name.replace(/\.pug$/,'.html').replace(/\.scss$/,'.css')) :
|
|
undefined;
|
|
if(entry.name.endsWith('.scss')){
|
|
console.log(`Processing ${entry.name}`);
|
|
const newSass = await renderSASS({source:resSource,destination:resDest,options:scssOptions});
|
|
scssOutput.push(newSass);
|
|
}
|
|
if(entry.name.endsWith('.pug')){
|
|
console.log(`Processing ${entry.name}`);
|
|
const newPug = await renderPug({source:resSource,destination:resDest,options:pugOptions});
|
|
pugOutput.push(newPug);
|
|
}
|
|
}
|
|
}
|
|
return [pugOutput,scssOutput];
|
|
};
|
|
|
|
module.exports = {
|
|
pug:renderPug,
|
|
scss:renderSASS,
|
|
all:renderAll
|
|
}; |