#!/usr/bin/env -S bun --no-env-file --config=/dev/null // gstack-design-craft — free craft check for a generated page (/design-html Step 4). // // Usage: gstack-design-craft [--accepted ] // // Prints one "CRAFT_CHECK: " line per tell, then // "CRAFT_RESULT: clean" (exit 0) or "CRAFT_RESULT: issue(s)" (exit 1). // --accepted reads the craft_exceptions a finalized.json recorded: a tell an // exception covers (same id, count at most the accepted count) prints as // "CRAFT_ACCEPTED: " and does not fail the check; the // result line then adds " ( accepted)" or ", accepted". // Exit 2: usage error, a non-HTML file, or an unreadable or empty file, with // nothing checked; or an unreadable or malformed exceptions file, after a // warning and a full check with no exceptions accepted, so a bad record never // hides the page's tells. Head and navigation rules run only on a full HTML // document; a fragment gets the copy and code rules alone. import { readFileSync } from 'fs'; import { acceptFindings, checkCraft, formatCraft, parseCraftExceptions, type CraftException } from '../lib/design-craft'; const USAGE = 'Usage: gstack-design-craft [--accepted ]'; const [file, flag, acceptedFile, ...rest] = process.argv.slice(2); if (!file || (flag !== undefined && (flag !== '--accepted' || !acceptedFile)) || rest.length > 0) { console.error(USAGE); process.exit(2); } if (!/\.html?$/i.test(file)) { console.error(`gstack-design-craft: ${file} is not an HTML file; check the rendered HTML preview instead`); process.exit(2); } let source: string; try { source = readFileSync(file, 'utf-8'); } catch (err) { console.error(`gstack-design-craft: cannot read ${file}: ${(err as Error).message}`); process.exit(2); } if (source.trim() === '') { console.error(`gstack-design-craft: ${file} is empty; nothing was checked`); process.exit(2); } let exceptions: CraftException[] = []; let badExceptions = false; if (acceptedFile) { try { exceptions = parseCraftExceptions(readFileSync(acceptedFile, 'utf-8')); } catch (err) { console.error(`gstack-design-craft: cannot use exceptions from ${acceptedFile}: ${(err as Error).message}; checked with none accepted`); badExceptions = true; } } const { issues, accepted } = acceptFindings(checkCraft(source), exceptions); console.log(formatCraft(issues, accepted)); process.exit(badExceptions ? 2 : issues.length === 0 ? 0 : 1);