mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 06:06:37 +03:00
Fix CLI docs and browser detector bugs
- Fix README CLI examples to use `bun bin/impeccable.mjs` instead of `npx impeccable` - Fix classList.match() crash in Node/jsdom by converting DOMTokenList to string - Fix overlapping page-level banners by merging all findings into a single banner Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
ce64404248
commit
122dddb686
@@ -341,26 +341,27 @@ function checkColors(opts) {
|
||||
|
||||
// Tailwind class checks
|
||||
if (classList) {
|
||||
if (/\bbg-black\b/.test(classList)) {
|
||||
const classStr = typeof classList === 'string' ? classList : Array.from(classList).join(' ');
|
||||
if (/\bbg-black\b/.test(classStr)) {
|
||||
findings.push({ id: 'pure-black-white', snippet: 'bg-black' });
|
||||
}
|
||||
|
||||
const grayMatch = classList.match(/\btext-(?:gray|slate|zinc|neutral|stone)-\d+\b/);
|
||||
const colorBgMatch = classList.match(/\bbg-(?:red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-\d+\b/);
|
||||
const grayMatch = classStr.match(/\btext-(?:gray|slate|zinc|neutral|stone)-\d+\b/);
|
||||
const colorBgMatch = classStr.match(/\bbg-(?:red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-\d+\b/);
|
||||
if (grayMatch && colorBgMatch) {
|
||||
findings.push({ id: 'gray-on-color', snippet: `${grayMatch[0]} on ${colorBgMatch[0]}` });
|
||||
}
|
||||
|
||||
if (/\bbg-clip-text\b/.test(classList) && /\bbg-gradient-to-/.test(classList)) {
|
||||
if (/\bbg-clip-text\b/.test(classStr) && /\bbg-gradient-to-/.test(classStr)) {
|
||||
findings.push({ id: 'gradient-text', snippet: 'bg-clip-text + bg-gradient (Tailwind)' });
|
||||
}
|
||||
|
||||
const purpleText = classList.match(/\btext-(?:purple|violet|indigo)-\d+\b/);
|
||||
if (purpleText && (['h1', 'h2', 'h3'].includes(tag) || /\btext-(?:[2-9]xl)\b/.test(classList))) {
|
||||
const purpleText = classStr.match(/\btext-(?:purple|violet|indigo)-\d+\b/);
|
||||
if (purpleText && (['h1', 'h2', 'h3'].includes(tag) || /\btext-(?:[2-9]xl)\b/.test(classStr))) {
|
||||
findings.push({ id: 'ai-color-palette', snippet: `${purpleText[0]} on heading` });
|
||||
}
|
||||
|
||||
if (/\bfrom-(?:purple|violet|indigo)-\d+\b/.test(classList) && /\bto-(?:purple|violet|indigo|blue|cyan|pink|fuchsia)-\d+\b/.test(classList)) {
|
||||
if (/\bfrom-(?:purple|violet|indigo)-\d+\b/.test(classStr) && /\bto-(?:purple|violet|indigo|blue|cyan|pink|fuchsia)-\d+\b/.test(classStr)) {
|
||||
findings.push({ id: 'ai-color-palette', snippet: 'Purple/violet gradient (Tailwind)' });
|
||||
}
|
||||
}
|
||||
@@ -1395,9 +1396,11 @@ if (IS_BROWSER) {
|
||||
}
|
||||
}
|
||||
|
||||
const pageLevelFindings = [];
|
||||
|
||||
const typoFindings = checkTypography();
|
||||
if (typoFindings.length > 0) {
|
||||
showPageBanner(typoFindings);
|
||||
pageLevelFindings.push(...typoFindings);
|
||||
allFindings.push({ el: document.body, findings: typoFindings });
|
||||
}
|
||||
|
||||
@@ -1412,7 +1415,7 @@ if (IS_BROWSER) {
|
||||
// Page-level quality checks (headings, etc.)
|
||||
const qualityFindings = checkPageQualityDOM();
|
||||
if (qualityFindings.length > 0) {
|
||||
showPageBanner(qualityFindings);
|
||||
pageLevelFindings.push(...qualityFindings);
|
||||
allFindings.push({ el: document.body, findings: qualityFindings });
|
||||
}
|
||||
|
||||
@@ -1420,10 +1423,14 @@ if (IS_BROWSER) {
|
||||
const htmlPatternFindings = checkHtmlPatterns(document.documentElement.outerHTML);
|
||||
if (htmlPatternFindings.length > 0) {
|
||||
const mapped = htmlPatternFindings.map(f => ({ type: f.id, detail: f.snippet }));
|
||||
showPageBanner(mapped);
|
||||
pageLevelFindings.push(...mapped);
|
||||
allFindings.push({ el: document.body, findings: mapped });
|
||||
}
|
||||
|
||||
if (pageLevelFindings.length > 0) {
|
||||
showPageBanner(pageLevelFindings);
|
||||
}
|
||||
|
||||
printSummary(allFindings);
|
||||
return allFindings;
|
||||
};
|
||||
|
||||
@@ -150,10 +150,10 @@ Most commands accept an optional argument to focus on a specific area:
|
||||
Impeccable includes a standalone CLI for detecting anti-patterns without an AI harness:
|
||||
|
||||
```bash
|
||||
npx impeccable detect src/ # scan a directory
|
||||
npx impeccable detect index.html # scan an HTML file
|
||||
npx impeccable detect https://example.com # scan a URL (Puppeteer)
|
||||
npx impeccable detect --fast --json . # regex-only, JSON output
|
||||
bun bin/impeccable.mjs detect src/ # scan a directory
|
||||
bun bin/impeccable.mjs detect index.html # scan an HTML file
|
||||
bun bin/impeccable.mjs detect https://example.com # scan a URL (Puppeteer)
|
||||
bun bin/impeccable.mjs detect --fast --json . # regex-only, JSON output
|
||||
```
|
||||
|
||||
The detector catches 25 issues across AI slop (side-tab borders, purple gradients, bounce easing, dark glows) and general design quality (line length, cramped padding, small touch targets, skipped headings, and more).
|
||||
|
||||
@@ -339,26 +339,27 @@ function checkColors(opts) {
|
||||
|
||||
// Tailwind class checks
|
||||
if (classList) {
|
||||
if (/\bbg-black\b/.test(classList)) {
|
||||
const classStr = typeof classList === 'string' ? classList : Array.from(classList).join(' ');
|
||||
if (/\bbg-black\b/.test(classStr)) {
|
||||
findings.push({ id: 'pure-black-white', snippet: 'bg-black' });
|
||||
}
|
||||
|
||||
const grayMatch = classList.match(/\btext-(?:gray|slate|zinc|neutral|stone)-\d+\b/);
|
||||
const colorBgMatch = classList.match(/\bbg-(?:red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-\d+\b/);
|
||||
const grayMatch = classStr.match(/\btext-(?:gray|slate|zinc|neutral|stone)-\d+\b/);
|
||||
const colorBgMatch = classStr.match(/\bbg-(?:red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-\d+\b/);
|
||||
if (grayMatch && colorBgMatch) {
|
||||
findings.push({ id: 'gray-on-color', snippet: `${grayMatch[0]} on ${colorBgMatch[0]}` });
|
||||
}
|
||||
|
||||
if (/\bbg-clip-text\b/.test(classList) && /\bbg-gradient-to-/.test(classList)) {
|
||||
if (/\bbg-clip-text\b/.test(classStr) && /\bbg-gradient-to-/.test(classStr)) {
|
||||
findings.push({ id: 'gradient-text', snippet: 'bg-clip-text + bg-gradient (Tailwind)' });
|
||||
}
|
||||
|
||||
const purpleText = classList.match(/\btext-(?:purple|violet|indigo)-\d+\b/);
|
||||
if (purpleText && (['h1', 'h2', 'h3'].includes(tag) || /\btext-(?:[2-9]xl)\b/.test(classList))) {
|
||||
const purpleText = classStr.match(/\btext-(?:purple|violet|indigo)-\d+\b/);
|
||||
if (purpleText && (['h1', 'h2', 'h3'].includes(tag) || /\btext-(?:[2-9]xl)\b/.test(classStr))) {
|
||||
findings.push({ id: 'ai-color-palette', snippet: `${purpleText[0]} on heading` });
|
||||
}
|
||||
|
||||
if (/\bfrom-(?:purple|violet|indigo)-\d+\b/.test(classList) && /\bto-(?:purple|violet|indigo|blue|cyan|pink|fuchsia)-\d+\b/.test(classList)) {
|
||||
if (/\bfrom-(?:purple|violet|indigo)-\d+\b/.test(classStr) && /\bto-(?:purple|violet|indigo|blue|cyan|pink|fuchsia)-\d+\b/.test(classStr)) {
|
||||
findings.push({ id: 'ai-color-palette', snippet: 'Purple/violet gradient (Tailwind)' });
|
||||
}
|
||||
}
|
||||
@@ -1393,9 +1394,11 @@ if (IS_BROWSER) {
|
||||
}
|
||||
}
|
||||
|
||||
const pageLevelFindings = [];
|
||||
|
||||
const typoFindings = checkTypography();
|
||||
if (typoFindings.length > 0) {
|
||||
showPageBanner(typoFindings);
|
||||
pageLevelFindings.push(...typoFindings);
|
||||
allFindings.push({ el: document.body, findings: typoFindings });
|
||||
}
|
||||
|
||||
@@ -1410,7 +1413,7 @@ if (IS_BROWSER) {
|
||||
// Page-level quality checks (headings, etc.)
|
||||
const qualityFindings = checkPageQualityDOM();
|
||||
if (qualityFindings.length > 0) {
|
||||
showPageBanner(qualityFindings);
|
||||
pageLevelFindings.push(...qualityFindings);
|
||||
allFindings.push({ el: document.body, findings: qualityFindings });
|
||||
}
|
||||
|
||||
@@ -1418,10 +1421,14 @@ if (IS_BROWSER) {
|
||||
const htmlPatternFindings = checkHtmlPatterns(document.documentElement.outerHTML);
|
||||
if (htmlPatternFindings.length > 0) {
|
||||
const mapped = htmlPatternFindings.map(f => ({ type: f.id, detail: f.snippet }));
|
||||
showPageBanner(mapped);
|
||||
pageLevelFindings.push(...mapped);
|
||||
allFindings.push({ el: document.body, findings: mapped });
|
||||
}
|
||||
|
||||
if (pageLevelFindings.length > 0) {
|
||||
showPageBanner(pageLevelFindings);
|
||||
}
|
||||
|
||||
printSummary(allFindings);
|
||||
return allFindings;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user