Merge 3 detection scripts into one universal file

Combine detect-antipatterns-core.mjs, detect-antipatterns.mjs, and
detect-antipatterns-browser-wrapper.js into a single universal file
that auto-detects browser vs Node via IS_BROWSER. Shared constants,
color utilities, and pure detection logic exist once instead of
being duplicated across files.

Build script simplified to strip @browser-strip-start/end markers,
set IS_BROWSER=true, and wrap in IIFE.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-03-17 19:17:00 -07:00
co-authored by Claude Opus 4.6
parent d8803c8151
commit d1d8929dc2
8 changed files with 2240 additions and 1521 deletions
+26 -19
View File
@@ -1,10 +1,8 @@
#!/usr/bin/env node
/**
* Generates public/js/detect-antipatterns-browser.js by:
* 1. Reading the core module (shared constants + pure functions)
* 2. Reading the browser wrapper template
* 3. Injecting the core into the wrapper's IIFE
* Generates .claude/skills/critique/scripts/detect-antipatterns-browser.js
* by stripping Node-specific sections from the universal source and wrapping in an IIFE.
*
* Run: node scripts/build-browser-detector.js
*/
@@ -16,22 +14,31 @@ import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(__dirname, '..');
const CORE_PATH = path.join(ROOT, 'source/skills/critique/scripts/detect-antipatterns-core.mjs');
const WRAPPER_PATH = path.join(ROOT, 'source/skills/critique/scripts/detect-antipatterns-browser-wrapper.js');
const OUTPUT_PATH = path.join(ROOT, '.claude/skills/critique/scripts/detect-antipatterns-browser.js');
const SOURCE = path.join(ROOT, 'source/skills/critique/scripts/detect-antipatterns.mjs');
const OUTPUT = path.join(ROOT, '.claude/skills/critique/scripts/detect-antipatterns-browser.js');
// Read and strip exports from core
let core = fs.readFileSync(CORE_PATH, 'utf-8');
core = core
.replace(/^export\s+/gm, '') // Remove 'export' keywords
.replace(/^\/\*\*[\s\S]*?\*\/\n/m, '') // Remove file-level JSDoc
.trim();
let code = fs.readFileSync(SOURCE, 'utf-8');
// Read the browser wrapper
const wrapper = fs.readFileSync(WRAPPER_PATH, 'utf-8');
// Strip shebang
code = code.replace(/^#!.*\n/, '');
// Strip sections between @browser-strip-start / @browser-strip-end markers
code = code.replace(/^\/\/ @browser-strip-start\n[\s\S]*?^\/\/ @browser-strip-end\n?/gm, '');
// Set IS_BROWSER = true (dead-code eliminates Node paths)
code = code.replace(/^const IS_BROWSER = .*$/m, 'const IS_BROWSER = true;');
// Inject core into the wrapper at the marker
const output = wrapper.replace('// {{CORE_INJECTION_POINT}}', core);
const output = `/**
* Anti-Pattern Browser Detector for Impeccable
* GENERATED — do not edit. Source: detect-antipatterns.mjs
* Rebuild: node scripts/build-browser-detector.js
*
* Usage: <script src="detect-antipatterns-browser.js"></script>
* Re-scan: window.impeccableScan()
*/
(function () {
if (typeof window === 'undefined') return;
${code}
})();
`;
fs.writeFileSync(OUTPUT_PATH, output);
console.log(` Generated ${path.relative(ROOT, OUTPUT_PATH)} (${(output.length / 1024).toFixed(1)} KB)`);
fs.writeFileSync(OUTPUT, output);
console.log(`\u2713 Generated ${path.relative(ROOT, OUTPUT)} (${(output.length / 1024).toFixed(1)} KB)`);