ghost-qa 1.3.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +77 -24
  2. package/SKILL.md +78 -77
  3. package/dist/bin/ghost-qa.d.ts +10 -2
  4. package/dist/bin/ghost-qa.d.ts.map +1 -1
  5. package/dist/bin/ghost-qa.js +106 -16
  6. package/dist/bin/ghost-qa.js.map +1 -1
  7. package/dist/src/engine/audit-runner.d.ts +6 -5
  8. package/dist/src/engine/audit-runner.d.ts.map +1 -1
  9. package/dist/src/engine/audit-runner.js +117 -60
  10. package/dist/src/engine/audit-runner.js.map +1 -1
  11. package/dist/src/engine/browser-session.d.ts +3 -3
  12. package/dist/src/engine/browser-session.d.ts.map +1 -1
  13. package/dist/src/engine/browser-session.js +18 -7
  14. package/dist/src/engine/browser-session.js.map +1 -1
  15. package/dist/src/engine/compare.d.ts +37 -0
  16. package/dist/src/engine/compare.d.ts.map +1 -0
  17. package/dist/src/engine/compare.js +63 -0
  18. package/dist/src/engine/compare.js.map +1 -0
  19. package/dist/src/engine/health-score.d.ts +14 -0
  20. package/dist/src/engine/health-score.d.ts.map +1 -0
  21. package/dist/src/engine/health-score.js +74 -0
  22. package/dist/src/engine/health-score.js.map +1 -0
  23. package/dist/src/engine/version.d.ts +14 -0
  24. package/dist/src/engine/version.d.ts.map +1 -0
  25. package/dist/src/engine/version.js +43 -0
  26. package/dist/src/engine/version.js.map +1 -0
  27. package/dist/src/index.d.ts +6 -0
  28. package/dist/src/index.d.ts.map +1 -1
  29. package/dist/src/index.js +6 -0
  30. package/dist/src/index.js.map +1 -1
  31. package/dist/src/mcp/server.d.ts +24 -4
  32. package/dist/src/mcp/server.d.ts.map +1 -1
  33. package/dist/src/mcp/server.js +43 -5
  34. package/dist/src/mcp/server.js.map +1 -1
  35. package/dist/src/reporter/agent-diagnostic.d.ts +6 -0
  36. package/dist/src/reporter/agent-diagnostic.d.ts.map +1 -1
  37. package/dist/src/reporter/agent-diagnostic.js +52 -2
  38. package/dist/src/reporter/agent-diagnostic.js.map +1 -1
  39. package/dist/src/reporter/html-report.d.ts.map +1 -1
  40. package/dist/src/reporter/html-report.js +79 -4
  41. package/dist/src/reporter/html-report.js.map +1 -1
  42. package/dist/src/reporter/terminal-summary.d.ts.map +1 -1
  43. package/dist/src/reporter/terminal-summary.js +6 -0
  44. package/dist/src/reporter/terminal-summary.js.map +1 -1
  45. package/dist/src/traps/a11y-trap.d.ts +23 -0
  46. package/dist/src/traps/a11y-trap.d.ts.map +1 -1
  47. package/dist/src/traps/a11y-trap.js +185 -0
  48. package/dist/src/traps/a11y-trap.js.map +1 -1
  49. package/dist/src/traps/console-trap.d.ts +3 -1
  50. package/dist/src/traps/console-trap.d.ts.map +1 -1
  51. package/dist/src/traps/console-trap.js +41 -0
  52. package/dist/src/traps/console-trap.js.map +1 -1
  53. package/dist/src/traps/layout-trap.d.ts +31 -0
  54. package/dist/src/traps/layout-trap.d.ts.map +1 -1
  55. package/dist/src/traps/layout-trap.js +173 -0
  56. package/dist/src/traps/layout-trap.js.map +1 -1
  57. package/dist/src/traps/links-trap.d.ts +34 -0
  58. package/dist/src/traps/links-trap.d.ts.map +1 -0
  59. package/dist/src/traps/links-trap.js +136 -0
  60. package/dist/src/traps/links-trap.js.map +1 -0
  61. package/dist/src/traps/network-trap.d.ts +4 -1
  62. package/dist/src/traps/network-trap.d.ts.map +1 -1
  63. package/dist/src/traps/network-trap.js +29 -2
  64. package/dist/src/traps/network-trap.js.map +1 -1
  65. package/dist/src/traps/perf-trap.d.ts +18 -0
  66. package/dist/src/traps/perf-trap.d.ts.map +1 -1
  67. package/dist/src/traps/perf-trap.js +148 -8
  68. package/dist/src/traps/perf-trap.js.map +1 -1
  69. package/dist/src/traps/seo-trap.d.ts +30 -0
  70. package/dist/src/traps/seo-trap.d.ts.map +1 -0
  71. package/dist/src/traps/seo-trap.js +98 -0
  72. package/dist/src/traps/seo-trap.js.map +1 -0
  73. package/dist/src/traps/theme-trap.d.ts +32 -0
  74. package/dist/src/traps/theme-trap.d.ts.map +1 -0
  75. package/dist/src/traps/theme-trap.js +109 -0
  76. package/dist/src/traps/theme-trap.js.map +1 -0
  77. package/dist/src/types.d.ts +55 -3
  78. package/dist/src/types.d.ts.map +1 -1
  79. package/dist/src/types.js +30 -2
  80. package/dist/src/types.js.map +1 -1
  81. package/package.json +11 -3
@@ -6,7 +6,25 @@ export const EMPTY_A11Y_METRICS = {
6
6
  inputsMissingLabel: [],
7
7
  hasDocumentTitle: true,
8
8
  hasHtmlLang: true,
9
+ contrastFailures: [],
10
+ headingProblems: [],
11
+ focusProblems: [],
9
12
  };
13
+ /** WCAG relative luminance of an sRGB colour. */
14
+ export function relativeLuminance(r, g, b) {
15
+ const linear = (channel) => {
16
+ const s = channel / 255;
17
+ return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
18
+ };
19
+ return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
20
+ }
21
+ /** WCAG contrast ratio (1–21) between two sRGB colours. */
22
+ export function contrastRatio(fg, bg) {
23
+ const l1 = relativeLuminance(...fg);
24
+ const l2 = relativeLuminance(...bg);
25
+ const [hi, lo] = l1 >= l2 ? [l1, l2] : [l2, l1];
26
+ return (hi + 0.05) / (lo + 0.05);
27
+ }
10
28
  const MAX_PER_KIND = 5;
11
29
  /**
12
30
  * Pure evaluator: DOM accessibility facts in, structured issues out.
@@ -58,6 +76,40 @@ export function evaluateA11yMetrics(metrics, route, viewport) {
58
76
  details: { element: descriptor },
59
77
  }));
60
78
  }
79
+ for (const failure of metrics.contrastFailures.slice(0, MAX_PER_KIND)) {
80
+ issues.push(makeIssue({
81
+ category: 'accessibility',
82
+ severity: 'major',
83
+ type: 'contrast-insufficient',
84
+ message: `Insufficient text contrast (WCAG 2.1 AA): ${failure.descriptor} has ratio ${failure.ratio}:1, needs ${failure.required}:1. Darken the text or lighten the background (or vice versa) — do not rely on opacity tricks.`,
85
+ route,
86
+ viewport,
87
+ details: { element: failure.descriptor, ratio: failure.ratio, required: failure.required },
88
+ selector: failure.selector,
89
+ }));
90
+ }
91
+ for (const problem of metrics.headingProblems.slice(0, MAX_PER_KIND)) {
92
+ issues.push(makeIssue({
93
+ category: 'accessibility',
94
+ severity: 'minor',
95
+ type: 'heading-hierarchy',
96
+ message: `Heading hierarchy problem: ${problem}. Keep one <h1> per page and never skip levels (h1 → h2 → h3) — screen-reader users navigate by headings.`,
97
+ route,
98
+ viewport,
99
+ details: { problem },
100
+ }));
101
+ }
102
+ for (const problem of metrics.focusProblems.slice(0, MAX_PER_KIND)) {
103
+ issues.push(makeIssue({
104
+ category: 'accessibility',
105
+ severity: 'major',
106
+ type: 'focus-not-visible',
107
+ message: `Keyboard focus problem: ${problem}. Every interactive element needs a visible :focus-visible style (outline or ring) — keyboard users must always know where focus is.`,
108
+ route,
109
+ viewport,
110
+ details: { problem },
111
+ }));
112
+ }
61
113
  if (!metrics.hasDocumentTitle) {
62
114
  issues.push(makeIssue({
63
115
  category: 'accessibility',
@@ -144,6 +196,80 @@ function probeA11y() {
144
196
  if (!hasLabel)
145
197
  inputsMissingLabel.push(describe(el));
146
198
  });
199
+ // Heading hierarchy: exactly one h1, no skipped levels.
200
+ const headingProblems = [];
201
+ const headings = Array.from(document.querySelectorAll('h1, h2, h3, h4, h5, h6'));
202
+ const h1Count = headings.filter((h) => h.tagName === 'H1').length;
203
+ if (headings.length > 0 && h1Count === 0)
204
+ headingProblems.push('page has headings but no <h1>');
205
+ if (h1Count > 1)
206
+ headingProblems.push(`page has ${h1Count} <h1> elements (expected exactly one)`);
207
+ let previousLevel = 0;
208
+ for (const heading of headings) {
209
+ const level = Number(heading.tagName.slice(1));
210
+ if (previousLevel > 0 && level > previousLevel + 1) {
211
+ headingProblems.push(`level skip h${previousLevel} → h${level} at "${(heading.textContent ?? '').replace(/\s+/g, ' ').trim().slice(0, 40)}"`);
212
+ }
213
+ previousLevel = level;
214
+ }
215
+ // Computed contrast: sample visible text-bearing elements and compute the
216
+ // real WCAG ratio between computed foreground and effective background.
217
+ const parseRgb = (value) => {
218
+ const match = value.match(/rgba?\(([^)]+)\)/);
219
+ if (!match)
220
+ return null;
221
+ const parts = match[1].split(',').map((p) => Number.parseFloat(p));
222
+ if (parts.length < 3 || parts.some((n) => Number.isNaN(n)))
223
+ return null;
224
+ return [parts[0], parts[1], parts[2], parts.length > 3 ? parts[3] : 1];
225
+ };
226
+ const luminance = (rgb) => {
227
+ const linear = (channel) => {
228
+ const s = channel / 255;
229
+ return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
230
+ };
231
+ return 0.2126 * linear(rgb[0]) + 0.7152 * linear(rgb[1]) + 0.0722 * linear(rgb[2]);
232
+ };
233
+ const effectiveBackground = (el) => {
234
+ let node = el;
235
+ while (node) {
236
+ const bg = parseRgb(window.getComputedStyle(node).backgroundColor);
237
+ if (bg && bg[3] > 0)
238
+ return [bg[0], bg[1], bg[2]];
239
+ node = node.parentElement;
240
+ }
241
+ return [255, 255, 255];
242
+ };
243
+ const contrastFailures = [];
244
+ const textCandidates = Array.from(document.querySelectorAll('body *')).slice(0, 400);
245
+ for (const el of textCandidates) {
246
+ if (contrastFailures.length >= 8)
247
+ break;
248
+ const html = el;
249
+ const ownText = Array.from(html.childNodes).some((n) => n.nodeType === Node.TEXT_NODE && (n.textContent ?? '').trim().length > 0);
250
+ if (!ownText || !visible(el))
251
+ continue;
252
+ const style = window.getComputedStyle(html);
253
+ const fg = parseRgb(style.color);
254
+ if (!fg)
255
+ continue;
256
+ const bg = effectiveBackground(el);
257
+ const l1 = luminance([fg[0], fg[1], fg[2]]);
258
+ const l2 = luminance(bg);
259
+ const ratio = (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
260
+ const fontSize = Number.parseFloat(style.fontSize) || 16;
261
+ const bold = Number.parseInt(style.fontWeight, 10) >= 700 || style.fontWeight === 'bold';
262
+ const large = fontSize >= 24 || (fontSize >= 18.66 && bold);
263
+ const required = large ? 3 : 4.5;
264
+ if (ratio < required) {
265
+ contrastFailures.push({
266
+ descriptor: describe(el),
267
+ selector: describe(el),
268
+ ratio: Math.round(ratio * 100) / 100,
269
+ required,
270
+ });
271
+ }
272
+ }
147
273
  return {
148
274
  buttonsWithoutName,
149
275
  linksWithoutName,
@@ -151,6 +277,27 @@ function probeA11y() {
151
277
  inputsMissingLabel,
152
278
  hasDocumentTitle: document.title.trim().length > 0,
153
279
  hasHtmlLang: (document.documentElement.getAttribute('lang') ?? '').trim().length > 0,
280
+ contrastFailures,
281
+ headingProblems,
282
+ focusProblems: [],
283
+ };
284
+ }
285
+ /** In-page probe: describes the currently focused element + focus styling. */
286
+ function probeFocusStep() {
287
+ const el = document.activeElement;
288
+ if (!el || el === document.body) {
289
+ return { descriptor: '(no element focused)', hasVisibleFocus: false, isBody: true };
290
+ }
291
+ const style = window.getComputedStyle(el);
292
+ const outlineVisible = style.outlineStyle !== 'none' && Number.parseFloat(style.outlineWidth) > 0;
293
+ const shadowVisible = style.boxShadow !== 'none' && style.boxShadow !== '';
294
+ const tag = el.tagName.toLowerCase();
295
+ const id = el.id ? `#${el.id}` : '';
296
+ const text = (el.textContent ?? '').replace(/\s+/g, ' ').trim().slice(0, 30);
297
+ return {
298
+ descriptor: `${tag}${id}${text ? ` "${text}"` : ''}`,
299
+ hasVisibleFocus: outlineVisible || shadowVisible,
300
+ isBody: false,
154
301
  };
155
302
  }
156
303
  /** Runs the in-page a11y probe against a live page and evaluates it. */
@@ -167,7 +314,45 @@ export class A11yTrap {
167
314
  catch {
168
315
  return [];
169
316
  }
317
+ metrics.focusProblems = await this.probeKeyboardFocus(page);
170
318
  return evaluateA11yMetrics(metrics, route, this.viewport);
171
319
  }
320
+ /**
321
+ * Automated keyboard tab-order verification: press Tab repeatedly and
322
+ * confirm focus actually moves and lands somewhere visibly styled.
323
+ */
324
+ async probeKeyboardFocus(page) {
325
+ const problems = [];
326
+ try {
327
+ const focusableCount = await page.evaluate(() => document.querySelectorAll('a[href], button:not([disabled]), input:not([disabled]), select, textarea, [tabindex]:not([tabindex="-1"])').length);
328
+ if (focusableCount === 0)
329
+ return problems;
330
+ let stuckTabs = 0;
331
+ let invisibleFocus = 0;
332
+ const steps = Math.min(12, focusableCount + 2);
333
+ for (let i = 0; i < steps; i++) {
334
+ await page.keyboard.press('Tab');
335
+ const step = await page.evaluate(probeFocusStep);
336
+ if (step.isBody) {
337
+ stuckTabs += 1;
338
+ }
339
+ else {
340
+ stuckTabs = 0;
341
+ if (!step.hasVisibleFocus)
342
+ invisibleFocus += 1;
343
+ }
344
+ }
345
+ if (stuckTabs >= 3) {
346
+ problems.push(`Tab key never moves focus onto any of the ${focusableCount} focusable elements (dead focus state — check tabindex and focus management).`);
347
+ }
348
+ else if (invisibleFocus >= 3) {
349
+ problems.push(`${invisibleFocus} focused elements show no visible focus indicator (no outline or focus ring) during Tab navigation.`);
350
+ }
351
+ }
352
+ catch {
353
+ /* keyboard simulation unsupported on this page — skip silently */
354
+ }
355
+ return problems;
356
+ }
172
357
  }
173
358
  //# sourceMappingURL=a11y-trap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"a11y-trap.js","sourceRoot":"","sources":["../../../src/traps/a11y-trap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"a11y-trap.js","sourceRoot":"","sources":["../../../src/traps/a11y-trap.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  import type { Page } from 'playwright';
2
2
  import { type QAIssue, type ViewportName } from '../types.js';
3
- export type ConsoleClassification = 'hydration-mismatch' | 'unhandled-rejection' | 'page-error' | 'console-error' | 'console-warning' | 'benign';
3
+ export type ConsoleClassification = 'hydration-mismatch' | 'unhandled-rejection' | 'duplicate-key-warning' | 'csp-violation' | 'page-error' | 'console-error' | 'console-warning' | 'benign';
4
+ export declare function isDuplicateKeyWarning(text: string): boolean;
5
+ export declare function isCspViolation(text: string): boolean;
4
6
  export declare function isHydrationError(text: string): boolean;
5
7
  export declare function isUnhandledRejection(text: string): boolean;
6
8
  export declare function isBenignConsoleNoise(text: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"console-trap.d.ts","sourceRoot":"","sources":["../../../src/traps/console-trap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAa,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzE,MAAM,MAAM,qBAAqB,GAC7B,oBAAoB,GACpB,qBAAqB,GACrB,YAAY,GACZ,eAAe,GACf,iBAAiB,GACjB,QAAQ,CAAC;AA+Bb,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,eAAe,GAAG,iBAAiB,GAAG,WAA6B,GAC1E,qBAAqB,CAOvB;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,YAAY,EACtB,MAAM,GAAE,eAAe,GAAG,iBAAiB,GAAG,WAA6B,EAC3E,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,GAAG,IAAI,CAwDhB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,CAAM;IAChC,OAAO,CAAC,KAAK,CAAO;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,YAAY;IAIlC,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IA4BxB,MAAM,IAAI,IAAI;CAGf"}
1
+ {"version":3,"file":"console-trap.d.ts","sourceRoot":"","sources":["../../../src/traps/console-trap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAa,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzE,MAAM,MAAM,qBAAqB,GAC7B,oBAAoB,GACpB,qBAAqB,GACrB,uBAAuB,GACvB,eAAe,GACf,YAAY,GACZ,eAAe,GACf,iBAAiB,GACjB,QAAQ,CAAC;AAeb,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AA+BD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,eAAe,GAAG,iBAAiB,GAAG,WAA6B,GAC1E,qBAAqB,CASvB;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,YAAY,EACtB,MAAM,GAAE,eAAe,GAAG,iBAAiB,GAAG,WAA6B,EAC3E,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,GAAG,IAAI,CA4EhB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,CAAM;IAChC,OAAO,CAAC,KAAK,CAAO;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,YAAY;IAIlC,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IA4BxB,MAAM,IAAI,IAAI;CAGf"}
@@ -1,4 +1,21 @@
1
1
  import { makeIssue } from '../types.js';
2
+ const DUPLICATE_KEY_PATTERNS = [
3
+ /encountered two children with the same key/i,
4
+ /duplicate key/i,
5
+ /same key.*twice/i,
6
+ ];
7
+ const CSP_PATTERNS = [
8
+ /content security policy/i,
9
+ /violates the following content security policy/i,
10
+ /refused to .* because it violates/i,
11
+ /CSP violation/i,
12
+ ];
13
+ export function isDuplicateKeyWarning(text) {
14
+ return DUPLICATE_KEY_PATTERNS.some((p) => p.test(text));
15
+ }
16
+ export function isCspViolation(text) {
17
+ return CSP_PATTERNS.some((p) => p.test(text));
18
+ }
2
19
  const HYDRATION_PATTERNS = [
3
20
  /hydration/i,
4
21
  /did not match/i,
@@ -45,6 +62,10 @@ export function classifyConsoleText(text, source = 'console-error') {
45
62
  return 'hydration-mismatch';
46
63
  if (isUnhandledRejection(text))
47
64
  return 'unhandled-rejection';
65
+ if (isDuplicateKeyWarning(text))
66
+ return 'duplicate-key-warning';
67
+ if (isCspViolation(text))
68
+ return 'csp-violation';
48
69
  if (source === 'pageerror')
49
70
  return 'page-error';
50
71
  if (source === 'console-warning')
@@ -87,6 +108,26 @@ export function consoleIssueFromText(text, route, viewport, source = 'console-er
87
108
  viewport,
88
109
  ...(stack ? { stack: stack.slice(0, 2000) } : {}),
89
110
  });
111
+ case 'duplicate-key-warning':
112
+ return makeIssue({
113
+ category: 'console',
114
+ severity: 'major',
115
+ type: 'duplicate-key-warning',
116
+ message: `React duplicate key warning: ${clean} Duplicate keys break reconciliation — keyed children can swap state, replay animations, or drop updates. Use a stable unique id per item.`,
117
+ route,
118
+ viewport,
119
+ ...(stack ? { stack: stack.slice(0, 2000) } : {}),
120
+ });
121
+ case 'csp-violation':
122
+ return makeIssue({
123
+ category: 'console',
124
+ severity: 'major',
125
+ type: 'csp-violation',
126
+ message: `Content-Security-Policy violation: ${clean} A resource was blocked by CSP — allowlist the origin in the policy or self-host the asset; never silence this by removing the CSP header.`,
127
+ route,
128
+ viewport,
129
+ ...(stack ? { stack: stack.slice(0, 2000) } : {}),
130
+ });
90
131
  case 'console-warning':
91
132
  return makeIssue({
92
133
  category: 'console',
@@ -1 +1 @@
1
- {"version":3,"file":"console-trap.js","sourceRoot":"","sources":["../../../src/traps/console-trap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"console-trap.js","sourceRoot":"","sources":["../../../src/traps/console-trap.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,27 @@ export interface OffendingElement {
5
5
  right: number;
6
6
  width: number;
7
7
  }
8
+ export interface ElementFinding {
9
+ descriptor: string;
10
+ selector: string;
11
+ box: {
12
+ x: number;
13
+ y: number;
14
+ width: number;
15
+ height: number;
16
+ };
17
+ }
18
+ export interface CollisionFinding {
19
+ first: string;
20
+ second: string;
21
+ selector: string;
22
+ box: {
23
+ x: number;
24
+ y: number;
25
+ width: number;
26
+ height: number;
27
+ };
28
+ }
8
29
  export interface LayoutMetrics {
9
30
  innerWidth: number;
10
31
  scrollWidth: number;
@@ -13,8 +34,18 @@ export interface LayoutMetrics {
13
34
  zeroSizeInteractives: string[];
14
35
  /** Images that finished loading but decoded to nothing. */
15
36
  brokenImages: string[];
37
+ /** Inline SVGs rendered with a 0×0 bounding box. */
38
+ brokenSvgs: string[];
16
39
  /** Elements extending past the right edge of the viewport. */
17
40
  overflowingElements: OffendingElement[];
41
+ /** Visible interactive elements overlapping each other (collision math). */
42
+ collisions: CollisionFinding[];
43
+ /** Touch targets below 44×44px on touch viewports (WCAG 2.5.5 / Apple HIG). */
44
+ smallTouchTargets: ElementFinding[];
45
+ /** Text containers whose content is unintentionally clipped. */
46
+ clippedText: ElementFinding[];
47
+ /** Interactive elements positioned entirely off-screen. */
48
+ offscreenInteractives: ElementFinding[];
18
49
  }
19
50
  export declare const EMPTY_METRICS: LayoutMetrics;
20
51
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"layout-trap.d.ts","sourceRoot":"","sources":["../../../src/traps/layout-trap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAa,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,uEAAuE;IACvE,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,2DAA2D;IAC3D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,8DAA8D;IAC9D,mBAAmB,EAAE,gBAAgB,EAAE,CAAC;CACzC;AAED,eAAO,MAAM,aAAa,EAAE,aAO3B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,YAAY,GACrB,OAAO,EAAE,CA0EX;AA2DD,8EAA8E;AAC9E,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAE5B,QAAQ,EAAE,YAAY;IAI5B,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAiB7D"}
1
+ {"version":3,"file":"layout-trap.d.ts","sourceRoot":"","sources":["../../../src/traps/layout-trap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAa,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,uEAAuE;IACvE,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,2DAA2D;IAC3D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,oDAAoD;IACpD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,8DAA8D;IAC9D,mBAAmB,EAAE,gBAAgB,EAAE,CAAC;IACxC,4EAA4E;IAC5E,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,+EAA+E;IAC/E,iBAAiB,EAAE,cAAc,EAAE,CAAC;IACpC,gEAAgE;IAChE,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,2DAA2D;IAC3D,qBAAqB,EAAE,cAAc,EAAE,CAAC;CACzC;AAED,eAAO,MAAM,aAAa,EAAE,aAY3B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,YAAY,GACrB,OAAO,EAAE,CA2JX;AAgKD,8EAA8E;AAC9E,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAE5B,QAAQ,EAAE,YAAY;IAI5B,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAiB7D"}
@@ -6,7 +6,12 @@ export const EMPTY_METRICS = {
6
6
  hasViewportMeta: false,
7
7
  zeroSizeInteractives: [],
8
8
  brokenImages: [],
9
+ brokenSvgs: [],
9
10
  overflowingElements: [],
11
+ collisions: [],
12
+ smallTouchTargets: [],
13
+ clippedText: [],
14
+ offscreenInteractives: [],
10
15
  };
11
16
  /**
12
17
  * Pure evaluator: DOM geometry in, structured layout issues out.
@@ -60,6 +65,72 @@ export function evaluateLayoutMetrics(metrics, route, viewport) {
60
65
  details: { src },
61
66
  }));
62
67
  }
68
+ for (const src of metrics.brokenSvgs.slice(0, 5)) {
69
+ issues.push(makeIssue({
70
+ category: 'network',
71
+ severity: 'major',
72
+ type: 'broken-svg',
73
+ message: `Broken inline SVG (0×0 bounding box): ${src}. Give the <svg> explicit width/height or a viewBox with CSS size so it actually renders.`,
74
+ route,
75
+ viewport,
76
+ details: { element: src },
77
+ selector: src,
78
+ }));
79
+ }
80
+ for (const hit of metrics.collisions.slice(0, 5)) {
81
+ issues.push(makeIssue({
82
+ category: 'layout',
83
+ severity: 'major',
84
+ type: 'element-collision',
85
+ message: `Overlapping interactive elements: ${hit.first} overlaps ${hit.second}. Overlapping tap/click targets cause mis-taps — fix stacking (z-index), absolute positioning, or flow layout.`,
86
+ route,
87
+ viewport,
88
+ details: { first: hit.first, second: hit.second },
89
+ selector: hit.selector,
90
+ boundingBox: hit.box,
91
+ }));
92
+ }
93
+ if (viewport !== 'desktop') {
94
+ for (const target of metrics.smallTouchTargets.slice(0, 5)) {
95
+ issues.push(makeIssue({
96
+ category: 'layout',
97
+ severity: 'major',
98
+ type: 'small-touch-target',
99
+ message: `Touch target too small on ${viewport}: ${target.descriptor} is ${Math.round(target.box.width)}×${Math.round(target.box.height)}px (minimum 44×44px per WCAG 2.5.5 / Apple HIG). Increase padding or min-height/min-width.`,
100
+ route,
101
+ viewport,
102
+ details: { element: target.descriptor, width: Math.round(target.box.width), height: Math.round(target.box.height) },
103
+ selector: target.selector,
104
+ boundingBox: target.box,
105
+ }));
106
+ }
107
+ }
108
+ for (const clipped of metrics.clippedText.slice(0, 5)) {
109
+ issues.push(makeIssue({
110
+ category: 'layout',
111
+ severity: 'minor',
112
+ type: 'clipped-text',
113
+ message: `Text may be unintentionally clipped: ${clipped.descriptor} (content overflows its box with overflow hidden). Allow the container to grow, wrap, or scroll intentionally.`,
114
+ route,
115
+ viewport,
116
+ details: { element: clipped.descriptor },
117
+ selector: clipped.selector,
118
+ boundingBox: clipped.box,
119
+ }));
120
+ }
121
+ for (const off of metrics.offscreenInteractives.slice(0, 5)) {
122
+ issues.push(makeIssue({
123
+ category: 'layout',
124
+ severity: 'major',
125
+ type: 'offscreen-interactive',
126
+ message: `Interactive element is positioned off-screen and unreachable: ${off.descriptor}. Check transforms, absolute positioning and negative offsets.`,
127
+ route,
128
+ viewport,
129
+ details: { element: off.descriptor },
130
+ selector: off.selector,
131
+ boundingBox: off.box,
132
+ }));
133
+ }
63
134
  if (viewport === 'mobile' && !metrics.hasViewportMeta) {
64
135
  issues.push(makeIssue({
65
136
  category: 'layout',
@@ -93,12 +164,109 @@ function probeLayout() {
93
164
  zeroSizeInteractives.push(describe(el));
94
165
  }
95
166
  });
167
+ const cssPath = (el) => {
168
+ if (el.id)
169
+ return `#${el.id}`;
170
+ const testid = el.getAttribute('data-testid');
171
+ if (testid)
172
+ return `[data-testid="${testid}"]`;
173
+ const parts = [];
174
+ let node = el;
175
+ while (node && node !== document.body && parts.length < 4) {
176
+ const tag = node.tagName.toLowerCase();
177
+ const parent = node.parentElement;
178
+ if (!parent) {
179
+ parts.unshift(tag);
180
+ break;
181
+ }
182
+ const siblings = Array.from(parent.children).filter((c) => c.tagName === node.tagName);
183
+ parts.unshift(siblings.length > 1 ? `${tag}:nth-of-type(${siblings.indexOf(node) + 1})` : tag);
184
+ node = parent;
185
+ }
186
+ return parts.join(' > ');
187
+ };
188
+ const boxOf = (el) => {
189
+ const r = el.getBoundingClientRect();
190
+ return { x: Math.round(r.x), y: Math.round(r.y), width: Math.round(r.width), height: Math.round(r.height) };
191
+ };
96
192
  const brokenImages = [];
97
193
  document.querySelectorAll('img').forEach((img) => {
98
194
  if (img.complete && img.naturalWidth === 0) {
99
195
  brokenImages.push(img.currentSrc || img.src || img.alt || '(image without src)');
100
196
  }
101
197
  });
198
+ const brokenSvgs = [];
199
+ document.querySelectorAll('svg').forEach((svg) => {
200
+ const rect = svg.getBoundingClientRect();
201
+ const style = window.getComputedStyle(svg);
202
+ if (style.display !== 'none' && (rect.width === 0 || rect.height === 0)) {
203
+ brokenSvgs.push(cssPath(svg));
204
+ }
205
+ });
206
+ // Geometry pass over visible interactives: collisions, touch targets,
207
+ // off-screen elements. Capped — this runs on every route/viewport.
208
+ const visibleInteractives = [];
209
+ document.querySelectorAll(interactiveSelector).forEach((el) => {
210
+ const style = window.getComputedStyle(el);
211
+ if (style.display === 'none' || style.visibility === 'hidden')
212
+ return;
213
+ visibleInteractives.push(el);
214
+ });
215
+ const smallTouchTargets = [];
216
+ const offscreenInteractives = [];
217
+ for (const el of visibleInteractives.slice(0, 120)) {
218
+ const rect = el.getBoundingClientRect();
219
+ if (rect.width > 0 && rect.height > 0 && (rect.width < 44 || rect.height < 44)) {
220
+ smallTouchTargets.push({ descriptor: describe(el), selector: cssPath(el), box: boxOf(el) });
221
+ }
222
+ if (rect.right <= 0 || rect.left >= window.innerWidth) {
223
+ offscreenInteractives.push({ descriptor: describe(el), selector: cssPath(el), box: boxOf(el) });
224
+ }
225
+ }
226
+ const collisions = [];
227
+ const collisionPool = visibleInteractives.slice(0, 80);
228
+ for (let i = 0; i < collisionPool.length && collisions.length < 5; i++) {
229
+ for (let j = i + 1; j < collisionPool.length && collisions.length < 5; j++) {
230
+ const a = collisionPool[i];
231
+ const b = collisionPool[j];
232
+ if (a.contains(b) || b.contains(a))
233
+ continue;
234
+ const ra = a.getBoundingClientRect();
235
+ const rb = b.getBoundingClientRect();
236
+ if (ra.width === 0 || rb.width === 0)
237
+ continue;
238
+ const overlapW = Math.min(ra.right, rb.right) - Math.max(ra.left, rb.left);
239
+ const overlapH = Math.min(ra.bottom, rb.bottom) - Math.max(ra.top, rb.top);
240
+ if (overlapW > 4 && overlapH > 4) {
241
+ const overlapArea = overlapW * overlapH;
242
+ const minArea = Math.min(ra.width * ra.height, rb.width * rb.height);
243
+ if (overlapArea < minArea * 0.9) {
244
+ collisions.push({
245
+ first: describe(a),
246
+ second: describe(b),
247
+ selector: cssPath(a),
248
+ box: boxOf(a),
249
+ });
250
+ }
251
+ }
252
+ }
253
+ }
254
+ const clippedText = [];
255
+ document.querySelectorAll('body *').forEach((el) => {
256
+ if (clippedText.length >= 5)
257
+ return;
258
+ const html = el;
259
+ if (!html.textContent?.trim())
260
+ return;
261
+ const style = window.getComputedStyle(html);
262
+ if (style.overflow !== 'hidden' && style.overflowX !== 'hidden' && style.overflowY !== 'hidden')
263
+ return;
264
+ if (html.scrollHeight > html.clientHeight + 2 || html.scrollWidth > html.clientWidth + 2) {
265
+ if (html.clientHeight > 0 && html.clientWidth > 0) {
266
+ clippedText.push({ descriptor: describe(el), selector: cssPath(el), box: boxOf(el) });
267
+ }
268
+ }
269
+ });
102
270
  const overflowingElements = [];
103
271
  const innerWidth = window.innerWidth;
104
272
  document.querySelectorAll('body *').forEach((el) => {
@@ -119,7 +287,12 @@ function probeLayout() {
119
287
  hasViewportMeta: Boolean(document.querySelector('meta[name="viewport"]')),
120
288
  zeroSizeInteractives,
121
289
  brokenImages,
290
+ brokenSvgs,
122
291
  overflowingElements,
292
+ collisions,
293
+ smallTouchTargets,
294
+ clippedText,
295
+ offscreenInteractives,
123
296
  };
124
297
  }
125
298
  /** Runs the in-page probe against a live Playwright page and evaluates it. */