#!/usr/bin/env node /** * Build-time HTML templating system for DocFast. * No dependencies — uses only Node.js built-ins. * * - Reads page sources from templates/pages/*.html * - Reads partials from templates/partials/*.html * - Replaces {{> partial_name}} with partial content * - Supports metadata comments at top of page files * - Replaces {{key}} variables with extracted metadata * - Writes output to public/ */ import { readFileSync, writeFileSync, readdirSync } from 'node:fs'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); const ROOT = join(__dirname, '..'); const PAGES_DIR = join(ROOT, 'templates', 'pages'); const PARTIALS_DIR = join(ROOT, 'templates', 'partials'); const OUTPUT_DIR = join(ROOT, 'public'); // Load all partials const partials = {}; for (const file of readdirSync(PARTIALS_DIR)) { if (!file.endsWith('.html')) continue; const name = file.replace('.html', ''); partials[name] = readFileSync(join(PARTIALS_DIR, file), 'utf-8'); } console.log(`Loaded ${Object.keys(partials).length} partials: ${Object.keys(partials).join(', ')}`); // Process each page const pages = readdirSync(PAGES_DIR).filter(f => f.endsWith('.html')); console.log(`Processing ${pages.length} pages...`); for (const file of pages) { let content = readFileSync(join(PAGES_DIR, file), 'utf-8'); // Extract all metadata comments from the top const vars = {}; while (true) { const m = content.match(/^\n?/); if (!m) break; vars[m[1]] = m[2]; content = content.slice(m[0].length); } // Replace {{> partial_name}} with partial content (support nested partials) let maxDepth = 5; while (maxDepth-- > 0 && content.includes('{{>')) { content = content.replace(/\{\{>\s*([a-zA-Z0-9_-]+)\s*\}\}/g, (match, name) => { if (!(name in partials)) { console.warn(` Warning: partial "${name}" not found in ${file}`); return match; } return partials[name]; }); } // Replace {{variable}} with extracted metadata content = content.replace(/\{\{([a-zA-Z_-]+)\}\}/g, (match, key) => { if (key in vars) return vars[key]; console.warn(` Warning: variable "${key}" not defined in ${file}`); return match; }); // Write output const outPath = join(OUTPUT_DIR, file); writeFileSync(outPath, content); console.log(` ✓ ${file} (${(content.length / 1024).toFixed(1)}KB)`); } console.log('Done!');