/**
* KoalaSync Static Site Generator (i18n compiler)
* Build pipeline: esbuild + AVIF + hashing + SVG min.
*/
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const sharp = require('sharp');
const esbuild = require('esbuild');
const { optimize: svgoOptimize } = require('svgo');
// CSS minifier: simple regex-based (proven, 27% reduction, no deps)
function minifyCSS(code) {
return code
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/\s*([{}:;,])\s*/g, '$1')
.replace(/\s+/g, ' ')
.replace(/;\}/g, '}')
.trim();
}
const MIN_AVIF_KB = 0;
function copyDirSync(src, dest) {
fs.mkdirSync(dest, { recursive: true });
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
const s = path.join(src, entry.name);
const d = path.join(dest, entry.name);
entry.isDirectory() ? copyDirSync(s, d) : fs.copyFileSync(s, d);
}
}
function sha8(buf) { return crypto.createHash('sha256').update(buf).digest('hex').slice(0, 8); }
async function minifyJS(raw) {
const result = await esbuild.transform(raw, {
loader: 'js',
minify: true,
target: 'es2020'
});
return result.code;
}
function injectAvifPictures(html) {
return html.replace(/
]*)>/gi, (match, attrs) => {
const srcMatch = attrs.match(/\bsrc="([^"]*)"/i);
if (!srcMatch) return match;
if (!/\.webp"$/i.test(srcMatch[0])) return match;
const src = srcMatch[1];
const avifSrc = src.replace(/\.webp$/i, '.avif');
const srcsetMatch = attrs.match(/\bsrcset="([^"]*)"/i);
if (srcsetMatch) {
const avifSrcset = srcsetMatch[1].replace(/\.webp/gi, '.avif');
return `
`;
}
return `
`;
});
}
function minifyInlineSvgs(html) {
const svgRegex = /