@pseolint/core 0.1.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 (223) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/algorithms/entity-mask.d.ts +3 -0
  4. package/dist/algorithms/entity-mask.d.ts.map +1 -0
  5. package/dist/algorithms/entity-mask.js +8 -0
  6. package/dist/algorithms/entity-mask.js.map +1 -0
  7. package/dist/algorithms/entity-mask.test.d.ts +2 -0
  8. package/dist/algorithms/entity-mask.test.d.ts.map +1 -0
  9. package/dist/algorithms/entity-mask.test.js +23 -0
  10. package/dist/algorithms/entity-mask.test.js.map +1 -0
  11. package/dist/algorithms/simhash.d.ts +4 -0
  12. package/dist/algorithms/simhash.d.ts.map +1 -0
  13. package/dist/algorithms/simhash.js +64 -0
  14. package/dist/algorithms/simhash.js.map +1 -0
  15. package/dist/algorithms/simhash.test.d.ts +2 -0
  16. package/dist/algorithms/simhash.test.d.ts.map +1 -0
  17. package/dist/algorithms/simhash.test.js +23 -0
  18. package/dist/algorithms/simhash.test.js.map +1 -0
  19. package/dist/algorithms/tf-idf.d.ts +8 -0
  20. package/dist/algorithms/tf-idf.d.ts.map +1 -0
  21. package/dist/algorithms/tf-idf.js +55 -0
  22. package/dist/algorithms/tf-idf.js.map +1 -0
  23. package/dist/auditor.d.ts +3 -0
  24. package/dist/auditor.d.ts.map +1 -0
  25. package/dist/auditor.js +730 -0
  26. package/dist/auditor.js.map +1 -0
  27. package/dist/auditor.test.d.ts +2 -0
  28. package/dist/auditor.test.d.ts.map +1 -0
  29. package/dist/auditor.test.js +134 -0
  30. package/dist/auditor.test.js.map +1 -0
  31. package/dist/enrich-findings.d.ts +9 -0
  32. package/dist/enrich-findings.d.ts.map +1 -0
  33. package/dist/enrich-findings.js +436 -0
  34. package/dist/enrich-findings.js.map +1 -0
  35. package/dist/formatters/console.d.ts +6 -0
  36. package/dist/formatters/console.d.ts.map +1 -0
  37. package/dist/formatters/console.js +237 -0
  38. package/dist/formatters/console.js.map +1 -0
  39. package/dist/formatters/html.d.ts +3 -0
  40. package/dist/formatters/html.d.ts.map +1 -0
  41. package/dist/formatters/html.js +170 -0
  42. package/dist/formatters/html.js.map +1 -0
  43. package/dist/formatters/index.d.ts +6 -0
  44. package/dist/formatters/index.d.ts.map +1 -0
  45. package/dist/formatters/index.js +5 -0
  46. package/dist/formatters/index.js.map +1 -0
  47. package/dist/formatters/json.d.ts +3 -0
  48. package/dist/formatters/json.d.ts.map +1 -0
  49. package/dist/formatters/json.js +4 -0
  50. package/dist/formatters/json.js.map +1 -0
  51. package/dist/formatters/markdown.d.ts +3 -0
  52. package/dist/formatters/markdown.d.ts.map +1 -0
  53. package/dist/formatters/markdown.js +93 -0
  54. package/dist/formatters/markdown.js.map +1 -0
  55. package/dist/index.d.ts +45 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +45 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/page-classifier.d.ts +4 -0
  60. package/dist/page-classifier.d.ts.map +1 -0
  61. package/dist/page-classifier.js +133 -0
  62. package/dist/page-classifier.js.map +1 -0
  63. package/dist/parser.d.ts +3 -0
  64. package/dist/parser.d.ts.map +1 -0
  65. package/dist/parser.js +131 -0
  66. package/dist/parser.js.map +1 -0
  67. package/dist/parser.test.d.ts +2 -0
  68. package/dist/parser.test.d.ts.map +1 -0
  69. package/dist/parser.test.js +37 -0
  70. package/dist/parser.test.js.map +1 -0
  71. package/dist/renderer.d.ts +15 -0
  72. package/dist/renderer.d.ts.map +1 -0
  73. package/dist/renderer.js +124 -0
  74. package/dist/renderer.js.map +1 -0
  75. package/dist/rule-references.d.ts +2 -0
  76. package/dist/rule-references.d.ts.map +1 -0
  77. package/dist/rule-references.js +35 -0
  78. package/dist/rule-references.js.map +1 -0
  79. package/dist/rules/cannibal/keyword-collision.d.ts +3 -0
  80. package/dist/rules/cannibal/keyword-collision.d.ts.map +1 -0
  81. package/dist/rules/cannibal/keyword-collision.js +25 -0
  82. package/dist/rules/cannibal/keyword-collision.js.map +1 -0
  83. package/dist/rules/cannibal/title-overlap.d.ts +3 -0
  84. package/dist/rules/cannibal/title-overlap.d.ts.map +1 -0
  85. package/dist/rules/cannibal/title-overlap.js +43 -0
  86. package/dist/rules/cannibal/title-overlap.js.map +1 -0
  87. package/dist/rules/cannibal/url-pattern.d.ts +3 -0
  88. package/dist/rules/cannibal/url-pattern.d.ts.map +1 -0
  89. package/dist/rules/cannibal/url-pattern.js +48 -0
  90. package/dist/rules/cannibal/url-pattern.js.map +1 -0
  91. package/dist/rules/content/eeat-signals.d.ts +3 -0
  92. package/dist/rules/content/eeat-signals.d.ts.map +1 -0
  93. package/dist/rules/content/eeat-signals.js +46 -0
  94. package/dist/rules/content/eeat-signals.js.map +1 -0
  95. package/dist/rules/content/heading-uniqueness.d.ts +3 -0
  96. package/dist/rules/content/heading-uniqueness.d.ts.map +1 -0
  97. package/dist/rules/content/heading-uniqueness.js +56 -0
  98. package/dist/rules/content/heading-uniqueness.js.map +1 -0
  99. package/dist/rules/content/meta-uniqueness.d.ts +3 -0
  100. package/dist/rules/content/meta-uniqueness.d.ts.map +1 -0
  101. package/dist/rules/content/meta-uniqueness.js +28 -0
  102. package/dist/rules/content/meta-uniqueness.js.map +1 -0
  103. package/dist/rules/content/missing-author.d.ts +3 -0
  104. package/dist/rules/content/missing-author.d.ts.map +1 -0
  105. package/dist/rules/content/missing-author.js +26 -0
  106. package/dist/rules/content/missing-author.js.map +1 -0
  107. package/dist/rules/content/unique-value.d.ts +3 -0
  108. package/dist/rules/content/unique-value.d.ts.map +1 -0
  109. package/dist/rules/content/unique-value.js +26 -0
  110. package/dist/rules/content/unique-value.js.map +1 -0
  111. package/dist/rules/links/cluster-connectivity.d.ts +7 -0
  112. package/dist/rules/links/cluster-connectivity.d.ts.map +1 -0
  113. package/dist/rules/links/cluster-connectivity.js +73 -0
  114. package/dist/rules/links/cluster-connectivity.js.map +1 -0
  115. package/dist/rules/links/cluster-key.d.ts +3 -0
  116. package/dist/rules/links/cluster-key.d.ts.map +1 -0
  117. package/dist/rules/links/cluster-key.js +22 -0
  118. package/dist/rules/links/cluster-key.js.map +1 -0
  119. package/dist/rules/links/dead-ends.d.ts +3 -0
  120. package/dist/rules/links/dead-ends.d.ts.map +1 -0
  121. package/dist/rules/links/dead-ends.js +13 -0
  122. package/dist/rules/links/dead-ends.js.map +1 -0
  123. package/dist/rules/links/hub-pages.d.ts +7 -0
  124. package/dist/rules/links/hub-pages.d.ts.map +1 -0
  125. package/dist/rules/links/hub-pages.js +73 -0
  126. package/dist/rules/links/hub-pages.js.map +1 -0
  127. package/dist/rules/links/link-depth.d.ts +3 -0
  128. package/dist/rules/links/link-depth.d.ts.map +1 -0
  129. package/dist/rules/links/link-depth.js +46 -0
  130. package/dist/rules/links/link-depth.js.map +1 -0
  131. package/dist/rules/links/orphan-pages.d.ts +3 -0
  132. package/dist/rules/links/orphan-pages.d.ts.map +1 -0
  133. package/dist/rules/links/orphan-pages.js +19 -0
  134. package/dist/rules/links/orphan-pages.js.map +1 -0
  135. package/dist/rules/schema/consistency.d.ts +3 -0
  136. package/dist/rules/schema/consistency.d.ts.map +1 -0
  137. package/dist/rules/schema/consistency.js +44 -0
  138. package/dist/rules/schema/consistency.js.map +1 -0
  139. package/dist/rules/schema/json-ld-valid.d.ts +3 -0
  140. package/dist/rules/schema/json-ld-valid.d.ts.map +1 -0
  141. package/dist/rules/schema/json-ld-valid.js +47 -0
  142. package/dist/rules/schema/json-ld-valid.js.map +1 -0
  143. package/dist/rules/schema/required-fields.d.ts +3 -0
  144. package/dist/rules/schema/required-fields.d.ts.map +1 -0
  145. package/dist/rules/schema/required-fields.js +60 -0
  146. package/dist/rules/schema/required-fields.js.map +1 -0
  147. package/dist/rules/spam/boilerplate-ratio.d.ts +3 -0
  148. package/dist/rules/spam/boilerplate-ratio.d.ts.map +1 -0
  149. package/dist/rules/spam/boilerplate-ratio.js +50 -0
  150. package/dist/rules/spam/boilerplate-ratio.js.map +1 -0
  151. package/dist/rules/spam/doorway-pattern.d.ts +4 -0
  152. package/dist/rules/spam/doorway-pattern.d.ts.map +1 -0
  153. package/dist/rules/spam/doorway-pattern.js +47 -0
  154. package/dist/rules/spam/doorway-pattern.js.map +1 -0
  155. package/dist/rules/spam/entity-swap.d.ts +7 -0
  156. package/dist/rules/spam/entity-swap.d.ts.map +1 -0
  157. package/dist/rules/spam/entity-swap.js +26 -0
  158. package/dist/rules/spam/entity-swap.js.map +1 -0
  159. package/dist/rules/spam/near-duplicate.d.ts +11 -0
  160. package/dist/rules/spam/near-duplicate.d.ts.map +1 -0
  161. package/dist/rules/spam/near-duplicate.js +25 -0
  162. package/dist/rules/spam/near-duplicate.js.map +1 -0
  163. package/dist/rules/spam/publication-velocity.d.ts +3 -0
  164. package/dist/rules/spam/publication-velocity.d.ts.map +1 -0
  165. package/dist/rules/spam/publication-velocity.js +25 -0
  166. package/dist/rules/spam/publication-velocity.js.map +1 -0
  167. package/dist/rules/spam/template-coverage.d.ts +3 -0
  168. package/dist/rules/spam/template-coverage.d.ts.map +1 -0
  169. package/dist/rules/spam/template-coverage.js +87 -0
  170. package/dist/rules/spam/template-coverage.js.map +1 -0
  171. package/dist/rules/spam/template-diversity.d.ts +3 -0
  172. package/dist/rules/spam/template-diversity.d.ts.map +1 -0
  173. package/dist/rules/spam/template-diversity.js +19 -0
  174. package/dist/rules/spam/template-diversity.js.map +1 -0
  175. package/dist/rules/spam/thin-content.d.ts +6 -0
  176. package/dist/rules/spam/thin-content.d.ts.map +1 -0
  177. package/dist/rules/spam/thin-content.js +22 -0
  178. package/dist/rules/spam/thin-content.js.map +1 -0
  179. package/dist/rules/tech/canonical-consistency.d.ts +4 -0
  180. package/dist/rules/tech/canonical-consistency.d.ts.map +1 -0
  181. package/dist/rules/tech/canonical-consistency.js +78 -0
  182. package/dist/rules/tech/canonical-consistency.js.map +1 -0
  183. package/dist/rules/tech/canonical-noindex-conflict.d.ts +3 -0
  184. package/dist/rules/tech/canonical-noindex-conflict.d.ts.map +1 -0
  185. package/dist/rules/tech/canonical-noindex-conflict.js +27 -0
  186. package/dist/rules/tech/canonical-noindex-conflict.js.map +1 -0
  187. package/dist/rules/tech/hreflang-consistency.d.ts +3 -0
  188. package/dist/rules/tech/hreflang-consistency.d.ts.map +1 -0
  189. package/dist/rules/tech/hreflang-consistency.js +99 -0
  190. package/dist/rules/tech/hreflang-consistency.js.map +1 -0
  191. package/dist/rules/tech/og-completeness.d.ts +3 -0
  192. package/dist/rules/tech/og-completeness.d.ts.map +1 -0
  193. package/dist/rules/tech/og-completeness.js +35 -0
  194. package/dist/rules/tech/og-completeness.js.map +1 -0
  195. package/dist/rules/tech/redirect-chain.d.ts +3 -0
  196. package/dist/rules/tech/redirect-chain.d.ts.map +1 -0
  197. package/dist/rules/tech/redirect-chain.js +20 -0
  198. package/dist/rules/tech/redirect-chain.js.map +1 -0
  199. package/dist/rules/tech/robots-noindex-conflict.d.ts +3 -0
  200. package/dist/rules/tech/robots-noindex-conflict.d.ts.map +1 -0
  201. package/dist/rules/tech/robots-noindex-conflict.js +30 -0
  202. package/dist/rules/tech/robots-noindex-conflict.js.map +1 -0
  203. package/dist/rules/tech/robots-sitemap-presence.d.ts +3 -0
  204. package/dist/rules/tech/robots-sitemap-presence.d.ts.map +1 -0
  205. package/dist/rules/tech/robots-sitemap-presence.js +61 -0
  206. package/dist/rules/tech/robots-sitemap-presence.js.map +1 -0
  207. package/dist/rules/tech/sitemap-completeness.d.ts +3 -0
  208. package/dist/rules/tech/sitemap-completeness.d.ts.map +1 -0
  209. package/dist/rules/tech/sitemap-completeness.js +40 -0
  210. package/dist/rules/tech/sitemap-completeness.js.map +1 -0
  211. package/dist/rules/tech/soft-404.d.ts +3 -0
  212. package/dist/rules/tech/soft-404.d.ts.map +1 -0
  213. package/dist/rules/tech/soft-404.js +24 -0
  214. package/dist/rules/tech/soft-404.js.map +1 -0
  215. package/dist/types.d.ts +170 -0
  216. package/dist/types.d.ts.map +1 -0
  217. package/dist/types.js +2 -0
  218. package/dist/types.js.map +1 -0
  219. package/dist/url-normalize.d.ts +10 -0
  220. package/dist/url-normalize.d.ts.map +1 -0
  221. package/dist/url-normalize.js +52 -0
  222. package/dist/url-normalize.js.map +1 -0
  223. package/package.json +46 -0
@@ -0,0 +1,237 @@
1
+ // ANSI escape codes
2
+ const RESET = "\x1b[0m";
3
+ const BOLD = "\x1b[1m";
4
+ const DIM = "\x1b[2m";
5
+ const RED = "\x1b[31m";
6
+ const GREEN = "\x1b[32m";
7
+ const YELLOW = "\x1b[33m";
8
+ const RED_BRIGHT = "\x1b[91m";
9
+ const ORANGE = "\x1b[38;5;208m";
10
+ function scoreColor(score) {
11
+ if (score <= 20)
12
+ return GREEN;
13
+ if (score <= 40)
14
+ return YELLOW;
15
+ if (score <= 60)
16
+ return ORANGE;
17
+ if (score <= 80)
18
+ return RED;
19
+ return RED + BOLD;
20
+ }
21
+ function scoreLabel(score) {
22
+ if (score <= 20)
23
+ return "Safe";
24
+ if (score <= 40)
25
+ return "Caution";
26
+ if (score <= 60)
27
+ return "Risky";
28
+ if (score <= 80)
29
+ return "Dangerous";
30
+ return "Critical";
31
+ }
32
+ function bar(score, width = 10) {
33
+ const filled = Math.round((score / 100) * width);
34
+ const empty = width - filled;
35
+ return "\u2588".repeat(filled) + "\u2591".repeat(empty);
36
+ }
37
+ const SEVERITY_ORDER = ["critical", "error", "warning", "info"];
38
+ const EFFORT_ORDER = ["quick", "moderate", "structural"];
39
+ function severityColor(severity) {
40
+ switch (severity) {
41
+ case "critical":
42
+ return RED + BOLD;
43
+ case "error":
44
+ return RED_BRIGHT;
45
+ case "warning":
46
+ return YELLOW;
47
+ case "info":
48
+ return DIM;
49
+ }
50
+ }
51
+ function effortLabel(effort) {
52
+ switch (effort) {
53
+ case "quick":
54
+ return `${GREEN}[quick fix]${RESET}`;
55
+ case "moderate":
56
+ return `${YELLOW}[moderate]${RESET}`;
57
+ case "structural":
58
+ return `${RED}[structural]${RESET}`;
59
+ }
60
+ }
61
+ function shortenUrl(url) {
62
+ try {
63
+ const u = new URL(url);
64
+ return u.pathname;
65
+ }
66
+ catch {
67
+ return url;
68
+ }
69
+ }
70
+ export function formatConsole(summary, options) {
71
+ const strip = options?.noColor ?? false;
72
+ const lines = [];
73
+ // Score header
74
+ const color = scoreColor(summary.score);
75
+ const label = scoreLabel(summary.score);
76
+ lines.push(`${BOLD}SpamBrain Risk Score:${RESET} ${color}${summary.score}/100 (${label})${RESET}`);
77
+ lines.push(`Pages analysed: ${summary.pageCount}`);
78
+ // Template banner
79
+ if (summary.templateDetected) {
80
+ lines.push(`${DIM}Template-generated content detected. Fix suggestions are tailored for template authors.${RESET}`);
81
+ }
82
+ lines.push("");
83
+ // Category scores
84
+ lines.push(`${BOLD}Category Scores${RESET}`);
85
+ const categories = summary.categoryScores;
86
+ for (const [name, value] of Object.entries(categories)) {
87
+ const catColor = scoreColor(value);
88
+ const padded = name.charAt(0).toUpperCase() + name.slice(1);
89
+ lines.push(` ${padded.padEnd(10)} ${catColor}${bar(value)}${RESET} ${value}`);
90
+ }
91
+ lines.push("");
92
+ // Group scores
93
+ if (summary.groupScores && summary.groupPageCounts) {
94
+ lines.push(`${BOLD}Group Scores${RESET}`);
95
+ for (const [name, value] of Object.entries(summary.groupScores)) {
96
+ const count = summary.groupPageCounts[name] ?? 0;
97
+ const gColor = scoreColor(value);
98
+ lines.push(` ${name.padEnd(15)} ${gColor}${bar(value)}${RESET} ${value} (${count} pages)`);
99
+ }
100
+ lines.push("");
101
+ }
102
+ const ruleAgg = new Map();
103
+ for (const f of summary.findings) {
104
+ const existing = ruleAgg.get(f.ruleId);
105
+ const isCluster = f.context?.type === "cluster";
106
+ const clusterCtx = isCluster ? f.context : undefined;
107
+ if (existing) {
108
+ // Escalate severity if needed
109
+ if (SEVERITY_ORDER.indexOf(f.severity) < SEVERITY_ORDER.indexOf(existing.severity)) {
110
+ existing.severity = f.severity;
111
+ }
112
+ // Escalate effort if needed
113
+ if (f.effort !== undefined) {
114
+ if (existing.effort === undefined || EFFORT_ORDER.indexOf(f.effort) > EFFORT_ORDER.indexOf(existing.effort)) {
115
+ existing.effort = f.effort;
116
+ }
117
+ }
118
+ if (isCluster && clusterCtx) {
119
+ existing.clusterCount += 1;
120
+ existing.totalPages += clusterCtx.members.length;
121
+ // Merge similarity range
122
+ if (existing.similarityRange) {
123
+ existing.similarityRange[0] = Math.min(existing.similarityRange[0], clusterCtx.similarityRange[0]);
124
+ existing.similarityRange[1] = Math.max(existing.similarityRange[1], clusterCtx.similarityRange[1]);
125
+ }
126
+ else {
127
+ existing.similarityRange = [...clusterCtx.similarityRange];
128
+ }
129
+ }
130
+ else if (!isCluster) {
131
+ existing.totalPages += 1;
132
+ }
133
+ }
134
+ else {
135
+ if (isCluster && clusterCtx) {
136
+ ruleAgg.set(f.ruleId, {
137
+ severity: f.severity,
138
+ effort: f.effort,
139
+ clusterCount: 1,
140
+ totalPages: clusterCtx.members.length,
141
+ similarityRange: [...clusterCtx.similarityRange],
142
+ });
143
+ }
144
+ else {
145
+ ruleAgg.set(f.ruleId, {
146
+ severity: f.severity,
147
+ effort: f.effort,
148
+ clusterCount: 0,
149
+ totalPages: 1,
150
+ });
151
+ }
152
+ }
153
+ }
154
+ if (ruleAgg.size > 0) {
155
+ const sorted = Array.from(ruleAgg.entries())
156
+ .sort((a, b) => {
157
+ const sevDiff = SEVERITY_ORDER.indexOf(a[1].severity) - SEVERITY_ORDER.indexOf(b[1].severity);
158
+ if (sevDiff !== 0)
159
+ return sevDiff;
160
+ // Within same severity, sort effort ascending (quick wins first)
161
+ const aEffort = a[1].effort ? EFFORT_ORDER.indexOf(a[1].effort) : EFFORT_ORDER.length;
162
+ const bEffort = b[1].effort ? EFFORT_ORDER.indexOf(b[1].effort) : EFFORT_ORDER.length;
163
+ return aEffort - bEffort;
164
+ })
165
+ .slice(0, 7);
166
+ lines.push(`${BOLD}Top Issues${RESET}`);
167
+ for (let i = 0; i < sorted.length; i += 1) {
168
+ const [ruleId, agg] = sorted[i];
169
+ const sColor = severityColor(agg.severity);
170
+ let detail;
171
+ if (agg.clusterCount > 0 && agg.similarityRange) {
172
+ const simMin = Math.round(agg.similarityRange[0] * 100);
173
+ const simMax = Math.round(agg.similarityRange[1] * 100);
174
+ detail = `${agg.clusterCount} cluster${agg.clusterCount !== 1 ? "s" : ""} (${agg.totalPages} pages, ${simMin}\u2013${simMax}% similar). Structural fix.`;
175
+ }
176
+ else {
177
+ const effortStr = agg.effort
178
+ ? ` ${agg.effort.charAt(0).toUpperCase() + agg.effort.slice(1)} fix.`
179
+ : "";
180
+ detail = `${agg.totalPages} page${agg.totalPages !== 1 ? "s" : ""}.${effortStr}`;
181
+ }
182
+ lines.push(` ${sColor}${i + 1}.${RESET} ${ruleId} \u2014 ${detail}`);
183
+ }
184
+ lines.push("");
185
+ }
186
+ // Findings grouped by severity
187
+ const grouped = new Map();
188
+ for (const sev of SEVERITY_ORDER) {
189
+ grouped.set(sev, []);
190
+ }
191
+ for (const f of summary.findings) {
192
+ grouped.get(f.severity).push(f);
193
+ }
194
+ for (const sev of SEVERITY_ORDER) {
195
+ const items = grouped.get(sev);
196
+ if (items.length === 0)
197
+ continue;
198
+ const sevLabel = sev.toUpperCase();
199
+ lines.push(`${severityColor(sev)}${sevLabel}${RESET} (${items.length})`);
200
+ const showAll = sev === "critical" || sev === "error";
201
+ const limit = showAll ? items.length : 5;
202
+ const visible = items.slice(0, limit);
203
+ for (const item of visible) {
204
+ lines.push(` ${severityColor(sev)}\u2022${RESET} [${item.ruleId}] ${item.message}`);
205
+ // Cluster worst pair — show before fix so user sees the problem first
206
+ if (item.context?.type === "cluster") {
207
+ const clusterCtx = item.context;
208
+ if (clusterCtx.worstPairs.length > 0) {
209
+ const worst = clusterCtx.worstPairs[0];
210
+ const leftShort = shortenUrl(worst.left);
211
+ const rightShort = shortenUrl(worst.right);
212
+ const simPct = (worst.similarity * 100).toFixed(1);
213
+ lines.push(` ${DIM}Worst: ${leftShort} \u2194 ${rightShort} (${simPct}%)${RESET}`);
214
+ }
215
+ }
216
+ if (item.fix) {
217
+ lines.push(` ${DIM}Fix: ${item.fix}${RESET}`);
218
+ }
219
+ if (item.ref) {
220
+ lines.push(` ${DIM}Ref: ${item.ref}${RESET}`);
221
+ }
222
+ if (item.effort) {
223
+ lines.push(` ${effortLabel(item.effort)}`);
224
+ }
225
+ }
226
+ if (!showAll && items.length > limit) {
227
+ lines.push(` ${DIM}...${items.length - limit} more${RESET}`);
228
+ }
229
+ lines.push("");
230
+ }
231
+ const output = lines.join("\n");
232
+ if (strip) {
233
+ return output.replace(/\x1b\[[0-9;]*m/g, "");
234
+ }
235
+ return output;
236
+ }
237
+ //# sourceMappingURL=console.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console.js","sourceRoot":"","sources":["../../src/formatters/console.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { AuditSummary } from "../types.js";
2
+ export declare function formatHtml(summary: AuditSummary): string;
3
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/formatters/html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAmC,MAAM,aAAa,CAAC;AA6CjF,wBAAgB,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CA+HxD"}
@@ -0,0 +1,170 @@
1
+ const SEVERITY_ORDER = ["critical", "error", "warning", "info"];
2
+ function severityColor(severity) {
3
+ switch (severity) {
4
+ case "critical":
5
+ return "#dc2626";
6
+ case "error":
7
+ return "#ea580c";
8
+ case "warning":
9
+ return "#ca8a04";
10
+ case "info":
11
+ return "#2563eb";
12
+ }
13
+ }
14
+ function scoreColor(score) {
15
+ if (score <= 20)
16
+ return "#16a34a";
17
+ if (score <= 40)
18
+ return "#ca8a04";
19
+ if (score <= 60)
20
+ return "#ea580c";
21
+ return "#dc2626";
22
+ }
23
+ function escapeHtml(text) {
24
+ return text
25
+ .replace(/&/g, "&amp;")
26
+ .replace(/</g, "&lt;")
27
+ .replace(/>/g, "&gt;")
28
+ .replace(/"/g, "&quot;");
29
+ }
30
+ function effortColor(effort) {
31
+ switch (effort) {
32
+ case "quick": return "#16a34a";
33
+ case "moderate": return "#ca8a04";
34
+ case "structural": return "#dc2626";
35
+ default: return "#64748b";
36
+ }
37
+ }
38
+ function shortenUrl(url) {
39
+ try {
40
+ return new URL(url).pathname;
41
+ }
42
+ catch {
43
+ return url;
44
+ }
45
+ }
46
+ export function formatHtml(summary) {
47
+ const grouped = new Map();
48
+ for (const sev of SEVERITY_ORDER) {
49
+ grouped.set(sev, []);
50
+ }
51
+ for (const f of summary.findings) {
52
+ grouped.get(f.severity).push(f);
53
+ }
54
+ const categoryRows = Object.entries(summary.categoryScores)
55
+ .map(([name, value]) => {
56
+ const label = name.charAt(0).toUpperCase() + name.slice(1);
57
+ const pct = value;
58
+ return `<tr>
59
+ <td>${escapeHtml(label)}</td>
60
+ <td>
61
+ <div class="bar-bg"><div class="bar-fill" style="width:${pct}%;background:${scoreColor(pct)}"></div></div>
62
+ </td>
63
+ <td>${pct}</td>
64
+ </tr>`;
65
+ })
66
+ .join("\n");
67
+ const findingsSections = SEVERITY_ORDER.map((sev) => {
68
+ const items = grouped.get(sev);
69
+ if (items.length === 0)
70
+ return "";
71
+ const itemsHtml = items
72
+ .map((item) => {
73
+ let li = `<li><strong>${escapeHtml(item.ruleId)}</strong>`;
74
+ if (item.effort) {
75
+ li += ` <span class="effort-pill" style="background:${effortColor(item.effort)}">${escapeHtml(item.effort)}</span>`;
76
+ }
77
+ li += `: ${escapeHtml(item.message)}`;
78
+ if (item.context?.type === "cluster") {
79
+ const ctx = item.context;
80
+ const [minSim, maxSim] = ctx.similarityRange;
81
+ const worstPairsHtml = ctx.worstPairs
82
+ .map(p => `<li>${escapeHtml(shortenUrl(p.left))} &#8596; ${escapeHtml(shortenUrl(p.right))} (${(p.similarity * 100).toFixed(1)}%)</li>`)
83
+ .join("\n");
84
+ const membersHtml = ctx.members
85
+ .map(m => `<li>${escapeHtml(shortenUrl(m))}</li>`)
86
+ .join("\n");
87
+ li += `
88
+ <details>
89
+ <summary>${ctx.clusterSize} pages in cluster (${(minSim * 100).toFixed(0)}&ndash;${(maxSim * 100).toFixed(0)}% similar)</summary>
90
+ <div class="cluster-details">
91
+ <strong>Worst pairs:</strong>
92
+ <ul>${worstPairsHtml}</ul>
93
+ <strong>All members:</strong>
94
+ <ul class="member-list">${membersHtml}</ul>
95
+ </div>
96
+ </details>`;
97
+ }
98
+ if (item.fix) {
99
+ li += `<div class="fix">Fix: ${escapeHtml(item.fix)}</div>`;
100
+ }
101
+ if (item.ref) {
102
+ li += ` <a href="${escapeHtml(item.ref)}" class="ref" target="_blank">Ref</a>`;
103
+ }
104
+ li += `</li>`;
105
+ return li;
106
+ })
107
+ .join("\n");
108
+ return `<h3 style="color:${severityColor(sev)}">${sev.charAt(0).toUpperCase() + sev.slice(1)} (${items.length})</h3>
109
+ <ul>${itemsHtml}</ul>`;
110
+ }).join("\n");
111
+ return `<!DOCTYPE html>
112
+ <html lang="en">
113
+ <head>
114
+ <meta charset="utf-8">
115
+ <meta name="viewport" content="width=device-width,initial-scale=1">
116
+ <title>pSEOlint Audit Report</title>
117
+ <style>
118
+ *{margin:0;padding:0;box-sizing:border-box}
119
+ body{font-family:system-ui,-apple-system,sans-serif;max-width:800px;margin:0 auto;padding:2rem;color:#1e293b;background:#f8fafc}
120
+ h1{margin-bottom:.5rem}
121
+ h2{margin-top:1.5rem;margin-bottom:.5rem;border-bottom:1px solid #e2e8f0;padding-bottom:.25rem}
122
+ h3{margin-top:1rem;margin-bottom:.25rem}
123
+ table{width:100%;border-collapse:collapse;margin:.5rem 0}
124
+ th,td{text-align:left;padding:.35rem .5rem;border-bottom:1px solid #e2e8f0}
125
+ th{font-weight:600}
126
+ td:last-child{text-align:right;width:3rem}
127
+ .score{font-size:2rem;font-weight:700}
128
+ .meta{color:#64748b;margin-bottom:1rem}
129
+ .bar-bg{background:#e2e8f0;border-radius:4px;height:14px;width:100%}
130
+ .bar-fill{height:100%;border-radius:4px;transition:width .3s}
131
+ ul{list-style:disc;padding-left:1.5rem;margin-bottom:.5rem}
132
+ li{margin:.2rem 0}
133
+ .fix{color:#64748b;font-size:.9em;margin-top:.2rem}
134
+ .ref{color:#2563eb;font-size:.85em}
135
+ .effort-pill{display:inline-block;padding:.1rem .4rem;border-radius:9999px;color:white;font-size:.75em;font-weight:600;vertical-align:middle}
136
+ .template-banner{background:#fef3c7;border:1px solid #f59e0b;border-radius:6px;padding:.5rem 1rem;margin:.5rem 0;color:#92400e;font-size:.9em}
137
+ details{margin:.25rem 0}
138
+ summary{cursor:pointer;color:#2563eb;font-size:.9em}
139
+ .cluster-details{padding:.5rem;background:#f1f5f9;border-radius:4px;margin:.25rem 0;font-size:.85em}
140
+ .cluster-details ul{margin:.25rem 0}
141
+ .member-list{max-height:200px;overflow-y:auto}
142
+ </style>
143
+ </head>
144
+ <body>
145
+ <h1>pSEOlint Audit Report</h1>
146
+ <p class="meta">Pages analysed: ${summary.pageCount}</p>
147
+ <p class="score" style="color:${scoreColor(summary.score)}">SpamBrain Risk Score: ${summary.score}/100</p>
148
+ ${summary.templateDetected ? `<p class="template-banner">Template-generated content detected. Fix suggestions are tailored for template authors.</p>` : ""}
149
+ <h2>Category Scores</h2>
150
+ <table>
151
+ <thead><tr><th>Category</th><th>Bar</th><th>Score</th></tr></thead>
152
+ <tbody>${categoryRows}</tbody>
153
+ </table>
154
+
155
+ ${summary.groupScores && summary.groupPageCounts ? `
156
+ <h2>Group Scores</h2>
157
+ <table>
158
+ <thead><tr><th>Group</th><th>Score</th><th>Pages</th></tr></thead>
159
+ <tbody>${Object.entries(summary.groupScores).map(([name, value]) => {
160
+ const count = summary.groupPageCounts[name] ?? 0;
161
+ return `<tr><td>${escapeHtml(name)}</td><td style="text-align:right">${value}</td><td style="text-align:right">${count}</td></tr>`;
162
+ }).join("\n")}</tbody>
163
+ </table>` : ""}
164
+
165
+ <h2>Findings</h2>
166
+ ${findingsSections}
167
+ </body>
168
+ </html>`;
169
+ }
170
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/formatters/html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { formatConsole } from "./console.js";
2
+ export type { ConsoleFormatOptions } from "./console.js";
3
+ export { formatJson } from "./json.js";
4
+ export { formatMarkdown } from "./markdown.js";
5
+ export { formatHtml } from "./html.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { formatConsole } from "./console.js";
2
+ export { formatJson } from "./json.js";
3
+ export { formatMarkdown } from "./markdown.js";
4
+ export { formatHtml } from "./html.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AuditSummary } from "../types.js";
2
+ export declare function formatJson(summary: AuditSummary): string;
3
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/formatters/json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,wBAAgB,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAExD"}
@@ -0,0 +1,4 @@
1
+ export function formatJson(summary) {
2
+ return JSON.stringify(summary, null, 2);
3
+ }
4
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/formatters/json.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,OAAqB;IAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AuditSummary } from "../types.js";
2
+ export declare function formatMarkdown(summary: AuditSummary): string;
3
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAmC,MAAM,aAAa,CAAC;AA0BjF,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAwE5D"}
@@ -0,0 +1,93 @@
1
+ const SEVERITY_ORDER = ["critical", "error", "warning", "info"];
2
+ function severityEmoji(severity) {
3
+ switch (severity) {
4
+ case "critical":
5
+ return "🔴";
6
+ case "error":
7
+ return "🟠";
8
+ case "warning":
9
+ return "🟡";
10
+ case "info":
11
+ return "🔵";
12
+ }
13
+ }
14
+ function effortBadge(effort) {
15
+ if (!effort)
16
+ return "";
17
+ return ` (**${effort} fix**)`;
18
+ }
19
+ function shortenUrl(url) {
20
+ try {
21
+ return new URL(url).pathname;
22
+ }
23
+ catch {
24
+ return url;
25
+ }
26
+ }
27
+ export function formatMarkdown(summary) {
28
+ const lines = [];
29
+ lines.push(`# pSEOlint Audit Report`);
30
+ lines.push("");
31
+ lines.push(`**SpamBrain Risk Score:** ${summary.score}/100`);
32
+ lines.push(`**Pages analysed:** ${summary.pageCount}`);
33
+ if (summary.templateDetected) {
34
+ lines.push("");
35
+ lines.push(`> Template-generated content detected. Fix suggestions are tailored for template authors.`);
36
+ }
37
+ lines.push("");
38
+ // Category scores table
39
+ lines.push(`## Category Scores`);
40
+ lines.push("");
41
+ lines.push(`| Category | Score |`);
42
+ lines.push(`|----------|------:|`);
43
+ for (const [name, value] of Object.entries(summary.categoryScores)) {
44
+ const label = name.charAt(0).toUpperCase() + name.slice(1);
45
+ lines.push(`| ${label} | ${value} |`);
46
+ }
47
+ lines.push("");
48
+ // Group scores
49
+ if (summary.groupScores && summary.groupPageCounts) {
50
+ lines.push(`## Group Scores`);
51
+ lines.push("");
52
+ lines.push(`| Group | Score | Pages |`);
53
+ lines.push(`|-------|------:|------:|`);
54
+ for (const [name, value] of Object.entries(summary.groupScores)) {
55
+ const count = summary.groupPageCounts[name] ?? 0;
56
+ lines.push(`| ${name} | ${value} | ${count} |`);
57
+ }
58
+ lines.push("");
59
+ }
60
+ // Findings
61
+ lines.push(`## Findings`);
62
+ lines.push("");
63
+ const grouped = new Map();
64
+ for (const sev of SEVERITY_ORDER) {
65
+ grouped.set(sev, []);
66
+ }
67
+ for (const f of summary.findings) {
68
+ grouped.get(f.severity).push(f);
69
+ }
70
+ for (const sev of SEVERITY_ORDER) {
71
+ const items = grouped.get(sev);
72
+ if (items.length === 0)
73
+ continue;
74
+ lines.push(`### ${severityEmoji(sev)} ${sev.charAt(0).toUpperCase() + sev.slice(1)} (${items.length})`);
75
+ lines.push("");
76
+ for (const item of items) {
77
+ lines.push(`- **${item.ruleId}**${effortBadge(item.effort)}: ${item.message}`);
78
+ if (item.context?.type === "cluster" && item.context.worstPairs.length > 0) {
79
+ const p = item.context.worstPairs[0];
80
+ lines.push(` > Worst: ${shortenUrl(p.left)} ↔ ${shortenUrl(p.right)} (${(p.similarity * 100).toFixed(1)}%)`);
81
+ }
82
+ if (item.fix) {
83
+ lines.push(` > ${item.fix}`);
84
+ }
85
+ if (item.ref) {
86
+ lines.push(` > [Google reference](${item.ref})`);
87
+ }
88
+ }
89
+ lines.push("");
90
+ }
91
+ return lines.join("\n");
92
+ }
93
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ export * from "./types.js";
2
+ export * from "./auditor.js";
3
+ export * from "./parser.js";
4
+ export * from "./url-normalize.js";
5
+ export * from "./algorithms/simhash.js";
6
+ export * from "./algorithms/entity-mask.js";
7
+ export * from "./rules/spam/near-duplicate.js";
8
+ export * from "./rules/spam/entity-swap.js";
9
+ export * from "./rules/spam/thin-content.js";
10
+ export * from "./rules/spam/boilerplate-ratio.js";
11
+ export * from "./rules/spam/template-diversity.js";
12
+ export * from "./rules/spam/publication-velocity.js";
13
+ export * from "./rules/spam/doorway-pattern.js";
14
+ export * from "./rules/spam/template-coverage.js";
15
+ export * from "./rules/content/unique-value.js";
16
+ export * from "./rules/content/heading-uniqueness.js";
17
+ export * from "./rules/content/meta-uniqueness.js";
18
+ export * from "./rules/content/missing-author.js";
19
+ export * from "./rules/content/eeat-signals.js";
20
+ export * from "./rules/links/orphan-pages.js";
21
+ export * from "./rules/links/dead-ends.js";
22
+ export * from "./rules/links/link-depth.js";
23
+ export * from "./rules/links/cluster-connectivity.js";
24
+ export * from "./rules/links/hub-pages.js";
25
+ export * from "./rules/tech/canonical-consistency.js";
26
+ export * from "./rules/tech/canonical-noindex-conflict.js";
27
+ export * from "./rules/tech/robots-noindex-conflict.js";
28
+ export * from "./rules/tech/sitemap-completeness.js";
29
+ export * from "./rules/tech/redirect-chain.js";
30
+ export * from "./rules/tech/soft-404.js";
31
+ export * from "./rules/tech/og-completeness.js";
32
+ export * from "./rules/tech/hreflang-consistency.js";
33
+ export * from "./rules/schema/json-ld-valid.js";
34
+ export * from "./rules/schema/required-fields.js";
35
+ export * from "./rules/schema/consistency.js";
36
+ export * from "./algorithms/tf-idf.js";
37
+ export * from "./rules/cannibal/title-overlap.js";
38
+ export * from "./rules/cannibal/keyword-collision.js";
39
+ export * from "./rules/cannibal/url-pattern.js";
40
+ export * from "./rule-references.js";
41
+ export * from "./page-classifier.js";
42
+ export * from "./formatters/index.js";
43
+ export * from "./renderer.js";
44
+ export * from "./enrich-findings.js";
45
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,sCAAsC,CAAC;AACrD,cAAc,iCAAiC,CAAC;AAChD,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AACtD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uCAAuC,CAAC;AACtD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uCAAuC,CAAC;AACtD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,yCAAyC,CAAC;AACxD,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAChD,cAAc,sCAAsC,CAAC;AACrD,cAAc,iCAAiC,CAAC;AAChD,cAAc,mCAAmC,CAAC;AAClD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,iCAAiC,CAAC;AAChD,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC"}