docfast/scripts/build-html.cjs
Hoid 6fd707ab64
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 11m51s
feat: Add JS minification to build pipeline and expand test coverage
Task 1: Add JS minification to build pipeline (fix BUG-053)
- Update scripts/build-html.cjs to minify JS files in-place with terser
- Modified public/src/index.html and status.html to reference original JS files
- Add TDD test to verify JS minification works correctly

Task 2: Expand test coverage for untested routes
- Add tests for /v1/usage endpoint (auth required, admin access checks)
- Add tests for /v1/billing/checkout route (rate limiting, config checks)
- Add tests for rate limit headers on PDF conversion endpoints
- Add tests for 404 handler JSON error format for API vs HTML routes
- All tests follow TDD principles (RED → GREEN)

Task 3: Update swagger-jsdoc to fix npm audit vulnerability
- Upgraded swagger-jsdoc to 7.0.0-rc.6
- Resolved minimatch vulnerability via npm audit fix
- Verified OpenAPI generation still works correctly
- All 52 tests passing, 0 vulnerabilities remaining

Build improvements and security hardening complete.
2026-02-25 10:05:50 +00:00

64 lines
2.2 KiB
JavaScript

#!/usr/bin/env node
/**
* DocFast HTML Build Script
* Replaces {{> partial_name}} in source files with partial contents.
* Source: public/src/*.html → Output: public/*.html
* Partials: public/partials/_*.html
*/
const fs = require('fs');
const path = require('path');
const srcDir = path.join(__dirname, '..', 'public', 'src');
const outDir = path.join(__dirname, '..', 'public');
const partialsDir = path.join(__dirname, '..', 'public', 'partials');
// Load all partials
const partials = {};
if (fs.existsSync(partialsDir)) {
for (const f of fs.readdirSync(partialsDir)) {
if (f.startsWith('_') && f.endsWith('.html')) {
const name = f.replace(/^_/, '').replace(/\.html$/, '');
partials[name] = fs.readFileSync(path.join(partialsDir, f), 'utf-8').trimEnd();
}
}
}
console.log(`Loaded partials: ${Object.keys(partials).join(', ')}`);
if (!fs.existsSync(srcDir)) {
console.error(`Source directory not found: ${srcDir}`);
process.exit(1);
}
// Process each source file
const files = fs.readdirSync(srcDir).filter(f => f.endsWith('.html'));
for (const file of files) {
let content = fs.readFileSync(path.join(srcDir, file), 'utf-8');
// Replace {{> partial_name}} with partial content
content = content.replace(/\{\{>\s*(\w+)\s*\}\}/g, (match, name) => {
if (partials[name]) return partials[name];
console.warn(` Warning: partial '${name}' not found in ${file}`);
return match;
});
const outPath = path.join(outDir, file);
fs.writeFileSync(outPath, content);
console.log(` Built: ${file}`);
}
console.log('Done.');
// JS Minification (overwrite original files)
const { execSync } = require("child_process");
const jsFiles = ["public/app.js", "public/status.js"];
console.log("Minifying JS...");
for (const jsFile of jsFiles) {
const filePath = path.join(__dirname, "..", jsFile);
if (fs.existsSync(filePath)) {
// Create backup, minify, then overwrite original
const backupPath = filePath + ".bak";
fs.copyFileSync(filePath, backupPath);
execSync(`npx terser ${filePath} -o ${filePath} -c -m`, { stdio: "inherit" });
fs.unlinkSync(backupPath); // Clean up backup
console.log(` Minified: ${jsFile} (overwritten)`);
}
}