@rivi-software/agentic-seo-check 0.1.0 → 0.1.1

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 (119) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +65 -15
  3. package/dist/brand.d.ts +11 -0
  4. package/dist/brand.js +22 -0
  5. package/dist/brand.js.map +1 -0
  6. package/dist/cli.js +125 -80
  7. package/dist/cli.js.map +1 -1
  8. package/dist/core/audit.d.ts +16 -16
  9. package/dist/core/audit.js +363 -248
  10. package/dist/core/audit.js.map +1 -1
  11. package/dist/core/concurrency.d.ts +4 -4
  12. package/dist/core/concurrency.js +33 -23
  13. package/dist/core/concurrency.js.map +1 -1
  14. package/dist/core/crawl.d.ts +5 -5
  15. package/dist/core/crawl.js +250 -121
  16. package/dist/core/crawl.js.map +1 -1
  17. package/dist/core/fetch.d.ts +5 -5
  18. package/dist/core/fetch.js +151 -100
  19. package/dist/core/fetch.js.map +1 -1
  20. package/dist/core/html/dom.d.ts +13 -0
  21. package/dist/core/html/dom.js +17 -0
  22. package/dist/core/html/dom.js.map +1 -0
  23. package/dist/core/html/extract.d.ts +2 -2
  24. package/dist/core/html/extract.js +168 -111
  25. package/dist/core/html/extract.js.map +1 -1
  26. package/dist/core/html/structured-data.d.ts +16 -6
  27. package/dist/core/html/structured-data.js +180 -145
  28. package/dist/core/html/structured-data.js.map +1 -1
  29. package/dist/core/html/text.d.ts +14 -14
  30. package/dist/core/html/text.js +110 -107
  31. package/dist/core/html/text.js.map +1 -1
  32. package/dist/core/lighthouse.d.ts +26 -25
  33. package/dist/core/lighthouse.js +181 -105
  34. package/dist/core/lighthouse.js.map +1 -1
  35. package/dist/core/performance-rules.d.ts +2 -2
  36. package/dist/core/performance-rules.js +105 -33
  37. package/dist/core/performance-rules.js.map +1 -1
  38. package/dist/core/render-rules.d.ts +5 -4
  39. package/dist/core/render-rules.js +129 -62
  40. package/dist/core/render-rules.js.map +1 -1
  41. package/dist/core/render.d.ts +2 -2
  42. package/dist/core/render.js +29 -23
  43. package/dist/core/render.js.map +1 -1
  44. package/dist/core/report/markdown.d.ts +2 -2
  45. package/dist/core/report/markdown.js +110 -131
  46. package/dist/core/report/markdown.js.map +1 -1
  47. package/dist/core/robots.d.ts +5 -5
  48. package/dist/core/robots.js +31 -16
  49. package/dist/core/robots.js.map +1 -1
  50. package/dist/core/rules/canonical.d.ts +1 -1
  51. package/dist/core/rules/canonical.js +93 -57
  52. package/dist/core/rules/canonical.js.map +1 -1
  53. package/dist/core/rules/content.js +40 -26
  54. package/dist/core/rules/content.js.map +1 -1
  55. package/dist/core/rules/document.js +64 -41
  56. package/dist/core/rules/document.js.map +1 -1
  57. package/dist/core/rules/headings.js +58 -38
  58. package/dist/core/rules/headings.js.map +1 -1
  59. package/dist/core/rules/hreflang.js +70 -38
  60. package/dist/core/rules/hreflang.js.map +1 -1
  61. package/dist/core/rules/images.js +44 -26
  62. package/dist/core/rules/images.js.map +1 -1
  63. package/dist/core/rules/index.d.ts +6 -6
  64. package/dist/core/rules/index.js +36 -35
  65. package/dist/core/rules/index.js.map +1 -1
  66. package/dist/core/rules/indexing.d.ts +2 -2
  67. package/dist/core/rules/indexing.js +48 -26
  68. package/dist/core/rules/indexing.js.map +1 -1
  69. package/dist/core/rules/keyword.js +84 -47
  70. package/dist/core/rules/keyword.js.map +1 -1
  71. package/dist/core/rules/links.js +72 -37
  72. package/dist/core/rules/links.js.map +1 -1
  73. package/dist/core/rules/meta.js +55 -34
  74. package/dist/core/rules/meta.js.map +1 -1
  75. package/dist/core/rules/response.js +75 -41
  76. package/dist/core/rules/response.js.map +1 -1
  77. package/dist/core/rules/rule.d.ts +6 -6
  78. package/dist/core/rules/rule.js +36 -36
  79. package/dist/core/rules/rule.js.map +1 -1
  80. package/dist/core/rules/social.js +86 -45
  81. package/dist/core/rules/social.js.map +1 -1
  82. package/dist/core/rules/structured-data.d.ts +6 -4
  83. package/dist/core/rules/structured-data.js +314 -102
  84. package/dist/core/rules/structured-data.js.map +1 -1
  85. package/dist/core/rules/title.js +48 -33
  86. package/dist/core/rules/title.js.map +1 -1
  87. package/dist/core/score.d.ts +3 -3
  88. package/dist/core/score.js +11 -9
  89. package/dist/core/score.js.map +1 -1
  90. package/dist/core/site-rules.d.ts +3 -3
  91. package/dist/core/site-rules.js +409 -198
  92. package/dist/core/site-rules.js.map +1 -1
  93. package/dist/core/sitemap.d.ts +5 -5
  94. package/dist/core/sitemap.js +109 -64
  95. package/dist/core/sitemap.js.map +1 -1
  96. package/dist/core/static.d.ts +2 -2
  97. package/dist/core/static.js +209 -112
  98. package/dist/core/static.js.map +1 -1
  99. package/dist/core/summary.d.ts +2 -2
  100. package/dist/core/summary.js +11 -6
  101. package/dist/core/summary.js.map +1 -1
  102. package/dist/core/types.d.ts +14 -14
  103. package/dist/core/types.js +15 -8
  104. package/dist/core/types.js.map +1 -1
  105. package/dist/core/url.d.ts +11 -11
  106. package/dist/core/url.js +122 -70
  107. package/dist/core/url.js.map +1 -1
  108. package/dist/index.d.ts +11 -11
  109. package/dist/index.js +9 -9
  110. package/dist/index.js.map +1 -1
  111. package/dist/mcp-bin.js +7 -4
  112. package/dist/mcp-bin.js.map +1 -1
  113. package/dist/mcp.d.ts +3 -3
  114. package/dist/mcp.js +312 -122
  115. package/dist/mcp.js.map +1 -1
  116. package/dist/version.d.ts +0 -1
  117. package/dist/version.js +4 -2
  118. package/dist/version.js.map +1 -1
  119. package/package.json +27 -9
@@ -1,48 +1,74 @@
1
- import { includesKeyword, keywordOccurrences, normalizeForComparison, words } from '../html/text.js';
2
- import { defineRule } from './rule.js';
1
+ import { includesKeyword, keywordOccurrences, normalizeForComparison, words, } from "../html/text.js";
2
+ import { defineRule } from "./rule.js";
3
3
  export const keywordRules = [
4
4
  defineRule({
5
- id: 'keyword.not-in-title',
6
- category: 'keyword',
7
- severity: 'warning',
8
- description: 'The target keyword does not appear in the title.',
9
- recommendation: 'Include the target keyword (or a close variant) near the start of the title.',
10
- requires: 'keyword',
11
- }, ({ page, keyword }, make) => (keyword && !includesKeyword(page.title, keyword) ? make(`Title does not contain "${keyword}".`, { selector: 'head > title', evidence: { title: page.title, keyword } }) : null)),
5
+ id: "keyword.not-in-title",
6
+ category: "keyword",
7
+ severity: "warning",
8
+ description: "The target keyword does not appear in the title.",
9
+ recommendation: "Include the target keyword (or a close variant) near the start of the title.",
10
+ requires: "keyword",
11
+ }, ({ page, keyword }, make) => keyword && !includesKeyword(page.title, keyword)
12
+ ? make(`Title does not contain "${keyword}".`, {
13
+ selector: "head > title",
14
+ evidence: { title: page.title, keyword },
15
+ })
16
+ : null),
12
17
  defineRule({
13
- id: 'keyword.not-in-h1',
14
- category: 'keyword',
15
- severity: 'warning',
16
- description: 'The target keyword does not appear in any H1.',
17
- recommendation: 'Use the target keyword in the H1 so the main heading matches the search intent.',
18
- requires: 'keyword',
19
- }, ({ page, keyword }, make) => (keyword && page.h1s.length > 0 && !page.h1s.some((h) => includesKeyword(h, keyword)) ? make(`No <h1> contains "${keyword}".`, { selector: 'h1', evidence: { h1s: page.h1s, keyword } }) : null)),
18
+ id: "keyword.not-in-h1",
19
+ category: "keyword",
20
+ severity: "warning",
21
+ description: "The target keyword does not appear in any H1.",
22
+ recommendation: "Use the target keyword in the H1 so the main heading matches the search intent.",
23
+ requires: "keyword",
24
+ }, ({ page, keyword }, make) => keyword &&
25
+ page.h1s.length > 0 &&
26
+ !page.h1s.some((h) => includesKeyword(h, keyword))
27
+ ? make(`No <h1> contains "${keyword}".`, {
28
+ selector: "h1",
29
+ evidence: { h1s: page.h1s, keyword },
30
+ })
31
+ : null),
20
32
  defineRule({
21
- id: 'keyword.not-in-description',
22
- category: 'keyword',
23
- severity: 'info',
24
- description: 'The target keyword does not appear in the meta description.',
25
- recommendation: 'Mention the keyword in the meta description; matching terms are bolded in search snippets.',
26
- requires: 'keyword',
27
- }, ({ page, keyword }, make) => (keyword && page.metaDescription && !includesKeyword(page.metaDescription, keyword) ? make(`Meta description does not contain "${keyword}".`, { selector: 'head > meta[name="description"]', evidence: { keyword } }) : null)),
33
+ id: "keyword.not-in-description",
34
+ category: "keyword",
35
+ severity: "info",
36
+ description: "The target keyword does not appear in the meta description.",
37
+ recommendation: "Mention the keyword in the meta description; matching terms are bolded in search snippets.",
38
+ requires: "keyword",
39
+ }, ({ page, keyword }, make) => keyword &&
40
+ page.metaDescription &&
41
+ !includesKeyword(page.metaDescription, keyword)
42
+ ? make(`Meta description does not contain "${keyword}".`, {
43
+ selector: 'head > meta[name="description"]',
44
+ evidence: { keyword },
45
+ })
46
+ : null),
28
47
  defineRule({
29
- id: 'keyword.not-in-body',
30
- category: 'keyword',
31
- severity: 'warning',
32
- description: 'The target keyword does not appear in the visible body text.',
33
- recommendation: 'Use the keyword naturally in the body copy, ideally in the first paragraph.',
34
- requires: 'keyword',
35
- }, ({ page, keyword }, make) => (keyword && page.wordCount > 0 && keywordOccurrences(page.text, keyword) === 0 ? make(`Body text does not contain "${keyword}".`, { evidence: { keyword, wordCount: page.wordCount } }) : null)),
48
+ id: "keyword.not-in-body",
49
+ category: "keyword",
50
+ severity: "warning",
51
+ description: "The target keyword does not appear in the visible body text.",
52
+ recommendation: "Use the keyword naturally in the body copy, ideally in the first paragraph.",
53
+ requires: "keyword",
54
+ }, ({ page, keyword }, make) => keyword &&
55
+ page.wordCount > 0 &&
56
+ keywordOccurrences(page.text, keyword) === 0
57
+ ? make(`Body text does not contain "${keyword}".`, {
58
+ evidence: { keyword, wordCount: page.wordCount },
59
+ })
60
+ : null),
36
61
  defineRule({
37
- id: 'keyword.not-in-url',
38
- category: 'keyword',
39
- severity: 'info',
40
- description: 'The target keyword does not appear in the URL path.',
41
- recommendation: 'Where the URL is still changeable, use a short slug containing the keyword (hyphen-separated).',
42
- requires: 'keyword',
62
+ id: "keyword.not-in-url",
63
+ category: "keyword",
64
+ severity: "info",
65
+ description: "The target keyword does not appear in the URL path.",
66
+ recommendation: "Where the URL is still changeable, use a short slug containing the keyword (hyphen-separated).",
67
+ requires: "keyword",
43
68
  }, ({ page, keyword, source }, make) => {
44
- if (!keyword || source === 'html')
69
+ if (!keyword || source === "html") {
45
70
  return null;
71
+ }
46
72
  let pathname = page.url;
47
73
  try {
48
74
  pathname = decodeURIComponent(new URL(page.url).pathname);
@@ -50,24 +76,35 @@ export const keywordRules = [
50
76
  catch {
51
77
  /* keep */
52
78
  }
53
- const slug = pathname.replace(/[-_/.+]+/g, ' ');
54
- return includesKeyword(slug, keyword) ? null : make(`URL path does not contain "${keyword}".`, { evidence: { path: pathname, keyword } });
79
+ const slug = pathname.replaceAll(/[-_/.+]+/gu, " ");
80
+ return includesKeyword(slug, keyword)
81
+ ? null
82
+ : make(`URL path does not contain "${keyword}".`, {
83
+ evidence: { path: pathname, keyword },
84
+ });
55
85
  }),
56
86
  defineRule({
57
- id: 'keyword.density-high',
58
- category: 'keyword',
59
- severity: 'info',
60
- description: 'The target keyword makes up an unusually large share of the body text (default > 3%).',
61
- recommendation: 'Reduce repetition; write for readers and use synonyms. Keyword stuffing can trigger spam filters.',
62
- requires: 'keyword',
87
+ id: "keyword.density-high",
88
+ category: "keyword",
89
+ severity: "info",
90
+ description: "The target keyword makes up an unusually large share of the body text (default > 3%).",
91
+ recommendation: "Reduce repetition; write for readers and use synonyms. Keyword stuffing can trigger spam filters.",
92
+ requires: "keyword",
63
93
  }, ({ page, keyword, thresholds }, make) => {
64
- if (!keyword || page.wordCount < 50)
94
+ if (!keyword || page.wordCount < 50) {
65
95
  return null;
96
+ }
66
97
  const occurrences = keywordOccurrences(page.text, keyword);
67
98
  const kwWords = words(normalizeForComparison(keyword)).length || 1;
68
99
  const density = ((occurrences * kwWords) / page.wordCount) * 100;
69
100
  return density > thresholds.maxKeywordDensityPercent
70
- ? make(`Keyword density is ${density.toFixed(1)}% (${occurrences} occurrences in ${page.wordCount} words).`, { evidence: { occurrences, wordCount: page.wordCount, densityPercent: Number(density.toFixed(2)) } })
101
+ ? make(`Keyword density is ${density.toFixed(1)}% (${occurrences} occurrences in ${page.wordCount} words).`, {
102
+ evidence: {
103
+ occurrences,
104
+ wordCount: page.wordCount,
105
+ densityPercent: Number(density.toFixed(2)),
106
+ },
107
+ })
71
108
  : null;
72
109
  }),
73
110
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"keyword.js","sourceRoot":"","sources":["../../../src/core/rules/keyword.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keyword.js","sourceRoot":"","sources":["../../../src/core/rules/keyword.ts"],"names":[],"mappings":"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"}
@@ -1,72 +1,107 @@
1
- import { isGenericAnchor } from '../html/text.js';
2
- import { cap, defineRule, GOOGLE_DOCS } from './rule.js';
1
+ import { isGenericAnchor } from "../html/text.js";
2
+ import { cap, defineRule, GOOGLE_DOCS } from "./rule.js";
3
3
  export const linkRules = [
4
4
  defineRule({
5
- id: 'links.no-internal',
6
- category: 'links',
7
- severity: 'warning',
8
- description: 'The page has no internal links, so crawlers cannot reach other pages from it and it passes no authority onward.',
9
- recommendation: 'Link to related pages and the main navigation with plain <a href> elements.',
5
+ id: "links.no-internal",
6
+ category: "links",
7
+ severity: "warning",
8
+ description: "The page has no internal links, so crawlers cannot reach other pages from it and it passes no authority onward.",
9
+ recommendation: "Link to related pages and the main navigation with plain <a href> elements.",
10
10
  docs: GOOGLE_DOCS.links,
11
- }, ({ page }, make) => (page.links.some((l) => l.internal) ? null : make('Page contains no internal links.', { evidence: { totalLinks: page.links.length } }))),
11
+ }, ({ page }, make) => page.links.some((l) => l.internal)
12
+ ? null
13
+ : make("Page contains no internal links.", {
14
+ evidence: { totalLinks: page.links.length },
15
+ })),
12
16
  defineRule({
13
- id: 'links.empty-anchor',
14
- category: 'links',
15
- severity: 'warning',
16
- description: 'Links without any accessible name (no text, aria-label, title or image alt).',
17
- recommendation: 'Add descriptive link text, or aria-label for icon links. Empty links tell crawlers nothing about the target page.',
17
+ id: "links.empty-anchor",
18
+ category: "links",
19
+ severity: "warning",
20
+ description: "Links without any accessible name (no text, aria-label, title or image alt).",
21
+ recommendation: "Add descriptive link text, or aria-label for icon links. Empty links tell crawlers nothing about the target page.",
18
22
  docs: GOOGLE_DOCS.links,
19
23
  }, ({ page }, make) => {
20
24
  const empty = page.links.filter((l) => l.url && !l.hasAccessibleName);
21
- return empty.length ? make(`${empty.length} link(s) have no accessible text.`, { evidence: { count: empty.length, examples: cap(empty.map((l) => l.href)) } }) : null;
25
+ return empty.length
26
+ ? make(`${empty.length} link(s) have no accessible text.`, {
27
+ evidence: {
28
+ count: empty.length,
29
+ examples: cap(empty.map((l) => l.href)),
30
+ },
31
+ })
32
+ : null;
22
33
  }),
23
34
  defineRule({
24
- id: 'links.generic-anchor-text',
25
- category: 'links',
26
- severity: 'info',
35
+ id: "links.generic-anchor-text",
36
+ category: "links",
37
+ severity: "info",
27
38
  description: 'Links whose text is generic ("click here", "read more", "learn more").',
28
39
  recommendation: 'Use anchor text that describes the destination, e.g. "pricing plans" instead of "click here".',
29
40
  docs: GOOGLE_DOCS.links,
30
41
  }, ({ page }, make) => {
31
42
  const generic = page.links.filter((l) => l.url && l.text && isGenericAnchor(l.text));
32
43
  return generic.length
33
- ? make(`${generic.length} link(s) use generic anchor text.`, { evidence: { count: generic.length, examples: cap(generic.map((l) => ({ text: l.text, href: l.href }))) } })
44
+ ? make(`${generic.length} link(s) use generic anchor text.`, {
45
+ evidence: {
46
+ count: generic.length,
47
+ examples: cap(generic.map((l) => ({ text: l.text, href: l.href }))),
48
+ },
49
+ })
34
50
  : null;
35
51
  }),
36
52
  defineRule({
37
- id: 'links.uncrawlable-href',
38
- category: 'links',
39
- severity: 'info',
53
+ id: "links.uncrawlable-href",
54
+ category: "links",
55
+ severity: "info",
40
56
  description: 'Anchors whose href is "#", empty, or a javascript: URL. Crawlers cannot follow them.',
41
- recommendation: 'Use <button> for actions. For navigation, give the anchor a real URL even when JavaScript intercepts the click.',
57
+ recommendation: "Use <button> for actions. For navigation, give the anchor a real URL even when JavaScript intercepts the click.",
42
58
  docs: GOOGLE_DOCS.links,
43
59
  }, ({ page }, make) => {
44
- const bad = page.links.filter((l) => l.href === '' || l.href === '#' || /^javascript:/i.test(l.href));
45
- return bad.length ? make(`${bad.length} anchor(s) have an uncrawlable href.`, { evidence: { count: bad.length, examples: cap(bad.map((l) => ({ href: l.href, text: l.text }))) } }) : null;
60
+ const bad = page.links.filter((l) => l.href === "" || l.href === "#" || /^javascript:/iu.test(l.href));
61
+ return bad.length
62
+ ? make(`${bad.length} anchor(s) have an uncrawlable href.`, {
63
+ evidence: {
64
+ count: bad.length,
65
+ examples: cap(bad.map((l) => ({ href: l.href, text: l.text }))),
66
+ },
67
+ })
68
+ : null;
46
69
  }),
47
70
  defineRule({
48
- id: 'links.insecure-internal',
49
- category: 'links',
50
- severity: 'warning',
51
- description: 'Internal links use http:// while the page is served over https://.',
52
- recommendation: 'Update internal links to https:// (or use relative URLs) to avoid an extra redirect on every click and crawl.',
71
+ id: "links.insecure-internal",
72
+ category: "links",
73
+ severity: "warning",
74
+ description: "Internal links use http:// while the page is served over https://.",
75
+ recommendation: "Update internal links to https:// (or use relative URLs) to avoid an extra redirect on every click and crawl.",
53
76
  docs: GOOGLE_DOCS.redirects,
54
77
  }, ({ page, source }, make) => {
55
- if (source !== 'url' || !page.url.startsWith('https://'))
78
+ if (source !== "url" || !page.url.startsWith("https://")) {
56
79
  return null;
57
- const insecure = page.links.filter((l) => l.internal && l.url?.startsWith('http://'));
58
- return insecure.length ? make(`${insecure.length} internal link(s) point to http:// URLs.`, { evidence: { count: insecure.length, examples: cap(insecure.map((l) => l.url)) } }) : null;
80
+ }
81
+ const insecure = page.links.filter((l) => l.internal && l.url?.startsWith("http://"));
82
+ return insecure.length
83
+ ? make(`${insecure.length} internal link(s) point to http:// URLs.`, {
84
+ evidence: {
85
+ count: insecure.length,
86
+ examples: cap(insecure.map((l) => l.url)),
87
+ },
88
+ })
89
+ : null;
59
90
  }),
60
91
  defineRule({
61
- id: 'links.nofollow-internal',
62
- category: 'links',
63
- severity: 'info',
92
+ id: "links.nofollow-internal",
93
+ category: "links",
94
+ severity: "info",
64
95
  description: 'Internal links carry rel="nofollow".',
65
- recommendation: 'Remove nofollow from internal links unless the target is intentionally kept out of the index; nofollow on internal links wastes crawl signals.',
96
+ recommendation: "Remove nofollow from internal links unless the target is intentionally kept out of the index; nofollow on internal links wastes crawl signals.",
66
97
  docs: GOOGLE_DOCS.links,
67
98
  }, ({ page }, make) => {
68
99
  const nf = page.links.filter((l) => l.internal && l.nofollow);
69
- return nf.length ? make(`${nf.length} internal link(s) are rel="nofollow".`, { evidence: { count: nf.length, examples: cap(nf.map((l) => l.url)) } }) : null;
100
+ return nf.length
101
+ ? make(`${nf.length} internal link(s) are rel="nofollow".`, {
102
+ evidence: { count: nf.length, examples: cap(nf.map((l) => l.url)) },
103
+ })
104
+ : null;
70
105
  }),
71
106
  ];
72
107
  //# sourceMappingURL=links.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"links.js","sourceRoot":"","sources":["../../../src/core/rules/links.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"links.js","sourceRoot":"","sources":["../../../src/core/rules/links.ts"],"names":[],"mappings":"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"}
@@ -1,60 +1,81 @@
1
- import { normalizeForComparison } from '../html/text.js';
2
- import { defineRule, GOOGLE_DOCS } from './rule.js';
1
+ import { normalizeForComparison } from "../html/text.js";
2
+ import { defineRule, GOOGLE_DOCS } from "./rule.js";
3
3
  const SELECTOR = 'head > meta[name="description"]';
4
4
  export const metaRules = [
5
5
  defineRule({
6
- id: 'meta-description.missing',
7
- category: 'meta',
8
- severity: 'warning',
6
+ id: "meta-description.missing",
7
+ category: "meta",
8
+ severity: "warning",
9
9
  description: 'No <meta name="description"> is present or it is empty.',
10
- recommendation: 'Add a unique meta description (about 70-160 characters) that summarises the page and invites the click. Search engines may show it as the snippet.',
10
+ recommendation: "Add a unique meta description (about 70-160 characters) that summarises the page and invites the click. Search engines may show it as the snippet.",
11
11
  docs: GOOGLE_DOCS.snippets,
12
- }, ({ page }, make) => (page.metaDescription ? null : make('Page has no meta description.', { selector: SELECTOR }))),
12
+ }, ({ page }, make) => page.metaDescription
13
+ ? null
14
+ : make("Page has no meta description.", { selector: SELECTOR })),
13
15
  defineRule({
14
- id: 'meta-description.multiple',
15
- category: 'meta',
16
- severity: 'warning',
17
- description: 'More than one meta description is present.',
18
- recommendation: 'Keep a single meta description; remove or merge the others.',
16
+ id: "meta-description.multiple",
17
+ category: "meta",
18
+ severity: "warning",
19
+ description: "More than one meta description is present.",
20
+ recommendation: "Keep a single meta description; remove or merge the others.",
19
21
  docs: GOOGLE_DOCS.snippets,
20
22
  }, ({ page }, make) => page.metaDescriptions.length > 1
21
- ? make(`Page has ${page.metaDescriptions.length} meta description tags.`, { selector: SELECTOR, evidence: { descriptions: page.metaDescriptions } })
23
+ ? make(`Page has ${page.metaDescriptions.length} meta description tags.`, {
24
+ selector: SELECTOR,
25
+ evidence: { descriptions: page.metaDescriptions },
26
+ })
22
27
  : null),
23
28
  defineRule({
24
- id: 'meta-description.too-long',
25
- category: 'meta',
26
- severity: 'warning',
27
- description: 'Meta description exceeds the configured maximum (default 160 characters) and will be truncated.',
28
- recommendation: 'Trim the description to about 160 characters, front-loading the key message.',
29
+ id: "meta-description.too-long",
30
+ category: "meta",
31
+ severity: "warning",
32
+ description: "Meta description exceeds the configured maximum (default 160 characters) and will be truncated.",
33
+ recommendation: "Trim the description to about 160 characters, front-loading the key message.",
29
34
  docs: GOOGLE_DOCS.snippets,
30
- }, ({ page, thresholds }, make) => page.metaDescription && page.metaDescription.length > thresholds.descriptionMaxChars
35
+ }, ({ page, thresholds }, make) => page.metaDescription &&
36
+ page.metaDescription.length > thresholds.descriptionMaxChars
31
37
  ? make(`Meta description is ${page.metaDescription.length} characters (max ${thresholds.descriptionMaxChars}).`, {
32
38
  selector: SELECTOR,
33
- evidence: { description: page.metaDescription, length: page.metaDescription.length, max: thresholds.descriptionMaxChars },
39
+ evidence: {
40
+ description: page.metaDescription,
41
+ length: page.metaDescription.length,
42
+ max: thresholds.descriptionMaxChars,
43
+ },
34
44
  })
35
45
  : null),
36
46
  defineRule({
37
- id: 'meta-description.too-short',
38
- category: 'meta',
39
- severity: 'info',
40
- description: 'Meta description is shorter than the configured minimum (default 70 characters).',
41
- recommendation: 'Expand the description so it summarises the page content and its value to the visitor.',
47
+ id: "meta-description.too-short",
48
+ category: "meta",
49
+ severity: "info",
50
+ description: "Meta description is shorter than the configured minimum (default 70 characters).",
51
+ recommendation: "Expand the description so it summarises the page content and its value to the visitor.",
42
52
  docs: GOOGLE_DOCS.snippets,
43
- }, ({ page, thresholds }, make) => page.metaDescription && page.metaDescription.length < thresholds.descriptionMinChars
53
+ }, ({ page, thresholds }, make) => page.metaDescription &&
54
+ page.metaDescription.length < thresholds.descriptionMinChars
44
55
  ? make(`Meta description is only ${page.metaDescription.length} characters (recommended at least ${thresholds.descriptionMinChars}).`, {
45
56
  selector: SELECTOR,
46
- evidence: { description: page.metaDescription, length: page.metaDescription.length, min: thresholds.descriptionMinChars },
57
+ evidence: {
58
+ description: page.metaDescription,
59
+ length: page.metaDescription.length,
60
+ min: thresholds.descriptionMinChars,
61
+ },
47
62
  })
48
63
  : null),
49
64
  defineRule({
50
- id: 'meta-description.same-as-title',
51
- category: 'meta',
52
- severity: 'info',
53
- description: 'Meta description is identical to the title.',
54
- recommendation: 'Write a description that adds information beyond the title instead of repeating it.',
65
+ id: "meta-description.same-as-title",
66
+ category: "meta",
67
+ severity: "info",
68
+ description: "Meta description is identical to the title.",
69
+ recommendation: "Write a description that adds information beyond the title instead of repeating it.",
55
70
  docs: GOOGLE_DOCS.snippets,
56
- }, ({ page }, make) => page.metaDescription && page.title && normalizeForComparison(page.metaDescription) === normalizeForComparison(page.title)
57
- ? make('Meta description repeats the title verbatim.', { selector: SELECTOR, evidence: { title: page.title } })
71
+ }, ({ page }, make) => page.metaDescription &&
72
+ page.title &&
73
+ normalizeForComparison(page.metaDescription) ===
74
+ normalizeForComparison(page.title)
75
+ ? make("Meta description repeats the title verbatim.", {
76
+ selector: SELECTOR,
77
+ evidence: { title: page.title },
78
+ })
58
79
  : null),
59
80
  ];
60
81
  //# sourceMappingURL=meta.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/core/rules/meta.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/core/rules/meta.ts"],"names":[],"mappings":"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"}