@rivi-software/agentic-seo-check 0.4.0 → 0.6.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 (131) hide show
  1. package/README.md +49 -7
  2. package/dist/cli.js +28 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/core/aeo/audit.d.ts +8 -0
  5. package/dist/core/aeo/audit.js +101 -17
  6. package/dist/core/aeo/audit.js.map +1 -1
  7. package/dist/core/aeo/bots.d.ts +48 -0
  8. package/dist/core/aeo/bots.js +151 -5
  9. package/dist/core/aeo/bots.js.map +1 -1
  10. package/dist/core/aeo/fixes.d.ts +38 -0
  11. package/dist/core/aeo/fixes.js +111 -0
  12. package/dist/core/aeo/fixes.js.map +1 -0
  13. package/dist/core/aeo/site-rules.d.ts +5 -0
  14. package/dist/core/aeo/site-rules.js +293 -10
  15. package/dist/core/aeo/site-rules.js.map +1 -1
  16. package/dist/core/audit.d.ts +8 -0
  17. package/dist/core/audit.js +144 -25
  18. package/dist/core/audit.js.map +1 -1
  19. package/dist/core/crawl.js +43 -4
  20. package/dist/core/crawl.js.map +1 -1
  21. package/dist/core/html/answer.d.ts +5 -2
  22. package/dist/core/html/answer.js +25 -7
  23. package/dist/core/html/answer.js.map +1 -1
  24. package/dist/core/html/dom.d.ts +13 -1
  25. package/dist/core/html/dom.js +30 -2
  26. package/dist/core/html/dom.js.map +1 -1
  27. package/dist/core/html/extract.js +122 -30
  28. package/dist/core/html/extract.js.map +1 -1
  29. package/dist/core/html/head.js +114 -19
  30. package/dist/core/html/head.js.map +1 -1
  31. package/dist/core/html/resources.js +15 -7
  32. package/dist/core/html/resources.js.map +1 -1
  33. package/dist/core/html/structured-data.js +21 -5
  34. package/dist/core/html/structured-data.js.map +1 -1
  35. package/dist/core/lighthouse.d.ts +5 -6
  36. package/dist/core/lighthouse.js +297 -7
  37. package/dist/core/lighthouse.js.map +1 -1
  38. package/dist/core/performance-fixes.d.ts +25 -0
  39. package/dist/core/performance-fixes.js +446 -0
  40. package/dist/core/performance-fixes.js.map +1 -0
  41. package/dist/core/performance-rules.js +56 -8
  42. package/dist/core/performance-rules.js.map +1 -1
  43. package/dist/core/recheck.d.ts +68 -0
  44. package/dist/core/recheck.js +247 -0
  45. package/dist/core/recheck.js.map +1 -0
  46. package/dist/core/render-fixes.d.ts +27 -0
  47. package/dist/core/render-fixes.js +164 -0
  48. package/dist/core/render-fixes.js.map +1 -0
  49. package/dist/core/render-rules.js +60 -21
  50. package/dist/core/render-rules.js.map +1 -1
  51. package/dist/core/render.d.ts +9 -1
  52. package/dist/core/render.js +36 -2
  53. package/dist/core/render.js.map +1 -1
  54. package/dist/core/report/markdown.js +68 -1
  55. package/dist/core/report/markdown.js.map +1 -1
  56. package/dist/core/robots.d.ts +5 -0
  57. package/dist/core/robots.js +8 -0
  58. package/dist/core/robots.js.map +1 -1
  59. package/dist/core/rules/aeo.js +339 -25
  60. package/dist/core/rules/aeo.js.map +1 -1
  61. package/dist/core/rules/canonical.js +107 -11
  62. package/dist/core/rules/canonical.js.map +1 -1
  63. package/dist/core/rules/content.js +65 -7
  64. package/dist/core/rules/content.js.map +1 -1
  65. package/dist/core/rules/document.js +73 -8
  66. package/dist/core/rules/document.js.map +1 -1
  67. package/dist/core/rules/fix.d.ts +55 -0
  68. package/dist/core/rules/fix.js +159 -0
  69. package/dist/core/rules/fix.js.map +1 -0
  70. package/dist/core/rules/head.js +81 -4
  71. package/dist/core/rules/head.js.map +1 -1
  72. package/dist/core/rules/headings.js +92 -9
  73. package/dist/core/rules/headings.js.map +1 -1
  74. package/dist/core/rules/hreflang.js +79 -9
  75. package/dist/core/rules/hreflang.js.map +1 -1
  76. package/dist/core/rules/images.js +49 -0
  77. package/dist/core/rules/images.js.map +1 -1
  78. package/dist/core/rules/index.d.ts +11 -0
  79. package/dist/core/rules/index.js +21 -1
  80. package/dist/core/rules/index.js.map +1 -1
  81. package/dist/core/rules/indexing.js +108 -1
  82. package/dist/core/rules/indexing.js.map +1 -1
  83. package/dist/core/rules/keyword.js +91 -1
  84. package/dist/core/rules/keyword.js.map +1 -1
  85. package/dist/core/rules/links.js +42 -0
  86. package/dist/core/rules/links.js.map +1 -1
  87. package/dist/core/rules/loading.js +54 -1
  88. package/dist/core/rules/loading.js.map +1 -1
  89. package/dist/core/rules/meta.js +36 -5
  90. package/dist/core/rules/meta.js.map +1 -1
  91. package/dist/core/rules/page-fixes.d.ts +39 -0
  92. package/dist/core/rules/page-fixes.js +107 -0
  93. package/dist/core/rules/page-fixes.js.map +1 -0
  94. package/dist/core/rules/quoted-tags.d.ts +23 -0
  95. package/dist/core/rules/quoted-tags.js +79 -0
  96. package/dist/core/rules/quoted-tags.js.map +1 -0
  97. package/dist/core/rules/response.js +71 -7
  98. package/dist/core/rules/response.js.map +1 -1
  99. package/dist/core/rules/rule.d.ts +17 -4
  100. package/dist/core/rules/rule.js +11 -2
  101. package/dist/core/rules/rule.js.map +1 -1
  102. package/dist/core/rules/social.js +101 -10
  103. package/dist/core/rules/social.js.map +1 -1
  104. package/dist/core/rules/structured-data-fixes.d.ts +33 -0
  105. package/dist/core/rules/structured-data-fixes.js +469 -0
  106. package/dist/core/rules/structured-data-fixes.js.map +1 -0
  107. package/dist/core/rules/structured-data-values.js +242 -31
  108. package/dist/core/rules/structured-data-values.js.map +1 -1
  109. package/dist/core/rules/structured-data.js +171 -4
  110. package/dist/core/rules/structured-data.js.map +1 -1
  111. package/dist/core/rules/title.js +39 -5
  112. package/dist/core/rules/title.js.map +1 -1
  113. package/dist/core/rules/urls.js +166 -0
  114. package/dist/core/rules/urls.js.map +1 -1
  115. package/dist/core/site-fixes.d.ts +111 -0
  116. package/dist/core/site-fixes.js +650 -0
  117. package/dist/core/site-fixes.js.map +1 -0
  118. package/dist/core/site-rules.js +474 -53
  119. package/dist/core/site-rules.js.map +1 -1
  120. package/dist/core/sitemap.d.ts +16 -0
  121. package/dist/core/sitemap.js +34 -0
  122. package/dist/core/sitemap.js.map +1 -1
  123. package/dist/core/types.d.ts +223 -3
  124. package/dist/core/types.js.map +1 -1
  125. package/dist/index.d.ts +2 -0
  126. package/dist/index.js +1 -0
  127. package/dist/index.js.map +1 -1
  128. package/dist/mcp.js +16 -2
  129. package/dist/mcp.js.map +1 -1
  130. package/package.json +5 -7
  131. package/skills/seo-audit/SKILL.md +23 -6
@@ -0,0 +1,164 @@
1
+ /**
2
+ * The edits that fix what a render comparison found: put into the server HTML what only JavaScript
3
+ * adds. `code` quotes the rendered DOM's own tag, so the server sends what the browser ends up
4
+ * with; `current` quotes the server HTML.
5
+ */
6
+ import { addHtml, escapeText, isCut, rebuildEdit, removeEdit, removeHtml, replaceHtml, slot, withContent, } from "./rules/fix.js";
7
+ const SSR = "JavaScript adds this after load. Render it in the server HTML instead (SSR, SSG or prerendering; in a framework, the route's metadata or head API), so crawlers that do not run JavaScript, and Google before it renders the page, see it.";
8
+ /** The tag of the element whose text is `value`, from parallel lists of texts and tags. */
9
+ const tagFor = (texts, tags, value) => {
10
+ const tag = tags[texts.indexOf(value)];
11
+ return tag && !isCut(tag) ? tag : undefined;
12
+ };
13
+ /** Writes `code` into the server HTML: in place of the empty tag it has, or added to <head>. */
14
+ const intoHead = (empty, code, at, write) => empty
15
+ ? replaceHtml(empty, code, { at, write })
16
+ : addHtml("head", code, write);
17
+ export const titleFix = (s, title) => [
18
+ intoHead(s.raw.markup.titles[0], tagFor(s.rendered.titles, s.rendered.markup.titles, title) ??
19
+ `<title>${escapeText(title)}</title>`, "head > title", SSR),
20
+ ];
21
+ export const titleChangedFix = (s, serverTitle, finalTitle) => {
22
+ const current = s.raw.markup.titles[s.raw.titles.indexOf(serverTitle)];
23
+ const content = escapeText(finalTitle);
24
+ const write = `JavaScript changes the title to this after load; send it from the server so both agree. If the change is on purpose (an unread count, a live status), keep the server title and leave this finding.`;
25
+ return current
26
+ ? [
27
+ replaceHtml(current, withContent(current, content) ?? `<title>${content}</title>`, { at: "head > title", write }),
28
+ ]
29
+ : [addHtml("head", `<title>${content}</title>`, write)];
30
+ };
31
+ export const descriptionFix = (s, description) => {
32
+ const rendered = tagFor(s.rendered.metaDescriptions, s.rendered.markup.metaDescriptions, description);
33
+ const code = rendered ??
34
+ `<meta name="description" content="${description.replaceAll('"', "&quot;")}">`;
35
+ return [
36
+ intoHead(s.raw.markup.metaDescriptions[0], code, 'head > meta[name="description"]', SSR),
37
+ ];
38
+ };
39
+ /**
40
+ * The canonical JavaScript sets, in the server HTML: added when the server sends none, in place of
41
+ * the server's when it sends another.
42
+ */
43
+ export const canonicalFix = (s, serverCanonical, finalCanonical) => {
44
+ const [rendered] = s.rendered.markup.canonicals;
45
+ const code = rendered && !isCut(rendered)
46
+ ? rendered
47
+ : `<link rel="canonical" href="${finalCanonical.replaceAll('"', "&quot;")}">`;
48
+ const at = 'head > link[rel="canonical"]';
49
+ const [current] = s.raw.markup.canonicals;
50
+ if (serverCanonical === null) {
51
+ return [intoHead(current, code, at, SSR)];
52
+ }
53
+ const write = `JavaScript changes the canonical from ${serverCanonical} to ${finalCanonical}. Check that ${finalCanonical} is this page's own URL, send it from the server, and stop setting it a second time in the browser (a head manager or router doing it again).`;
54
+ return current
55
+ ? [replaceHtml(current, code, { at, write })]
56
+ : [addHtml("head", code, write)];
57
+ };
58
+ const NOINDEX = /\bcontent\s*=\s*["']?[^"'>]*\b(?:noindex|none)\b/iu;
59
+ /** noindex that only JavaScript adds: the tag to take out of the component that renders it. */
60
+ export const noindexAddedFix = (s) => {
61
+ const tag = s.rendered.markup.metaRobots.find((t) => NOINDEX.test(t)) ??
62
+ '<meta name="robots" content="noindex">';
63
+ return [
64
+ removeEdit("html", tag, {
65
+ at: 'meta[name="robots"]',
66
+ write: "JavaScript adds this tag after load (often a head manager's default or an auth guard), and Google applies it when it renders the page. Remove it from the component that renders it. If the page must stay out of search, send noindex in the server HTML or an X-Robots-Tag header instead, so the decision does not wait for rendering.",
67
+ }),
68
+ ];
69
+ };
70
+ /** noindex the server sends and JavaScript removes: Google keeps the server's, so remove it there. */
71
+ export const noindexRemovedFix = (s) => {
72
+ const write = "The rendered page drops noindex, so the page is meant to be indexed, but Google reads the server's noindex and does not render the page. Remove it from the server. If the page must stay out of search, keep it and stop removing it in JavaScript instead.";
73
+ const tags = s.raw.markup.metaRobots.filter((t) => NOINDEX.test(t));
74
+ if (tags.length) {
75
+ return tags
76
+ .map((t) => removeHtml(t, 'meta[name="robots"]'))
77
+ .map((e) => ({
78
+ ...e,
79
+ write,
80
+ }));
81
+ }
82
+ const header = s.response?.headers["x-robots-tag"];
83
+ return [
84
+ removeEdit("http", `X-Robots-Tag: ${header ?? "noindex"}`, {
85
+ at: "X-Robots-Tag",
86
+ write,
87
+ }),
88
+ ];
89
+ };
90
+ /** Where the server HTML's content belongs: its empty app root, or <body>. */
91
+ const contentRoot = (s) => s.raw.answer.emptyAppRoot ?? "body";
92
+ export const h1Fix = (s) => {
93
+ const index = s.rendered.headings.findIndex((h) => h.level === 1 && h.text);
94
+ const heading = s.rendered.headings[index];
95
+ const tag = s.rendered.markup.headings[index];
96
+ const code = tag && !isCut(tag) ? tag : `<h1>${escapeText(heading?.text ?? "")}</h1>`;
97
+ return [
98
+ addHtml(contentRoot(s), code, `${SSR} Put it where the page's main content starts.`),
99
+ ];
100
+ };
101
+ export const contentFix = (s, words) => {
102
+ const start = s.rendered.text.split(" ").slice(0, 12).join(" ");
103
+ return [
104
+ addHtml(contentRoot(s), slot("the page's main content, as HTML"), `JavaScript adds ${words} words the server HTML does not have${start ? `; the rendered text starts "${start}…"` : ""}. Render this route on the server (SSR, SSG or prerendering) so the HTML carries the text.`),
105
+ ];
106
+ };
107
+ /** Internal links only the rendered DOM has, quoted as JavaScript writes them (the first 10). */
108
+ export const linksFix = (s, missing) => {
109
+ const known = new Set(s.raw.links.flatMap((l) => (l.internal && l.url ? [l.url] : [])));
110
+ const seen = new Set();
111
+ const lines = [];
112
+ for (const link of s.rendered.links) {
113
+ if (!link.internal ||
114
+ !link.url ||
115
+ known.has(link.url) ||
116
+ seen.has(link.url) ||
117
+ isCut(link.tag)) {
118
+ continue;
119
+ }
120
+ seen.add(link.url);
121
+ lines.push(`${link.tag}${escapeText(link.text)}</a>`);
122
+ if (lines.length === 10) {
123
+ break;
124
+ }
125
+ }
126
+ const write = `${missing} internal links exist only after JavaScript runs${lines.length ? `; the first ${lines.length} are here` : ""}. Render them as plain <a href> in the server HTML (the navigation and the content lists), so crawlers find the pages without running JavaScript.`;
127
+ return [
128
+ addHtml(contentRoot(s), lines.length
129
+ ? lines.join("\n")
130
+ : slot("the page's links, as <a href> elements"), write),
131
+ ];
132
+ };
133
+ /** JSON-LD longer than this is described with a slot rather than copied into the fix. */
134
+ const MAX_JSON_LD = 5000;
135
+ /** The JSON-LD JavaScript adds, as script elements for the server HTML. */
136
+ export const structuredDataFix = (s) => {
137
+ const scripts = new Set();
138
+ for (const item of s.rendered.structuredData) {
139
+ if (item.source !== "json-ld") {
140
+ continue;
141
+ }
142
+ // One <script> may hold several items (an array, an @graph): copy it once.
143
+ const json = item.scriptText?.trim() ||
144
+ JSON.stringify(item.data).replaceAll("<", String.raw `\u003c`);
145
+ scripts.add(json);
146
+ }
147
+ const edits = [...scripts]
148
+ .slice(0, 10)
149
+ .map((json) => addHtml("head", json.length > MAX_JSON_LD
150
+ ? `<script type="application/ld+json">${slot("the JSON-LD JavaScript adds")}</script>`
151
+ : `<script type="application/ld+json">${json}</script>`, `${SSR} Google reads JSON-LD that JavaScript adds, but other consumers (social previews, other search engines, AI crawlers) do not.`));
152
+ return edits.length
153
+ ? edits
154
+ : [
155
+ addHtml(contentRoot(s), slot("the microdata JavaScript adds"), `${SSR} The structured data is microdata on elements JavaScript renders.`),
156
+ ];
157
+ };
158
+ const SCRIPT_URL = /https?:\/\/[^\s"'()<>]+?\.m?js\b/u;
159
+ /** The scripts that throw while the page renders, from the messages they log (the first 5). */
160
+ export const consoleErrorFix = (errors) => errors.slice(0, 5).map((error) => {
161
+ const url = SCRIPT_URL.exec(error)?.[0];
162
+ return rebuildEdit(url, "code that does not throw", `Fix the error ${url ? "this script" : "a script of this page"} logs while the page renders (${error}): a script that fails can leave crawlers an incomplete page.`);
163
+ });
164
+ //# sourceMappingURL=render-fixes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-fixes.js","sourceRoot":"","sources":["../../src/core/render-fixes.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { canonicalFix, consoleErrorFix, contentFix, descriptionFix, h1Fix, linksFix, noindexAddedFix, noindexRemovedFix, structuredDataFix, titleChangedFix, titleFix, } from "./render-fixes.js";
1
2
  import { robotsDirectives } from "./rules/indexing.js";
2
3
  import { finding, GOOGLE_DOCS } from "./rules/rule.js";
3
4
  const meta = (id, severity, description, recommendation) => ({
@@ -42,36 +43,48 @@ export const snapshot = (page, response) => ({
42
43
  internalLinks: page.links.filter((l) => l.internal).length,
43
44
  structuredDataCount: page.structuredData.length,
44
45
  });
45
- /** Title, description, canonical and robots: what the head says before and after JavaScript runs. */
46
- const headFindings = (a, b) => {
46
+ const make = (id, message, extras) => finding(m(id), message, extras);
47
+ /** Title and description: what the head says before and after JavaScript runs. */
48
+ const textFindings = (s) => {
49
+ const { a, b } = s;
47
50
  const findings = [];
48
- const add = (f) => findings.push(f);
49
51
  if (!a.title && b.title) {
50
- add(finding(m("rendering.title-client-only"), `Title "${b.title}" is only present after rendering.`, {
52
+ findings.push(make("rendering.title-client-only", `Title "${b.title}" is only present after rendering.`, {
53
+ fix: titleFix(s, b.title),
51
54
  selector: "head > title",
52
55
  evidence: { raw: a.title, rendered: b.title },
53
56
  }));
54
57
  }
55
58
  else if (a.title && b.title && a.title !== b.title) {
56
- add(finding(m("rendering.title-changed"), "Title differs between server HTML and rendered DOM.", {
59
+ findings.push(make("rendering.title-changed", "Title differs between server HTML and rendered DOM.", {
60
+ fix: titleChangedFix(s, a.title, b.title),
57
61
  selector: "head > title",
58
62
  evidence: { raw: a.title, rendered: b.title },
59
63
  }));
60
64
  }
61
65
  if (!a.metaDescription && b.metaDescription) {
62
- add(finding(m("rendering.description-client-only"), "Meta description is only present after rendering.", {
66
+ findings.push(make("rendering.description-client-only", "Meta description is only present after rendering.", {
67
+ fix: descriptionFix(s, b.metaDescription),
63
68
  selector: 'head > meta[name="description"]',
64
69
  evidence: { rendered: b.metaDescription },
65
70
  }));
66
71
  }
72
+ return findings;
73
+ };
74
+ /** Canonical and robots: the signals that decide which URL is indexed, before and after JavaScript. */
75
+ const indexingFindings = (s) => {
76
+ const { a, b } = s;
77
+ const findings = [];
67
78
  if (!a.canonical && b.canonical) {
68
- add(finding(m("rendering.canonical-client-only"), `Canonical ${b.canonical} is only present after rendering.`, {
79
+ findings.push(make("rendering.canonical-client-only", `Canonical ${b.canonical} is only present after rendering.`, {
80
+ fix: canonicalFix(s, null, b.canonical),
69
81
  selector: 'head > link[rel="canonical"]',
70
82
  evidence: { rendered: b.canonical },
71
83
  }));
72
84
  }
73
85
  else if (a.canonical && b.canonical && a.canonical !== b.canonical) {
74
- add(finding(m("rendering.canonical-changed"), "Canonical differs between server HTML and rendered DOM.", {
86
+ findings.push(make("rendering.canonical-changed", "Canonical differs between server HTML and rendered DOM.", {
87
+ fix: canonicalFix(s, a.canonical, b.canonical),
75
88
  selector: 'head > link[rel="canonical"]',
76
89
  evidence: { raw: a.canonical, rendered: b.canonical },
77
90
  }));
@@ -79,46 +92,65 @@ const headFindings = (a, b) => {
79
92
  const rawNoindex = a.robots.some((d) => d === "noindex" || d === "none");
80
93
  const renderedNoindex = b.robots.some((d) => d === "noindex" || d === "none");
81
94
  if (!rawNoindex && renderedNoindex) {
82
- add(finding(m("rendering.noindex-client-only"), "noindex is added by JavaScript.", {
95
+ findings.push(make("rendering.noindex-client-only", "noindex is added by JavaScript.", {
96
+ fix: noindexAddedFix(s),
83
97
  selector: 'head > meta[name="robots"]',
84
98
  evidence: { raw: a.robots, rendered: b.robots },
85
99
  }));
86
100
  }
87
101
  if (rawNoindex && !renderedNoindex) {
88
- add(finding(m("rendering.noindex-removed-by-js"), "Server HTML contains noindex; JavaScript removes it.", {
102
+ findings.push(make("rendering.noindex-removed-by-js", "Server HTML contains noindex; JavaScript removes it.", {
103
+ fix: noindexRemovedFix(s),
89
104
  selector: 'head > meta[name="robots"]',
90
105
  evidence: { raw: a.robots, rendered: b.robots },
91
106
  }));
92
107
  }
93
108
  return findings;
94
109
  };
95
- /** H1, words, links, structured data and script errors: what only the rendered body has. */
96
- const bodyFindings = (a, b, consoleErrors) => {
110
+ /** H1, words and links: what only the rendered body has. */
111
+ const contentFindings = (s) => {
112
+ const { a, b } = s;
97
113
  const findings = [];
98
- const add = (f) => findings.push(f);
99
114
  if (a.h1Count === 0 && b.h1Count > 0) {
100
- add(finding(m("rendering.h1-client-only"), "The <h1> is only present after rendering.", {
115
+ findings.push(make("rendering.h1-client-only", "The <h1> is only present after rendering.", {
116
+ fix: h1Fix(s),
101
117
  selector: "h1",
102
118
  evidence: { rawH1Count: a.h1Count, renderedH1Count: b.h1Count },
103
119
  }));
104
120
  }
105
121
  if (b.wordCount - a.wordCount >= 100 && a.wordCount < b.wordCount * 0.5) {
106
- add(finding(m("rendering.content-client-only"), `Server HTML has ${a.wordCount} words; rendered DOM has ${b.wordCount}.`, { evidence: { rawWords: a.wordCount, renderedWords: b.wordCount } }));
122
+ findings.push(make("rendering.content-client-only", `Server HTML has ${a.wordCount} words; rendered DOM has ${b.wordCount}.`, {
123
+ fix: contentFix(s, b.wordCount - a.wordCount),
124
+ evidence: { rawWords: a.wordCount, renderedWords: b.wordCount },
125
+ }));
107
126
  }
108
127
  if (b.internalLinks - a.internalLinks >= 10 &&
109
128
  a.internalLinks < b.internalLinks * 0.5) {
110
- add(finding(m("rendering.links-client-only"), `Server HTML has ${a.internalLinks} internal links; rendered DOM has ${b.internalLinks}.`, {
129
+ findings.push(make("rendering.links-client-only", `Server HTML has ${a.internalLinks} internal links; rendered DOM has ${b.internalLinks}.`, {
130
+ fix: linksFix(s, b.internalLinks - a.internalLinks),
111
131
  evidence: {
112
132
  rawLinks: a.internalLinks,
113
133
  renderedLinks: b.internalLinks,
114
134
  },
115
135
  }));
116
136
  }
137
+ return findings;
138
+ };
139
+ /** Structured data and script errors that only the rendered page has. */
140
+ const scriptFindings = (s, consoleErrors) => {
141
+ const { a, b } = s;
142
+ const findings = [];
117
143
  if (a.structuredDataCount === 0 && b.structuredDataCount > 0) {
118
- add(finding(m("rendering.structured-data-client-only"), `${b.structuredDataCount} structured data item(s) are only present after rendering.`, { evidence: { renderedCount: b.structuredDataCount } }));
144
+ findings.push(make("rendering.structured-data-client-only", `${b.structuredDataCount} structured data item(s) are only present after rendering.`, {
145
+ fix: structuredDataFix(s),
146
+ evidence: { renderedCount: b.structuredDataCount },
147
+ }));
119
148
  }
120
149
  if (consoleErrors.length) {
121
- add(finding(m("rendering.console-errors"), `${consoleErrors.length} JavaScript error(s) logged during render.`, { evidence: { errors: consoleErrors.slice(0, 5) } }));
150
+ findings.push(make("rendering.console-errors", `${consoleErrors.length} JavaScript error(s) logged during render.`, {
151
+ fix: consoleErrorFix(consoleErrors),
152
+ evidence: { errors: consoleErrors.slice(0, 5) },
153
+ }));
122
154
  }
123
155
  return findings;
124
156
  };
@@ -126,10 +158,17 @@ export const compareRender = (raw, rendered, renderedUrl, consoleErrors, rawResp
126
158
  const a = snapshot(raw, rawResponse);
127
159
  const b = snapshot(rendered);
128
160
  const url = rawResponse?.finalUrl ?? raw.url;
161
+ const sides = { raw, rendered, response: rawResponse, a, b };
129
162
  const findings = [
130
- ...headFindings(a, b),
131
- ...bodyFindings(a, b, consoleErrors),
132
- ].map((f) => ({ ...f, url }));
163
+ ...textFindings(sides),
164
+ ...indexingFindings(sides),
165
+ ...contentFindings(sides),
166
+ ...scriptFindings(sides, consoleErrors),
167
+ ];
168
+ // Set in place: a copy would lose the key a finding's id is made from.
169
+ for (const f of findings) {
170
+ f.url = url;
171
+ }
133
172
  return {
134
173
  comparison: {
135
174
  tool: "playwright",
@@ -1 +1 @@
1
- {"version":3,"file":"render-rules.js","sourceRoot":"","sources":["../../src/core/render-rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAUvD,MAAM,IAAI,GAAG,CACX,EAAU,EACV,QAA8B,EAC9B,WAAmB,EACnB,cAAsB,EACZ,EAAE,CAAC,CAAC;IACd,EAAE;IACF,QAAQ,EAAE,WAAW;IACrB,QAAQ;IACR,WAAW;IACX,cAAc;IACd,IAAI,EAAE,WAAW,CAAC,UAAU;IAC5B,QAAQ,EAAE,QAAQ;CACnB,CAAC,CAAC;AAEH,MAAM,OAAO,GACX,yJAAyJ,CAAC;AAE5J,MAAM,CAAC,MAAM,YAAY,GAAe;IACtC,IAAI,CACF,6BAA6B,EAC7B,SAAS,EACT,gDAAgD,EAChD,OAAO,CACR;IACD,IAAI,CACF,yBAAyB,EACzB,MAAM,EACN,4CAA4C,EAC5C,iEAAiE,CAClE;IACD,IAAI,CACF,mCAAmC,EACnC,SAAS,EACT,yDAAyD,EACzD,OAAO,CACR;IACD,IAAI,CACF,iCAAiC,EACjC,SAAS,EACT,uDAAuD,EACvD,OAAO,CACR;IACD,IAAI,CACF,6BAA6B,EAC7B,SAAS,EACT,+EAA+E,EAC/E,+EAA+E,CAChF;IACD,IAAI,CACF,+BAA+B,EAC/B,OAAO,EACP,mIAAmI,EACnI,8HAA8H,CAC/H;IACD,IAAI,CACF,iCAAiC,EACjC,SAAS,EACT,oJAAoJ,EACpJ,oEAAoE,CACrE;IACD,IAAI,CACF,0BAA0B,EAC1B,SAAS,EACT,6CAA6C,EAC7C,OAAO,CACR;IACD,IAAI,CACF,+BAA+B,EAC/B,SAAS,EACT,0DAA0D,EAC1D,OAAO,CACR;IACD,IAAI,CACF,6BAA6B,EAC7B,SAAS,EACT,+FAA+F,EAC/F,GAAG,OAAO,wEAAwE,CACnF;IACD,IAAI,CACF,uCAAuC,EACvC,MAAM,EACN,8CAA8C,EAC9C,qHAAqH,CACtH;IACD,IAAI,CACF,0BAA0B,EAC1B,MAAM,EACN,oDAAoD,EACpD,kFAAkF,CACnF;CACF,CAAC;AAEF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzD,MAAM,CAAC,GAAG,CAAC,EAAU,EAAY,EAAE;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAE1B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAmB,EACnB,QAAuB,EACP,EAAE,CAAC,CAAC;IACpB,KAAK,EAAE,IAAI,CAAC,KAAK;IACjB,eAAe,EAAE,IAAI,CAAC,eAAe;IACrC,SAAS,EAAE,IAAI,CAAC,SAAS;IACzB,MAAM,EAAE,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,UAAU;IACnD,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM;IACxC,SAAS,EAAE,IAAI,CAAC,SAAS;IACzB,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM;IAC1D,mBAAmB,EAAE,IAAI,CAAC,cAAc,CAAC,MAAM;CAChD,CAAC,CAAC;AAEH,qGAAqG;AACrG,MAAM,YAAY,GAAG,CAAC,CAAiB,EAAE,CAAiB,EAAa,EAAE;IACvE,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE7C,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACxB,GAAG,CACD,OAAO,CACL,CAAC,CAAC,6BAA6B,CAAC,EAChC,UAAU,CAAC,CAAC,KAAK,oCAAoC,EACrD;YACE,QAAQ,EAAE,cAAc;YACxB,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE;SAC9C,CACF,CACF,CAAC;IACJ,CAAC;SAAM,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;QACrD,GAAG,CACD,OAAO,CACL,CAAC,CAAC,yBAAyB,CAAC,EAC5B,qDAAqD,EACrD;YACE,QAAQ,EAAE,cAAc;YACxB,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE;SAC9C,CACF,CACF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;QAC5C,GAAG,CACD,OAAO,CACL,CAAC,CAAC,mCAAmC,CAAC,EACtC,mDAAmD,EACnD;YACE,QAAQ,EAAE,iCAAiC;YAC3C,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,eAAe,EAAE;SAC1C,CACF,CACF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;QAChC,GAAG,CACD,OAAO,CACL,CAAC,CAAC,iCAAiC,CAAC,EACpC,aAAa,CAAC,CAAC,SAAS,mCAAmC,EAC3D;YACE,QAAQ,EAAE,8BAA8B;YACxC,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE;SACpC,CACF,CACF,CAAC;IACJ,CAAC;SAAM,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,SAAS,EAAE,CAAC;QACrE,GAAG,CACD,OAAO,CACL,CAAC,CAAC,6BAA6B,CAAC,EAChC,yDAAyD,EACzD;YACE,QAAQ,EAAE,8BAA8B;YACxC,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE;SACtD,CACF,CACF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC;IACzE,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC;IAE9E,IAAI,CAAC,UAAU,IAAI,eAAe,EAAE,CAAC;QACnC,GAAG,CACD,OAAO,CACL,CAAC,CAAC,+BAA+B,CAAC,EAClC,iCAAiC,EACjC;YACE,QAAQ,EAAE,4BAA4B;YACtC,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;SAChD,CACF,CACF,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,IAAI,CAAC,eAAe,EAAE,CAAC;QACnC,GAAG,CACD,OAAO,CACL,CAAC,CAAC,iCAAiC,CAAC,EACpC,sDAAsD,EACtD;YACE,QAAQ,EAAE,4BAA4B;YACtC,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;SAChD,CACF,CACF,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF,4FAA4F;AAC5F,MAAM,YAAY,GAAG,CACnB,CAAiB,EACjB,CAAiB,EACjB,aAAuB,EACZ,EAAE;IACb,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE7C,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QACrC,GAAG,CACD,OAAO,CACL,CAAC,CAAC,0BAA0B,CAAC,EAC7B,2CAA2C,EAC3C;YACE,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE;SAChE,CACF,CACF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC;QACxE,GAAG,CACD,OAAO,CACL,CAAC,CAAC,+BAA+B,CAAC,EAClC,mBAAmB,CAAC,CAAC,SAAS,4BAA4B,CAAC,CAAC,SAAS,GAAG,EACxE,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,SAAS,EAAE,EAAE,CACpE,CACF,CAAC;IACJ,CAAC;IAED,IACE,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,IAAI,EAAE;QACvC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,GAAG,GAAG,EACvC,CAAC;QACD,GAAG,CACD,OAAO,CACL,CAAC,CAAC,6BAA6B,CAAC,EAChC,mBAAmB,CAAC,CAAC,aAAa,qCAAqC,CAAC,CAAC,aAAa,GAAG,EACzF;YACE,QAAQ,EAAE;gBACR,QAAQ,EAAE,CAAC,CAAC,aAAa;gBACzB,aAAa,EAAE,CAAC,CAAC,aAAa;aAC/B;SACF,CACF,CACF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,CAAC,mBAAmB,KAAK,CAAC,IAAI,CAAC,CAAC,mBAAmB,GAAG,CAAC,EAAE,CAAC;QAC7D,GAAG,CACD,OAAO,CACL,CAAC,CAAC,uCAAuC,CAAC,EAC1C,GAAG,CAAC,CAAC,mBAAmB,4DAA4D,EACpF,EAAE,QAAQ,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC,mBAAmB,EAAE,EAAE,CACvD,CACF,CAAC;IACJ,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,EAAE,CAAC;QACzB,GAAG,CACD,OAAO,CACL,CAAC,CAAC,0BAA0B,CAAC,EAC7B,GAAG,aAAa,CAAC,MAAM,4CAA4C,EACnE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CACpD,CACF,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAOF,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,GAAkB,EAClB,QAAuB,EACvB,WAAmB,EACnB,aAAuB,EACvB,WAA0B,EACL,EAAE;IACvB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACrC,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,WAAW,EAAE,QAAQ,IAAI,GAAG,CAAC,GAAG,CAAC;IAE7C,MAAM,QAAQ,GAAG;QACf,GAAG,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;QACrB,GAAG,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC;KACrC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IAE9B,OAAO;QACL,UAAU,EAAE;YACV,IAAI,EAAE,YAAY;YAClB,WAAW;YACX,aAAa,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YACzC,GAAG,EAAE,CAAC;YACN,QAAQ,EAAE,CAAC;SACZ;QACD,QAAQ;KACT,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"render-rules.js","sourceRoot":"","sources":["../../src/core/render-rules.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,14 @@ export interface RenderOutput {
17
17
  finalUrl: string;
18
18
  consoleErrors: string[];
19
19
  }
20
- export declare const RENDER_INSTALL_HINT = "Install Playwright to enable rendering: `pnpm add -D playwright && pnpm exec playwright install chromium` (or npm/npx equivalents).";
20
+ export declare const RENDER_INSTALL_HINT = "Playwright installs with agentic-seo-check as an optional dependency, so it is missing only where optional dependencies were left out (`--omit=optional`, `--no-optional`): reinstall with them, or add `playwright` next to agentic-seo-check.";
21
+ export declare const BROWSER_INSTALL_HINT = "Install Google Chrome, or download the Chromium build this Playwright expects with `agentic-seo-check install-browser` (`npx @rivi-software/agentic-seo-check install-browser` with npx).";
22
+ /**
23
+ * Downloads the Chromium build the installed Playwright expects, through Playwright's own CLI: a
24
+ * build fetched by `npx playwright install` for another Playwright version does not launch.
25
+ */
26
+ export declare const installBrowser: (options?: {
27
+ withDeps?: boolean;
28
+ }) => Promise<void>;
21
29
  /** Load the page in headless Chromium and return the rendered DOM. */
22
30
  export declare const renderPage: (url: string, options?: RenderOptions) => Promise<RenderOutput>;
@@ -1,3 +1,8 @@
1
+ import { spawn } from "node:child_process";
2
+ import { once } from "node:events";
3
+ import { promises as fs } from "node:fs";
4
+ import { createRequire } from "node:module";
5
+ import path from "node:path";
1
6
  import { DEFAULT_USER_AGENT } from "./fetch.js";
2
7
  export class RenderUnavailableError extends Error {
3
8
  constructor(message) {
@@ -5,7 +10,36 @@ export class RenderUnavailableError extends Error {
5
10
  this.name = "RenderUnavailableError";
6
11
  }
7
12
  }
8
- export const RENDER_INSTALL_HINT = "Install Playwright to enable rendering: `pnpm add -D playwright && pnpm exec playwright install chromium` (or npm/npx equivalents).";
13
+ export const RENDER_INSTALL_HINT = "Playwright installs with agentic-seo-check as an optional dependency, so it is missing only where optional dependencies were left out (`--omit=optional`, `--no-optional`): reinstall with them, or add `playwright` next to agentic-seo-check.";
14
+ export const BROWSER_INSTALL_HINT = "Install Google Chrome, or download the Chromium build this Playwright expects with `agentic-seo-check install-browser` (`npx @rivi-software/agentic-seo-check install-browser` with npx).";
15
+ /**
16
+ * Downloads the Chromium build the installed Playwright expects, through Playwright's own CLI: a
17
+ * build fetched by `npx playwright install` for another Playwright version does not launch.
18
+ */
19
+ export const installBrowser = async (options = {}) => {
20
+ let manifestPath;
21
+ try {
22
+ manifestPath = createRequire(import.meta.url).resolve("playwright/package.json");
23
+ }
24
+ catch {
25
+ throw new RenderUnavailableError(`Playwright is not installed. ${RENDER_INSTALL_HINT}`);
26
+ }
27
+ // SAFETY: the manifest of an installed package; a missing bin fails the spawn below.
28
+ const manifest = JSON.parse(await fs.readFile(manifestPath, "utf-8"));
29
+ const cli = path.join(path.dirname(manifestPath), manifest.bin?.playwright ?? "cli.js");
30
+ const args = [cli, "install", "chromium"];
31
+ if (options.withDeps) {
32
+ args.push("--with-deps");
33
+ }
34
+ // Playwright's progress goes to stderr, like the CLI's own: stdout is for reports.
35
+ const child = spawn(process.execPath, args, {
36
+ stdio: ["inherit", 2, "inherit"],
37
+ });
38
+ await once(child, "close");
39
+ if (child.exitCode !== 0) {
40
+ throw new Error(`playwright install chromium exited with ${child.exitCode ?? child.signalCode}.`);
41
+ }
42
+ };
9
43
  const launchSystemBrowser = async (playwright) => {
10
44
  for (const channel of ["chrome", "msedge"]) {
11
45
  try {
@@ -36,7 +70,7 @@ export const renderPage = async (url, options = {}) => {
36
70
  // No downloaded Playwright browser: fall back to an installed Google Chrome / Edge.
37
71
  const fallback = await launchSystemBrowser(playwright);
38
72
  if (!fallback) {
39
- throw new RenderUnavailableError(`Could not launch Chromium: ${firstLine(error instanceof Error ? error.message : String(error))}. ${RENDER_INSTALL_HINT}`);
73
+ throw new RenderUnavailableError(`Could not launch Chromium: ${firstLine(error instanceof Error ? error.message : String(error))}. ${BROWSER_INSTALL_HINT}`);
40
74
  }
41
75
  browser = fallback;
42
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"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"}
@@ -8,11 +8,53 @@ const cell = (value) => {
8
8
  };
9
9
  const ms = (value) => value === null ? "—" : `${Math.round(value)} ms`;
10
10
  const countsLine = (c) => `${c.error} error(s), ${c.warning} warning(s), ${c.info} info`;
11
+ /** `text` as inline code, fenced with more backticks than it holds so a page's own backticks cannot end it. */
12
+ const codeSpan = (text) => {
13
+ const longest = Math.max(0, ...[...text.matchAll(/`+/gu)].map((m) => m[0].length));
14
+ const fence = "`".repeat(longest + 1);
15
+ const pad = text.startsWith("`") || text.endsWith("`") ? " " : "";
16
+ return `${fence}${pad}${text}${pad}${fence}`;
17
+ };
18
+ /** A labelled line for one line of code, or a fenced block under the label for several. */
19
+ const codeLines = (label, text, indent) => {
20
+ if (!text.includes("\n")) {
21
+ return [`${indent}- ${label}: ${codeSpan(text)}`];
22
+ }
23
+ const longest = Math.max(2, ...[...text.matchAll(/`+/gu)].map((m) => m[0].length));
24
+ const fence = "`".repeat(longest + 1);
25
+ return [
26
+ `${indent}- ${label}:`,
27
+ "",
28
+ `${indent} ${fence}`,
29
+ ...text.split("\n").map((line) => `${indent} ${line}`),
30
+ `${indent} ${fence}`,
31
+ "",
32
+ ];
33
+ };
34
+ const editLines = (e) => {
35
+ const where = [e.in, e.url, e.at ? codeSpan(e.at) : undefined]
36
+ .filter(Boolean)
37
+ .join(", ");
38
+ const out = [` - Edit: ${e.action} in ${where}`];
39
+ if (e.current !== undefined) {
40
+ out.push(...codeLines("Current", e.current, " "));
41
+ }
42
+ if (e.code !== undefined) {
43
+ out.push(...codeLines("Code", e.code, " "));
44
+ }
45
+ if (e.write) {
46
+ out.push(` - Write: ${e.write}`);
47
+ }
48
+ return out;
49
+ };
11
50
  const findingLines = (f) => {
12
51
  const out = [
13
52
  `- **\`${f.rule}\`** ${f.message}`,
14
53
  ` - Fix: ${f.recommendation}`,
15
54
  ];
55
+ for (const e of f.fix ?? []) {
56
+ out.push(...editLines(e));
57
+ }
16
58
  if (f.selector) {
17
59
  out.push(` - Where: \`${f.selector}\``);
18
60
  }
@@ -21,6 +63,25 @@ const findingLines = (f) => {
21
63
  }
22
64
  return out;
23
65
  };
66
+ /** What a re-check found: the findings fixed since the baseline, still open and new. */
67
+ const baselineLines = (b, heading) => {
68
+ const lines = [
69
+ `${heading}# Re-check`,
70
+ "",
71
+ `${b.fixed.length} fixed · ${b.open.length} still open · ${b.new.length} new${b.notChecked ? ` · ${b.notChecked} not checked (their rule or page did not run this time)` : ""}`,
72
+ "",
73
+ ];
74
+ for (const f of b.fixed) {
75
+ lines.push(`- Fixed: \`${f.id}\`${f.message ? ` ${f.message}` : ""}${f.url ? ` (${f.url})` : ""}`);
76
+ }
77
+ for (const id of b.new) {
78
+ lines.push(`- New: \`${id}\``);
79
+ }
80
+ if (b.fixed.length || b.new.length) {
81
+ lines.push("");
82
+ }
83
+ return lines;
84
+ };
24
85
  const SEVERITY_HEADINGS = {
25
86
  error: "Errors",
26
87
  warning: "Warnings",
@@ -66,6 +127,9 @@ const pageMarkdown = (audit, heading = "#") => {
66
127
  const r = audit.rendering;
67
128
  lines.push(`${heading}# Rendered vs server HTML`, "", "| Field | Server HTML | Rendered DOM |", "| --- | --- | --- |", `| Title | ${cell(r.raw.title)} | ${cell(r.rendered.title)} |`, `| Meta description | ${cell(r.raw.metaDescription)} | ${cell(r.rendered.metaDescription)} |`, `| Canonical | ${cell(r.raw.canonical)} | ${cell(r.rendered.canonical)} |`, `| Robots | ${r.raw.robots.join(", ") || "—"} | ${r.rendered.robots.join(", ") || "—"} |`, `| H1 count | ${r.raw.h1Count} | ${r.rendered.h1Count} |`, `| Words | ${r.raw.wordCount} | ${r.rendered.wordCount} |`, `| Internal links | ${r.raw.internalLinks} | ${r.rendered.internalLinks} |`, `| Structured data items | ${r.raw.structuredDataCount} | ${r.rendered.structuredDataCount} |`, "");
68
129
  }
130
+ if (audit.baseline) {
131
+ lines.push(...baselineLines(audit.baseline, heading));
132
+ }
69
133
  lines.push(...findingsSection(audit.findings, heading));
70
134
  return lines.join("\n");
71
135
  };
@@ -90,6 +154,9 @@ const siteMarkdown = (audit) => {
90
154
  `| Sitemaps | ${audit.sitemaps.sources.length ? `${audit.sitemaps.sources.length} file(s), ${audit.sitemaps.urlCount} URLs` : "none found"}${audit.sitemaps.errors.length ? `, ${audit.sitemaps.errors.length} error(s)` : ""} |`,
91
155
  "",
92
156
  ];
157
+ if (audit.baseline) {
158
+ lines.push(...baselineLines(audit.baseline, "#"));
159
+ }
93
160
  if (audit.siteFindings.length) {
94
161
  lines.push("## Site-wide findings", "");
95
162
  for (const f of audit.siteFindings) {
@@ -209,7 +276,7 @@ const aeoMarkdown = (audit) => {
209
276
  if (audit.crawlers) {
210
277
  lines.push(...crawlerLines(audit.crawlers, audit.llmsTxt, audit.summary.pages));
211
278
  }
212
- lines.push(...aeoPageLines(audit), ...findingsSection(audit.findings, "#"));
279
+ lines.push(...aeoPageLines(audit), ...(audit.baseline ? baselineLines(audit.baseline, "#") : []), ...findingsSection(audit.findings, "#"));
213
280
  if (audit.issues?.length) {
214
281
  lines.push("", "## Page issues by rule", "", "| Severity | Rule | Pages | Example |", "| --- | --- | --- | --- |");
215
282
  for (const i of audit.issues) {