Fix: fail CI when the vendored HTML parser bundle is stale.

Greptile caught that editing the bundle entry did not refresh the committed vendor file, and neither build nor the detector suite would notice. --check compares a fresh rebuild, bun run build runs that check, and the detector suite now triggers on the entry.

AI-assisted.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Abdul Wahab
2026-09-03 08:24:16 -07:00
committed by Paul Bakaus
co-authored by Cursor
parent f4f16e3802
commit 894b95b988
4 changed files with 70 additions and 22 deletions
+40 -19
View File
@@ -5,9 +5,11 @@
* by bundling htmlparser2, css-select, css-tree, and domutils for skill/plugin installs.
*
* Run: node scripts/build-static-html-parsers.js
* Check: node scripts/build-static-html-parsers.js --check
*/
import fs from 'fs';
import os from 'node:os';
import path from 'path';
import { fileURLToPath } from 'url';
import { spawnSync } from 'node:child_process';
@@ -18,29 +20,48 @@ const ROOT = path.resolve(__dirname, '..');
const ENTRY = path.join(__dirname, 'lib/static-html-parsers.entry.mjs');
const OUT_DIR = path.join(ROOT, 'cli/engine/vendor');
const OUTPUT = path.join(OUT_DIR, 'static-html-parsers.mjs');
fs.mkdirSync(OUT_DIR, { recursive: true });
const result = spawnSync(
'bun',
['build', ENTRY, '--outfile', OUTPUT, '--target', 'node', '--format', 'esm'],
{ cwd: ROOT, encoding: 'utf8' },
);
if (result.status !== 0) {
process.stderr.write(result.stderr || result.stdout || 'bun build failed\n');
process.exit(result.status ?? 1);
}
const bundled = fs.readFileSync(OUTPUT, 'utf8');
const output = `/**
const HEADER = `/**
* GENERATED -- do not edit. Source: scripts/lib/static-html-parsers.entry.mjs
* Rebuild: node scripts/build-static-html-parsers.js
*
* Bundles htmlparser2, css-select, css-tree, and domutils for skill/plugin installs.
* Third-party licenses: see NOTICE.md.
*/
${bundled}`;
`;
fs.writeFileSync(OUTPUT, output);
console.log(`Generated ${path.relative(ROOT, OUTPUT)} (${(output.length / 1024).toFixed(1)} KB)`);
function generate(outfile) {
fs.mkdirSync(path.dirname(outfile), { recursive: true });
const result = spawnSync(
'bun',
['build', ENTRY, '--outfile', outfile, '--target', 'node', '--format', 'esm'],
{ cwd: ROOT, encoding: 'utf8' },
);
if (result.status !== 0) {
process.stderr.write(result.stderr || result.stdout || 'bun build failed\n');
process.exit(result.status ?? 1);
}
const output = HEADER + fs.readFileSync(outfile, 'utf8');
fs.writeFileSync(outfile, output);
return output;
}
if (process.argv.includes('--check')) {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'impeccable-static-html-parsers-'));
const tmpFile = path.join(tmpDir, 'static-html-parsers.mjs');
try {
const fresh = generate(tmpFile);
const committed = fs.readFileSync(OUTPUT, 'utf8');
if (fresh !== committed) {
process.stderr.write(
'cli/engine/vendor/static-html-parsers.mjs is stale. Run: node scripts/build-static-html-parsers.js\n',
);
process.exit(1);
}
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
process.exit(0);
}
generate(OUTPUT);
console.log(`Generated ${path.relative(ROOT, OUTPUT)} (${(fs.statSync(OUTPUT).size / 1024).toFixed(1)} KB)`);
+2 -1
View File
@@ -25,7 +25,7 @@ export const SUITES = {
description: 'Build, provider transforms, CLI helpers, context, and storage unit tests.',
triggers: [
...COMMON_INFRA_PATTERNS,
/^scripts\/(?!benchmark-detector|build-browser-detector|build-static-html-parsers|build-extension)/,
/^scripts\/(?!benchmark-detector|build-browser-detector|build-static-html-parsers|build-extension|lib\/static-html-parsers\.entry)/,
/^skill\/(SKILL\.src\.md|agents\/|reference\/|scripts\/(cleanup-deprecated|comp-diff|comp-spec|build-phase|font-match|data\/font-index|concept-seed|generate-image|context|context-signals|critique-storage|design-parser|doctor|hook|impeccable-paths|is-generated|lib\/(artifact-schema|png|raster|image-metrics|font-fingerprint|font-index|hero-checks|composition-catalog|concept-catalog|provider|staleness|staleness-deep|staleness-notice|surface-briefs|target-slug|template-extensions)|pin|surface-brief))/,
/^README(\.npm)?\.md$/,
/^cli\/bin\//,
@@ -96,6 +96,7 @@ export const SUITES = {
/^cli\/engine\//,
/^extension\/(background|content|detector|devtools|popup|manifest\.json)/,
/^scripts\/(benchmark-detector|build-browser-detector|build-static-html-parsers|build-extension)\.js$/,
/^scripts\/lib\/static-html-parsers\.entry\.mjs$/,
/^site\/(pages\/detector|public\/antipattern|data\/anti-patterns-catalog\.js)/,
/^tests\/fixtures\/antipatterns/,
],