@pseolint/core 0.4.1 → 0.4.3

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 (67) hide show
  1. package/dist/auditor.d.ts +12 -1
  2. package/dist/auditor.d.ts.map +1 -1
  3. package/dist/auditor.js +240 -31
  4. package/dist/auditor.js.map +1 -1
  5. package/dist/formatters/bucket-findings.d.ts +43 -0
  6. package/dist/formatters/bucket-findings.d.ts.map +1 -0
  7. package/dist/formatters/bucket-findings.js +110 -0
  8. package/dist/formatters/bucket-findings.js.map +1 -0
  9. package/dist/formatters/console.d.ts.map +1 -1
  10. package/dist/formatters/console.js +103 -34
  11. package/dist/formatters/console.js.map +1 -1
  12. package/dist/formatters/fixplan.d.ts +13 -0
  13. package/dist/formatters/fixplan.d.ts.map +1 -0
  14. package/dist/formatters/fixplan.js +328 -0
  15. package/dist/formatters/fixplan.js.map +1 -0
  16. package/dist/formatters/html.d.ts.map +1 -1
  17. package/dist/formatters/html.js +27 -0
  18. package/dist/formatters/html.js.map +1 -1
  19. package/dist/formatters/index.d.ts +2 -0
  20. package/dist/formatters/index.d.ts.map +1 -1
  21. package/dist/formatters/index.js +1 -0
  22. package/dist/formatters/index.js.map +1 -1
  23. package/dist/formatters/markdown.d.ts.map +1 -1
  24. package/dist/formatters/markdown.js +77 -7
  25. package/dist/formatters/markdown.js.map +1 -1
  26. package/dist/page-filter.d.ts +64 -6
  27. package/dist/page-filter.d.ts.map +1 -1
  28. package/dist/page-filter.js +124 -3
  29. package/dist/page-filter.js.map +1 -1
  30. package/dist/rules/aeo/answer-first.d.ts.map +1 -1
  31. package/dist/rules/aeo/answer-first.js +17 -3
  32. package/dist/rules/aeo/answer-first.js.map +1 -1
  33. package/dist/rules/aeo/citable-facts.d.ts.map +1 -1
  34. package/dist/rules/aeo/citable-facts.js +12 -1
  35. package/dist/rules/aeo/citable-facts.js.map +1 -1
  36. package/dist/rules/aeo/content-modularity.d.ts.map +1 -1
  37. package/dist/rules/aeo/content-modularity.js +3 -0
  38. package/dist/rules/aeo/content-modularity.js.map +1 -1
  39. package/dist/rules/aeo/crawler-access.d.ts.map +1 -1
  40. package/dist/rules/aeo/crawler-access.js +6 -0
  41. package/dist/rules/aeo/crawler-access.js.map +1 -1
  42. package/dist/rules/aeo/faq-coverage.d.ts.map +1 -1
  43. package/dist/rules/aeo/faq-coverage.js +4 -0
  44. package/dist/rules/aeo/faq-coverage.js.map +1 -1
  45. package/dist/rules/aeo/freshness-signals.d.ts.map +1 -1
  46. package/dist/rules/aeo/freshness-signals.js +9 -2
  47. package/dist/rules/aeo/freshness-signals.js.map +1 -1
  48. package/dist/rules/aeo/llms-txt.d.ts.map +1 -1
  49. package/dist/rules/aeo/llms-txt.js +6 -1
  50. package/dist/rules/aeo/llms-txt.js.map +1 -1
  51. package/dist/rules/aeo/summary-bait.d.ts.map +1 -1
  52. package/dist/rules/aeo/summary-bait.js +5 -2
  53. package/dist/rules/aeo/summary-bait.js.map +1 -1
  54. package/dist/rules/content/missing-author.d.ts.map +1 -1
  55. package/dist/rules/content/missing-author.js +10 -2
  56. package/dist/rules/content/missing-author.js.map +1 -1
  57. package/dist/rules/spam/thin-content.d.ts.map +1 -1
  58. package/dist/rules/spam/thin-content.js +9 -1
  59. package/dist/rules/spam/thin-content.js.map +1 -1
  60. package/dist/site-classifier.d.ts +1 -1
  61. package/dist/site-classifier.d.ts.map +1 -1
  62. package/dist/site-classifier.js +216 -0
  63. package/dist/site-classifier.js.map +1 -1
  64. package/dist/types.d.ts +44 -0
  65. package/dist/types.d.ts.map +1 -1
  66. package/dist/types.js.map +1 -1
  67. package/package.json +1 -1
@@ -82,6 +82,13 @@ function renderCategoryTiles(categories) {
82
82
  })
83
83
  .join("");
84
84
  }
85
+ function confidenceCaveat(c) {
86
+ if (c === "low")
87
+ return "low confidence — known false-positive risk on this site type";
88
+ if (c === "speculative")
89
+ return "speculative — heuristic match; verify before acting";
90
+ return null;
91
+ }
85
92
  function renderFindingRow(f) {
86
93
  const tone = severityTone(f.severity);
87
94
  const effortPill = f.effort
@@ -90,6 +97,10 @@ function renderFindingRow(f) {
90
97
  const url = f.pageUrl ? `<span class="finding-url mono">${escapeHtml(shortenUrl(f.pageUrl))}</span>` : "";
91
98
  const fix = f.fix ? `<div class="fix"><span class="fix-label">Fix</span>${escapeHtml(f.fix)}</div>` : "";
92
99
  const docsHref = f.docsUrl ?? `https://pseolint.dev/rules/${f.ruleId.split("/").pop() ?? f.ruleId}`;
100
+ const caveat = confidenceCaveat(f.confidence);
101
+ const caveatPill = caveat
102
+ ? `<div class="caveat">${escapeHtml(caveat)}</div>`
103
+ : "";
93
104
  // Cluster context (collapsed details) — only on findings that carry one.
94
105
  let cluster = "";
95
106
  if (f.context?.type === "cluster") {
@@ -115,11 +126,23 @@ function renderFindingRow(f) {
115
126
  ${url}
116
127
  </div>
117
128
  <p class="finding-msg">${escapeHtml(f.message)}</p>
129
+ ${caveatPill}
118
130
  ${fix}
119
131
  ${cluster}
120
132
  <a class="docs-link" href="${escapeHtml(docsHref)}" target="_blank" rel="noopener">${escapeHtml(docsHref.replace(/^https?:\/\//, ""))} ↗</a>
121
133
  </li>`;
122
134
  }
135
+ /** v0.4.3 — "Audited as <type>" line shown under the verdict badge. */
136
+ function auditedAsHtml(c) {
137
+ if (!c)
138
+ return "";
139
+ const confPct = Math.round(c.confidence * 100);
140
+ const suppressed = c.suppressedRules.length;
141
+ const suppressedPart = suppressed > 0
142
+ ? ` ${suppressed} pSEO-only rule${suppressed === 1 ? "" : "s"} suppressed.`
143
+ : "";
144
+ return `<div class="audited-as">Audited as <strong>${escapeHtml(c.type)}</strong> (${confPct}% confidence).${escapeHtml(suppressedPart)}</div>`;
145
+ }
123
146
  function renderBucketSection(label, items, tone) {
124
147
  if (items.length === 0) {
125
148
  return `<section class="bucket bucket-empty">
@@ -311,6 +334,9 @@ export function formatHtml(summary, _options) {
311
334
  .sev.sev-warning{background:color-mix(in oklab,var(--warning) 14%,transparent);color:var(--warning);border-color:color-mix(in oklab,var(--warning) 35%,transparent)}
312
335
  .sev.sev-muted{background:var(--card-2);color:var(--muted);border-color:var(--border-strong)}
313
336
 
337
+ .caveat{margin-top:6px;padding:6px 10px;border-radius:8px;background:color-mix(in oklab,var(--warning) 8%,transparent);color:var(--warning);font-size:12px;line-height:1.4;border:1px solid color-mix(in oklab,var(--warning) 22%,transparent)}
338
+ .audited-as{display:block;margin-top:10px;font-size:13px;color:var(--muted);font-family:ui-monospace,"SFMono-Regular",Menlo,Consolas,monospace}
339
+ .audited-as strong{color:var(--fg)}
314
340
  .fix{margin-top:8px;padding:10px 12px;background:var(--card-2);border-radius:10px;color:var(--muted);font-size:13px;line-height:1.55}
315
341
  .fix-label{display:inline-block;margin-right:8px;padding:1px 6px;border-radius:4px;
316
342
  background:color-mix(in oklab,var(--primary) 18%,transparent);color:var(--primary);
@@ -361,6 +387,7 @@ export function formatHtml(summary, _options) {
361
387
 
362
388
  <section class="card">
363
389
  <span class="verdict-badge tone-${verdictTone}"><span class="verdict-dot"></span>${escapeHtml(VERDICT_LABEL[verdict])}</span>
390
+ ${auditedAsHtml(summary.siteClassification)}
364
391
  <span class="verdict-headline">${escapeHtml(summary.headline)}</span>
365
392
  <div class="cat-grid">${renderCategoryTiles(summary.categories)}</div>
366
393
  </section>
@@ -1 +1 @@
1
- {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/formatters/html.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/formatters/html.ts"],"names":[],"mappings":"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"}
@@ -6,4 +6,6 @@ export { formatMarkdown } from "./markdown.js";
6
6
  export type { MarkdownFormatOptions } from "./markdown.js";
7
7
  export { formatHtml } from "./html.js";
8
8
  export type { HtmlFormatOptions } from "./html.js";
9
+ export { formatFixplan } from "./fixplan.js";
10
+ export type { FixplanFormatOptions } from "./fixplan.js";
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC"}
@@ -2,4 +2,5 @@ export { formatConsole, aeoScoreLabel } from "./console.js";
2
2
  export { formatJson } from "./json.js";
3
3
  export { formatMarkdown } from "./markdown.js";
4
4
  export { formatHtml } from "./html.js";
5
+ export { formatFixplan } from "./fixplan.js";
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAMb,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,qBAAqB;IACpC,oIAAoI;IACpI,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAuBD,iBAAS,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAOnD;AAmED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,MAAM,CAoDR;AAGD,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAQb,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,qBAAqB;IACpC,oIAAoI;IACpI,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAuBD,iBAAS,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAOnD;AA0ID,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,MAAM,CAwDR;AAGD,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { bucketByTemplate } from "./bucket-findings.js";
1
2
  const VERDICT_GLYPH = {
2
3
  ready: "✅",
3
4
  caution: "⚠️",
@@ -26,10 +27,33 @@ function shortenUrl(url) {
26
27
  return url;
27
28
  }
28
29
  }
29
- function docsLink(f) {
30
- const url = f.docsUrl ?? `https://pseolint.dev/rules/${f.ruleId.split("/").pop() ?? f.ruleId}`;
30
+ function bucketDocsLink(b) {
31
+ const url = b.representativeDocsUrl ??
32
+ `https://pseolint.dev/rules/${b.ruleId.split("/").pop() ?? b.ruleId}`;
31
33
  return `[docs](${url})`;
32
34
  }
35
+ function effortPrefix(effort) {
36
+ return effort ? `[${effort}] ` : "";
37
+ }
38
+ /** v0.4.3 — caveat suffix for low-confidence findings, rendered inline. */
39
+ function confidenceCaveat(c) {
40
+ if (c === "low")
41
+ return "low confidence — known false-positive risk on this site type";
42
+ if (c === "speculative")
43
+ return "speculative — heuristic match; verify before acting";
44
+ return null;
45
+ }
46
+ /** v0.4.3 — "Audited as <type>" line shown under the verdict header. */
47
+ function auditedAsLine(c) {
48
+ if (!c)
49
+ return null;
50
+ const confPct = Math.round(c.confidence * 100);
51
+ const suppressed = c.suppressedRules.length;
52
+ const suppressedPart = suppressed > 0
53
+ ? ` ${suppressed} pSEO-only rule${suppressed === 1 ? "" : "s"} suppressed.`
54
+ : "";
55
+ return `_Audited as **${c.type}** (${confPct}% confidence).${suppressedPart}_`;
56
+ }
33
57
  function renderTriageMarkdown(triage) {
34
58
  const lines = ["", "## AI Triage", ""];
35
59
  const cost = triage.estimatedCostUsd !== undefined ? `, est $${triage.estimatedCostUsd.toFixed(2)}` : "";
@@ -55,17 +79,58 @@ function renderTriageMarkdown(triage) {
55
79
  }
56
80
  return lines.join("\n");
57
81
  }
82
+ /**
83
+ * Render a severity bucket. Findings are first collapsed by template
84
+ * signature so a single template bug surfaces once with a "Fix once,
85
+ * resolve all N" callout instead of N near-identical lines.
86
+ *
87
+ * Single-instance findings keep the legacy bullet format (no `### header`)
88
+ * so simple, low-volume reports still read like a flat list.
89
+ */
58
90
  function renderBucket(label, items) {
59
91
  const lines = [];
60
92
  if (items.length === 0)
61
93
  return lines;
62
94
  lines.push(`## ${label} (${items.length})`);
63
- for (const f of items) {
64
- const target = f.pageUrl ? ` — ${f.pageUrl}` : "";
65
- const message = f.fix ?? f.message;
66
- lines.push(`- **\`${f.ruleId}\`**${target} — ${message} ${docsLink(f)}`);
67
- }
68
95
  lines.push("");
96
+ const buckets = bucketByTemplate(items);
97
+ for (const b of buckets) {
98
+ const caveat = confidenceCaveat(b.representativeConfidence);
99
+ if (b.count === 1) {
100
+ const target = b.representativeUrl !== "<site-wide>" ? ` — ${b.representativeUrl}` : "";
101
+ const message = b.representativeFix ?? b.representativeMessage;
102
+ const eff = effortPrefix(b.effort);
103
+ lines.push(`- **\`${b.ruleId}\`**${target} — ${eff}${message} ${bucketDocsLink(b)}`);
104
+ if (caveat)
105
+ lines.push(` - _${caveat}_`);
106
+ continue;
107
+ }
108
+ // Multi-instance bucket: dedicated header + body block.
109
+ const isTemplateBucket = b.templateSignature !== null;
110
+ const eff = effortPrefix(b.effort);
111
+ const countLabel = isTemplateBucket
112
+ ? `× ${b.count} instances on \`${b.templateSignature}\` template`
113
+ : `× ${b.count} affected pages`;
114
+ lines.push(`### ${eff}\`${b.ruleId}\` ${countLabel}`);
115
+ lines.push("");
116
+ const moreSuffix = isTemplateBucket
117
+ ? ` — and ${b.count - 1} more page${b.count - 1 === 1 ? "" : "s"} match${b.count - 1 === 1 ? "es" : ""} this template.`
118
+ : ` — affecting ${b.count} pages total.`;
119
+ lines.push(`\`${b.representativeUrl}\` ${b.representativeMessage}${moreSuffix}`);
120
+ lines.push("");
121
+ if (caveat) {
122
+ lines.push(`> _${caveat}_`);
123
+ lines.push("");
124
+ }
125
+ if (b.representativeFix) {
126
+ const fixOnce = isTemplateBucket ? ` Fix once, resolve all ${b.count}.` : "";
127
+ lines.push(`**Fix:** ${b.representativeFix}${fixOnce} ${bucketDocsLink(b)}`);
128
+ }
129
+ else {
130
+ lines.push(bucketDocsLink(b));
131
+ }
132
+ lines.push("");
133
+ }
69
134
  return lines;
70
135
  }
71
136
  function categoryRows(categories) {
@@ -89,6 +154,11 @@ export function formatMarkdown(summary, _options) {
89
154
  lines.push(`# pseolint report`);
90
155
  lines.push("");
91
156
  lines.push(`**Verdict:** ${VERDICT_GLYPH[summary.verdict]} ${VERDICT_LABEL[summary.verdict]}`);
157
+ // v0.4.3 — show "Audited as <type>" right under the verdict so the
158
+ // operator knows which scoring profile produced the verdict.
159
+ const audited = auditedAsLine(summary.siteClassification);
160
+ if (audited)
161
+ lines.push(audited);
92
162
  lines.push(`**Risk:** ${summary.risk} / 100 (lower is better)`);
93
163
  lines.push("");
94
164
  lines.push(`**Headline:** ${summary.headline}`);
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Page-skip detection helpers used by the auditor pipeline (v0.4.1).
2
+ * Page-skip detection helpers used by the auditor pipeline (v0.4.1+).
3
3
  *
4
- * Two policy filters live here, each gated by an AuditOption:
4
+ * Five policy filters live here, each gated by an AuditOption:
5
5
  * - `detectNoindex(page)` honours `<meta name="robots" content="noindex">`
6
6
  * and `X-Robots-Tag: noindex` HTTP headers. The site owner already told
7
7
  * Google not to index these pages — auditing them produces noise the
@@ -12,8 +12,20 @@
12
12
  * regex). Two signals are required for a positive verdict, which keeps
13
13
  * the false-positive rate low: a marketing landing page with a single
14
14
  * password input or a single auth-shaped heading won't trip it.
15
+ * - `detectBoilerplatePage(page)` (v0.4.2) flags cookie / legal / consent /
16
+ * imprint pages. A single signal is enough because the patterns are
17
+ * anchored + specific (the title or H1 matches the whole-string compliance
18
+ * regex, or the URL path is one of the well-known compliance slugs).
19
+ * - `detectSearchResultPage(page)` (v0.4.2) flags pages that look like
20
+ * internal search-result URLs (query parameter `q` / `query` / `search` /
21
+ * `s` / `keyword`, or path under `/search`). Per Google's own guidance
22
+ * these should be noindex'd — auditing them generates noise.
23
+ * - `detectEmptyBodyPage(page)` (v0.4.2) flags un-hydrated SPA shells:
24
+ * body text < 100 chars, script tags present, and no substantive
25
+ * `<noscript>` fallback. These fail every content rule but the underlying
26
+ * fix is server-side rendering, not content quality.
15
27
  *
16
- * Both functions are pure and synchronous so they can be called inside the
28
+ * All functions are pure and synchronous so they can be called inside the
17
29
  * `parsedPages` map step without disrupting the existing pipeline shape.
18
30
  */
19
31
  import type { ParsedPage } from "./types.js";
@@ -36,15 +48,61 @@ export interface AuthDetectionResult {
36
48
  * borderline cases that might warrant a manual config exclude.
37
49
  */
38
50
  export declare function detectAuthPage(page: ParsedPage): AuthDetectionResult;
51
+ export interface BoilerplateDetectionResult {
52
+ isBoilerplate: boolean;
53
+ signals: Array<"boilerplate-title" | "boilerplate-h1" | "boilerplate-url">;
54
+ }
55
+ /**
56
+ * Heuristic boilerplate-page detection. Single-signal trigger (1+ = positive)
57
+ * because the patterns are anchored and specific — a marketing page that
58
+ * merely mentions "privacy" in its body won't fire any signal. Cookie / legal
59
+ * / consent / imprint pages exist for compliance, never as SEO targets, so
60
+ * auditing them produces routine findings the user already knows about.
61
+ */
62
+ export declare function detectBoilerplatePage(page: ParsedPage): BoilerplateDetectionResult;
63
+ /**
64
+ * Returns true when the URL has search-result hallmarks: a recognised search
65
+ * query parameter (`?q=`, `?query=`, `?search=`, `?s=`, `?keyword=`) or a
66
+ * pathname of `/search` or starting with `/search/`. Returns false for
67
+ * unparseable URLs (e.g. filesystem paths from local directory audits).
68
+ */
69
+ export declare function detectSearchResultPage(page: ParsedPage): boolean;
70
+ export interface EmptyBodyDetectionResult {
71
+ isEmpty: boolean;
72
+ reason?: string;
73
+ }
74
+ /**
75
+ * Heuristic detection of un-hydrated SPA shells. Three conditions must hold:
76
+ * 1. `contentText` (post-render-or-parse body text) trimmed < 100 chars
77
+ * 2. The HTML contains at least one `<script src=...>` tag (script-driven)
78
+ * 3. No substantive `<noscript>` fallback (combined noscript content
79
+ * <= 200 chars). A page with a long noscript block is doing
80
+ * progressive enhancement, not failing — don't flag it.
81
+ *
82
+ * Returns `{ isEmpty: true, reason: "spa-shell" }` when all three hold.
83
+ */
84
+ export declare function detectEmptyBodyPage(page: ParsedPage): EmptyBodyDetectionResult;
39
85
  /**
40
86
  * Combined skip decision for the auditor pipeline. Returns the reason string
41
87
  * to surface in `summary.skippedUrls` diagnostics, or `null` when the page
42
- * should be audited normally. Order matters: `noindex` takes priority over
43
- * `auth-detected` because it's the more specific (site-owner-declared) signal.
88
+ * should be audited normally. Order matters the priority is:
89
+ * `noindex` > `auth-detected` > `boilerplate` > `search-result` > `spa-shell`.
90
+ *
91
+ * - `noindex` first: the site-owner-declared signal beats every heuristic.
92
+ * - `auth-detected` next: a confirmed auth surface wins over generic
93
+ * boilerplate / search / shell heuristics.
94
+ * - `boilerplate` next: a clearly compliance-page-shaped URL beats the
95
+ * generic search/shell signals.
96
+ * - `search-result` next: explicit search hallmarks beat the empty-body
97
+ * fallback (a search page MAY be a SPA but the better label is "search").
98
+ * - `spa-shell` last: the most generic "we couldn't audit this" reason.
44
99
  */
45
100
  export interface PageSkipOptions {
46
101
  respectNoindex: boolean;
47
102
  skipDetectedAuth: boolean;
103
+ skipBoilerplate: boolean;
104
+ skipSearchPages: boolean;
105
+ skipEmptyBody: boolean;
48
106
  }
49
- export declare function pageSkipReason(page: ParsedPage, options: PageSkipOptions): "noindex" | "auth-detected" | null;
107
+ export declare function pageSkipReason(page: ParsedPage, options: PageSkipOptions): "noindex" | "auth-detected" | "boilerplate" | "search-result" | "spa-shell" | null;
50
108
  //# sourceMappingURL=page-filter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"page-filter.d.ts","sourceRoot":"","sources":["../src/page-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAIvD;AA6BD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC,gBAAgB,GAAG,YAAY,GAAG,SAAS,CAAC,CAAC;CAC7D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,mBAAmB,CAqBpE;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,eAAe,GACvB,SAAS,GAAG,eAAe,GAAG,IAAI,CAIpC"}
1
+ {"version":3,"file":"page-filter.d.ts","sourceRoot":"","sources":["../src/page-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAIvD;AA6BD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC,gBAAgB,GAAG,YAAY,GAAG,SAAS,CAAC,CAAC;CAC7D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,mBAAmB,CAqBpE;AAkBD,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC,mBAAmB,GAAG,gBAAgB,GAAG,iBAAiB,CAAC,CAAC;CAC5E;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,0BAA0B,CAyBlF;AASD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAgBhE;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,wBAAwB,CAoB9E;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,eAAe,GACvB,SAAS,GAAG,eAAe,GAAG,aAAa,GAAG,eAAe,GAAG,WAAW,GAAG,IAAI,CAOpF"}
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Page-skip detection helpers used by the auditor pipeline (v0.4.1).
2
+ * Page-skip detection helpers used by the auditor pipeline (v0.4.1+).
3
3
  *
4
- * Two policy filters live here, each gated by an AuditOption:
4
+ * Five policy filters live here, each gated by an AuditOption:
5
5
  * - `detectNoindex(page)` honours `<meta name="robots" content="noindex">`
6
6
  * and `X-Robots-Tag: noindex` HTTP headers. The site owner already told
7
7
  * Google not to index these pages — auditing them produces noise the
@@ -12,8 +12,20 @@
12
12
  * regex). Two signals are required for a positive verdict, which keeps
13
13
  * the false-positive rate low: a marketing landing page with a single
14
14
  * password input or a single auth-shaped heading won't trip it.
15
+ * - `detectBoilerplatePage(page)` (v0.4.2) flags cookie / legal / consent /
16
+ * imprint pages. A single signal is enough because the patterns are
17
+ * anchored + specific (the title or H1 matches the whole-string compliance
18
+ * regex, or the URL path is one of the well-known compliance slugs).
19
+ * - `detectSearchResultPage(page)` (v0.4.2) flags pages that look like
20
+ * internal search-result URLs (query parameter `q` / `query` / `search` /
21
+ * `s` / `keyword`, or path under `/search`). Per Google's own guidance
22
+ * these should be noindex'd — auditing them generates noise.
23
+ * - `detectEmptyBodyPage(page)` (v0.4.2) flags un-hydrated SPA shells:
24
+ * body text < 100 chars, script tags present, and no substantive
25
+ * `<noscript>` fallback. These fail every content rule but the underlying
26
+ * fix is server-side rendering, not content quality.
15
27
  *
16
- * Both functions are pure and synchronous so they can be called inside the
28
+ * All functions are pure and synchronous so they can be called inside the
17
29
  * `parsedPages` map step without disrupting the existing pipeline shape.
18
30
  */
19
31
  /**
@@ -76,11 +88,120 @@ export function detectAuthPage(page) {
76
88
  }
77
89
  return { isAuth: signals.length >= 2, signals };
78
90
  }
91
+ /**
92
+ * Boilerplate (cookie / legal / consent / imprint) title and H1 pattern.
93
+ * Whole-string match (anchored), case-insensitive. Applied to the title
94
+ * AFTER stripping the brand suffix (`Privacy Policy | MyApp` → `Privacy`).
95
+ */
96
+ const BOILERPLATE_TITLE_REGEX = /^(cookie|cookies|cookie[-\s]?policy|gdpr|ccpa|privacy|terms|terms[-\s](?:of[-\s])?(?:use|service|sale)|legal|disclaimer|impressum|imprint|do[-\s]not[-\s]sell|accessibility(?:[-\s]statement)?|copyright[-\s]notice)$/i;
97
+ /**
98
+ * Boilerplate URL pathname pattern. Matches `/cookies`, `/cookie-policy`,
99
+ * `/privacy`, `/terms/anything`, `/impressum`, etc. Anchored at path start
100
+ * so a marketing URL like `/blog/privacy-by-design` is NOT matched.
101
+ */
102
+ const BOILERPLATE_URL_REGEX = /^\/(?:cookies?|cookie-policy|gdpr|ccpa|privacy|terms|legal|disclaimer|impressum|imprint|accessibility|do-not-sell|copyright)(?:\/.*)?$/i;
103
+ /**
104
+ * Heuristic boilerplate-page detection. Single-signal trigger (1+ = positive)
105
+ * because the patterns are anchored and specific — a marketing page that
106
+ * merely mentions "privacy" in its body won't fire any signal. Cookie / legal
107
+ * / consent / imprint pages exist for compliance, never as SEO targets, so
108
+ * auditing them produces routine findings the user already knows about.
109
+ */
110
+ export function detectBoilerplatePage(page) {
111
+ const signals = [];
112
+ const cleanedTitle = stripBrandSuffix(page.title ?? "");
113
+ if (cleanedTitle && BOILERPLATE_TITLE_REGEX.test(cleanedTitle)) {
114
+ signals.push("boilerplate-title");
115
+ }
116
+ const firstH1 = (page.headings?.h1 ?? [])[0]?.trim() ?? "";
117
+ if (firstH1 && BOILERPLATE_TITLE_REGEX.test(firstH1)) {
118
+ signals.push("boilerplate-h1");
119
+ }
120
+ // URL pathname check. `page.url` may be a filesystem path on local audits,
121
+ // so wrap the URL parse in try/catch and skip the signal on failure.
122
+ try {
123
+ const pathname = new URL(page.url).pathname;
124
+ if (BOILERPLATE_URL_REGEX.test(pathname)) {
125
+ signals.push("boilerplate-url");
126
+ }
127
+ }
128
+ catch {
129
+ // unparseable URL (filesystem path); skip the URL signal
130
+ }
131
+ return { isBoilerplate: signals.length >= 1, signals };
132
+ }
133
+ /**
134
+ * Search-result query parameter names we treat as evidence of an internal
135
+ * search-result page. Compared case-insensitively against the URL's
136
+ * searchParams keys.
137
+ */
138
+ const SEARCH_QUERY_PARAMS = new Set(["q", "query", "search", "s", "keyword"]);
139
+ /**
140
+ * Returns true when the URL has search-result hallmarks: a recognised search
141
+ * query parameter (`?q=`, `?query=`, `?search=`, `?s=`, `?keyword=`) or a
142
+ * pathname of `/search` or starting with `/search/`. Returns false for
143
+ * unparseable URLs (e.g. filesystem paths from local directory audits).
144
+ */
145
+ export function detectSearchResultPage(page) {
146
+ let parsed;
147
+ try {
148
+ parsed = new URL(page.url);
149
+ }
150
+ catch {
151
+ return false;
152
+ }
153
+ for (const key of parsed.searchParams.keys()) {
154
+ if (SEARCH_QUERY_PARAMS.has(key.toLowerCase()))
155
+ return true;
156
+ }
157
+ const pathname = parsed.pathname;
158
+ if (pathname === "/search" || pathname.startsWith("/search/"))
159
+ return true;
160
+ return false;
161
+ }
162
+ /**
163
+ * Heuristic detection of un-hydrated SPA shells. Three conditions must hold:
164
+ * 1. `contentText` (post-render-or-parse body text) trimmed < 100 chars
165
+ * 2. The HTML contains at least one `<script src=...>` tag (script-driven)
166
+ * 3. No substantive `<noscript>` fallback (combined noscript content
167
+ * <= 200 chars). A page with a long noscript block is doing
168
+ * progressive enhancement, not failing — don't flag it.
169
+ *
170
+ * Returns `{ isEmpty: true, reason: "spa-shell" }` when all three hold.
171
+ */
172
+ export function detectEmptyBodyPage(page) {
173
+ const bodyLen = (page.contentText ?? "").trim().length;
174
+ if (bodyLen >= 100)
175
+ return { isEmpty: false };
176
+ const html = page.html ?? "";
177
+ if (!/<script\s[^>]*src\s*=/i.test(html))
178
+ return { isEmpty: false };
179
+ // Sum the visible content length of every <noscript>...</noscript> block.
180
+ // If the site provides a substantive noscript fallback, it's a
181
+ // progressive-enhancement page, not a broken SPA shell.
182
+ let noscriptTextLen = 0;
183
+ const noscriptRe = /<noscript[^>]*>([\s\S]*?)<\/noscript>/gi;
184
+ let match;
185
+ while ((match = noscriptRe.exec(html)) !== null) {
186
+ noscriptTextLen += match[1].replace(/<[^>]+>/g, "").trim().length;
187
+ if (noscriptTextLen > 200)
188
+ break;
189
+ }
190
+ if (noscriptTextLen > 200)
191
+ return { isEmpty: false };
192
+ return { isEmpty: true, reason: "spa-shell" };
193
+ }
79
194
  export function pageSkipReason(page, options) {
80
195
  if (options.respectNoindex && detectNoindex(page))
81
196
  return "noindex";
82
197
  if (options.skipDetectedAuth && detectAuthPage(page).isAuth)
83
198
  return "auth-detected";
199
+ if (options.skipBoilerplate && detectBoilerplatePage(page).isBoilerplate)
200
+ return "boilerplate";
201
+ if (options.skipSearchPages && detectSearchResultPage(page))
202
+ return "search-result";
203
+ if (options.skipEmptyBody && detectEmptyBodyPage(page).isEmpty)
204
+ return "spa-shell";
84
205
  return null;
85
206
  }
86
207
  //# sourceMappingURL=page-filter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"page-filter.js","sourceRoot":"","sources":["../src/page-filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"page-filter.js","sourceRoot":"","sources":["../src/page-filter.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"answer-first.d.ts","sourceRoot":"","sources":["../../../src/rules/aeo/answer-first.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEhF,MAAM,WAAW,kBAAkB;IACjC,0FAA0F;IAC1F,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA6BD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA0D1D;AA8CD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,UAAU,EAAE,EACnB,cAAc,EAAE,iBAAiB,EAAE,EACnC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,UAAU,EAAE,CA0Dd"}
1
+ {"version":3,"file":"answer-first.d.ts","sourceRoot":"","sources":["../../../src/rules/aeo/answer-first.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5F,MAAM,WAAW,kBAAkB;IACjC,0FAA0F;IAC1F,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA6BD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA0D1D;AA8CD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,UAAU,EAAE,EACnB,cAAc,EAAE,iBAAiB,EAAE,EACnC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,UAAU,EAAE,CA4Ed"}
@@ -172,14 +172,28 @@ export function answerFirstRule(pages, entityPatterns, options) {
172
172
  reasons.push(`opener is ${s.wordCount} words (too long to extract)`);
173
173
  if (isBoilerplateOpener(s.paragraph))
174
174
  reasons.push("opener is boilerplate ('Welcome to...', 'Generate your...')");
175
- if (!hasConcreteFact(s.paragraph))
175
+ const lacksFact = !hasConcreteFact(s.paragraph);
176
+ const lacksEntity = !hasNamedEntity(s.paragraph, entityPatterns);
177
+ if (lacksFact)
176
178
  reasons.push("no specific numbers, dates, or dollar amounts");
177
- if (!hasNamedEntity(s.paragraph, entityPatterns))
179
+ if (lacksEntity)
178
180
  reasons.push("no named entities (agencies, laws, proper nouns)");
181
+ // Confidence ladder:
182
+ // too-long opener → low (marketing/narrative pages legitimately use long openers)
183
+ // no facts AND no entity → medium (signal is present but interpretation is ambiguous)
184
+ // otherwise → high (templated/boilerplate openers are clear AEO failures)
185
+ const confidence = s.wordCount > tooLong ? "low" :
186
+ (lacksFact && lacksEntity) ? "medium" :
187
+ "high";
188
+ const contextNote = confidence === "low" || confidence === "medium"
189
+ ? " Marketing pages legitimately use narrative openers; this matters more for FAQ-style or directory pages."
190
+ : "";
179
191
  findings.push({
180
192
  ruleId: "aeo/answer-first",
181
193
  severity,
182
- message: `${s.url} does not open with a direct, extractable answer${reasons.length ? `: ${reasons.join("; ")}` : "."}`,
194
+ confidence,
195
+ message: `${s.url} does not open with a direct, extractable answer${reasons.length ? `: ${reasons.join("; ")}` : "."}` +
196
+ contextNote,
183
197
  pageUrl: s.url,
184
198
  fix: `Restructure the template to open with entity-specific facts. Instead of boilerplate or a topic preamble, ` +
185
199
  `lead with a complete-answer sentence containing the key number, date, agency, or form name a reader ` +