aboutsummaryrefslogblamecommitdiff
path: root/generator/make4htwrapper.js
blob: b8e0c3aed856cd7dec445b2e5c486fed0031bb99 (plain) (tree)








































































































                                                                                                       
#!/usr/bin/node
//Copyright Chris Xiong 2024
//License: Expat (MIT)

const content_dir='../content';
const image_dir='../content/img';

const process = require('node:process');
const path = require('node:path');
const util = require('node:util');
const fs = require('node:fs');
const jsdom = require('jsdom');
const spawn = require('child_process').spawn;
const image_size = require('image-size');

function promote_header(doc)
{
	for (let i = 2; i <= 6; ++i)
	{
		const list = doc.querySelectorAll(`h${i}`);
		for (let j = list.length - 1; j >= 0; --j)
		{
			const e = list[j];
			const newe = doc.createElement(`h${i-1}`);
			newe.innerHTML = e.innerHTML;
			e.parentNode.replaceChild(newe, e);
		}
	}
}

function image_unsquash(doc, wd)
{
	for (let im of doc.querySelectorAll('img'))
	{
		const d = image_size(path.join(wd, im.src));
		if (d.width > d.height)
			im.removeAttribute('width');
		else if (d.width < d.height)
			im.removeAttribute('height');
	}
}

function image_relocate(doc, wd, imd)
{
	for (let im of doc.querySelectorAll('img'))
	{
		fs.copyFileSync(path.join(wd, im.src), path.join(imd, im.src));
		im.src = `//filestorage.chrisoft.org/blog/img/${im.src}`;
	}
}

function css_embed(doc, cssc)
{
	const style = doc.createElement('style');
	style.textContent = cssc.replaceAll('font-family', 'not-font-family');
	const body = doc.querySelector('body');
	body.insertBefore(style, body.childNodes[0]);
}

async function main()
{
	process.stdin.setEncoding('utf8');

	const input = await new Promise((resolv, rej) => {
		let d = '';
		process.stdin.on('readable', () => { const r = process.stdin.read(); if (r) d += r; });
		process.stdin.on('end',() => { resolv(d.trim()); });
	});

	const wd = path.resolve(path.join(content_dir, path.dirname(input)));
	const fn = path.basename(input);
	const fnb = path.basename(input, '.tex');

	const make4htp = spawn('make4ht', ['-f', 'html5', fn, '"fn-in"'], {
		cwd: wd,
		shell: true,
		stdio: ['ignore', 'pipe', 'pipe']
	});
	make4htp.stdout.setEncoding('utf8');
	make4htp.stderr.setEncoding('utf8');
	make4htp.stdout.on('data', (d) => { console.error(d); });
	make4htp.stderr.on('data', (d) => { console.error(d); });
	try {
		await new Promise((resolv, rej) => {
			make4htp.on('close', (r) => r ? rej(r) : resolv())
		});
	} catch (e) {
		console.error(`make4ht failed with exitcode ${e}`);
		return;
	}

	const htmlc = fs.readFileSync(path.join(wd, `${fnb}.html`), 'utf8');
	const cssc = fs.readFileSync(path.join(wd, `${fnb}.css`), 'utf8');
	const domrt = new jsdom.JSDOM(htmlc);

	promote_header(domrt.window.document);
	image_unsquash(domrt.window.document, wd);
	image_relocate(domrt.window.document, wd, path.resolve(image_dir));
	css_embed(domrt.window.document, cssc);

	process.stdout.setEncoding('utf8');
	process.stdout.write(domrt.window.document.querySelector('body').innerHTML);
}

main()