/** * Free craft check for a page (/design-html Step 4, /design-review craft * audit). Counts the tells that make a page read as generated or unfinished: * placeholder content, AI cliché copy, scroll listeners, 100vh, dead links, * and the missing ship-floor tags. Copy checks read the visible text only * (script, style and tags removed); code checks read the source. Head checks * run only on a full document. Adapted from Elaya's landing-page-design and * redesign-skill (MIT); see NOTICE.md. Every id it prints is a * lib/design-catalog.ts entry and the fix beside it is that entry's `fix` * (test-enforced): buzzwords report under `marketing-buzzword`, whose * heuristic words BUZZWORDS covers, and `transition: all` under * `layout-transition`. */ import { catalogEntries } from './design-catalog'; /** The catalog's marketing-buzzword words plus Elaya's AI cliché words. */ export const BUZZWORDS: readonly string[] = [ 'seamless', 'effortless', 'supercharge', 'streamline', 'revolutionize', 'unlock', 'empower', 'elevate', 'unleash', 'next-gen', 'game-changer', 'delve', 'tapestry', 'in the world of', ]; function buzzwordPattern(): RegExp { const stem = (w: string) => w.replace(/-/g, '[- ]').replace(/e$/, ''); return new RegExp(`\\b(?:${BUZZWORDS.map(stem).join('|')})(?:e|es|ed|ing|ly|er|ers|s|d|eration)?\\b`, 'gi'); } export interface CraftFinding { id: string; count: number; fix: string; } interface CountRule { id: string; on: 'source' | 'text' | 'script'; pattern: RegExp; } interface PresenceRule { id: string; pattern: RegExp; } const COUNT_RULES: CountRule[] = [ { id: 'placeholder-name', on: 'text', pattern: /\b(?:John|Jane) Doe\b/gi }, { id: 'placeholder-brand', on: 'text', pattern: /\b(?:Acme|Nexus|SmartFlow)\b/g }, { id: 'lorem', on: 'text', pattern: /\blorem ipsum\b/gi }, { id: 'marketing-buzzword', on: 'text', pattern: buzzwordPattern() }, { id: 'round-number', on: 'text', pattern: /(?]*(?]*>/gi }, ]; const HEAD_RULES: PresenceRule[] = [ { id: 'missing-title', pattern: /