@pseolint/core 0.4.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +264 -169
- package/dist/ai/manifest/diff.d.ts +78 -0
- package/dist/ai/manifest/diff.d.ts.map +1 -0
- package/dist/ai/manifest/diff.js +139 -0
- package/dist/ai/manifest/diff.js.map +1 -0
- package/dist/ai/manifest/index.d.ts +18 -0
- package/dist/ai/manifest/index.d.ts.map +1 -0
- package/dist/ai/manifest/index.js +15 -0
- package/dist/ai/manifest/index.js.map +1 -0
- package/dist/ai/manifest/validate-manifest.d.ts +37 -0
- package/dist/ai/manifest/validate-manifest.d.ts.map +1 -0
- package/dist/ai/manifest/validate-manifest.js +67 -0
- package/dist/ai/manifest/validate-manifest.js.map +1 -0
- package/dist/ai/manifest/validators/domain-patches.d.ts +15 -0
- package/dist/ai/manifest/validators/domain-patches.d.ts.map +1 -0
- package/dist/ai/manifest/validators/domain-patches.js +110 -0
- package/dist/ai/manifest/validators/domain-patches.js.map +1 -0
- package/dist/ai/manifest/validators/index.d.ts +5 -0
- package/dist/ai/manifest/validators/index.d.ts.map +1 -0
- package/dist/ai/manifest/validators/index.js +4 -0
- package/dist/ai/manifest/validators/index.js.map +1 -0
- package/dist/ai/manifest/validators/page-changes.d.ts +36 -0
- package/dist/ai/manifest/validators/page-changes.d.ts.map +1 -0
- package/dist/ai/manifest/validators/page-changes.js +221 -0
- package/dist/ai/manifest/validators/page-changes.js.map +1 -0
- package/dist/ai/manifest/validators/types.d.ts +17 -0
- package/dist/ai/manifest/validators/types.d.ts.map +1 -0
- package/dist/ai/manifest/validators/types.js +5 -0
- package/dist/ai/manifest/validators/types.js.map +1 -0
- package/dist/ai/orchestrate.d.ts +74 -0
- package/dist/ai/orchestrate.d.ts.map +1 -0
- package/dist/ai/orchestrate.js +54 -0
- package/dist/ai/orchestrate.js.map +1 -0
- package/dist/ai/orchestrator/budget.d.ts +57 -0
- package/dist/ai/orchestrator/budget.d.ts.map +1 -0
- package/dist/ai/orchestrator/budget.js +114 -0
- package/dist/ai/orchestrator/budget.js.map +1 -0
- package/dist/ai/orchestrator/finish-tool.d.ts +568 -0
- package/dist/ai/orchestrator/finish-tool.d.ts.map +1 -0
- package/dist/ai/orchestrator/finish-tool.js +114 -0
- package/dist/ai/orchestrator/finish-tool.js.map +1 -0
- package/dist/ai/orchestrator/index.d.ts +25 -0
- package/dist/ai/orchestrator/index.d.ts.map +1 -0
- package/dist/ai/orchestrator/index.js +21 -0
- package/dist/ai/orchestrator/index.js.map +1 -0
- package/dist/ai/orchestrator/log.d.ts +24 -0
- package/dist/ai/orchestrator/log.d.ts.map +1 -0
- package/dist/ai/orchestrator/log.js +48 -0
- package/dist/ai/orchestrator/log.js.map +1 -0
- package/dist/ai/orchestrator/page-cache.d.ts +64 -0
- package/dist/ai/orchestrator/page-cache.d.ts.map +1 -0
- package/dist/ai/orchestrator/page-cache.js +127 -0
- package/dist/ai/orchestrator/page-cache.js.map +1 -0
- package/dist/ai/orchestrator/prompt.d.ts +16 -0
- package/dist/ai/orchestrator/prompt.d.ts.map +1 -0
- package/dist/ai/orchestrator/prompt.js +52 -0
- package/dist/ai/orchestrator/prompt.js.map +1 -0
- package/dist/ai/orchestrator/runner.d.ts +65 -0
- package/dist/ai/orchestrator/runner.d.ts.map +1 -0
- package/dist/ai/orchestrator/runner.js +223 -0
- package/dist/ai/orchestrator/runner.js.map +1 -0
- package/dist/ai/orchestrator/session.d.ts +44 -0
- package/dist/ai/orchestrator/session.d.ts.map +1 -0
- package/dist/ai/orchestrator/session.js +64 -0
- package/dist/ai/orchestrator/session.js.map +1 -0
- package/dist/ai/orchestrator/types.d.ts +99 -0
- package/dist/ai/orchestrator/types.d.ts.map +1 -0
- package/dist/ai/orchestrator/types.js +8 -0
- package/dist/ai/orchestrator/types.js.map +1 -0
- package/dist/ai/probes/cache.d.ts +12 -0
- package/dist/ai/probes/cache.d.ts.map +1 -0
- package/dist/ai/probes/cache.js +46 -0
- package/dist/ai/probes/cache.js.map +1 -0
- package/dist/ai/tools/ask-ai-engine.d.ts +77 -0
- package/dist/ai/tools/ask-ai-engine.d.ts.map +1 -0
- package/dist/ai/tools/ask-ai-engine.js +253 -0
- package/dist/ai/tools/ask-ai-engine.js.map +1 -0
- package/dist/ai/tools/check-domain-crawler-access.d.ts +71 -0
- package/dist/ai/tools/check-domain-crawler-access.d.ts.map +1 -0
- package/dist/ai/tools/check-domain-crawler-access.js +76 -0
- package/dist/ai/tools/check-domain-crawler-access.js.map +1 -0
- package/dist/ai/tools/check-domain-llms-txt.d.ts +70 -0
- package/dist/ai/tools/check-domain-llms-txt.d.ts.map +1 -0
- package/dist/ai/tools/check-domain-llms-txt.js +75 -0
- package/dist/ai/tools/check-domain-llms-txt.js.map +1 -0
- package/dist/ai/tools/check-indexability.d.ts +58 -0
- package/dist/ai/tools/check-indexability.d.ts.map +1 -0
- package/dist/ai/tools/check-indexability.js +64 -0
- package/dist/ai/tools/check-indexability.js.map +1 -0
- package/dist/ai/tools/check-robots.d.ts +68 -0
- package/dist/ai/tools/check-robots.d.ts.map +1 -0
- package/dist/ai/tools/check-robots.js +90 -0
- package/dist/ai/tools/check-robots.js.map +1 -0
- package/dist/ai/tools/check-rule-answer-first.d.ts +54 -0
- package/dist/ai/tools/check-rule-answer-first.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-answer-first.js +50 -0
- package/dist/ai/tools/check-rule-answer-first.js.map +1 -0
- package/dist/ai/tools/check-rule-canonical-consistency.d.ts +66 -0
- package/dist/ai/tools/check-rule-canonical-consistency.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-canonical-consistency.js +51 -0
- package/dist/ai/tools/check-rule-canonical-consistency.js.map +1 -0
- package/dist/ai/tools/check-rule-citable-facts.d.ts +58 -0
- package/dist/ai/tools/check-rule-citable-facts.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-citable-facts.js +41 -0
- package/dist/ai/tools/check-rule-citable-facts.js.map +1 -0
- package/dist/ai/tools/check-rule-content-modularity.d.ts +58 -0
- package/dist/ai/tools/check-rule-content-modularity.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-content-modularity.js +45 -0
- package/dist/ai/tools/check-rule-content-modularity.js.map +1 -0
- package/dist/ai/tools/check-rule-faq-coverage.d.ts +54 -0
- package/dist/ai/tools/check-rule-faq-coverage.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-faq-coverage.js +39 -0
- package/dist/ai/tools/check-rule-faq-coverage.js.map +1 -0
- package/dist/ai/tools/check-rule-freshness-signals.d.ts +54 -0
- package/dist/ai/tools/check-rule-freshness-signals.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-freshness-signals.js +45 -0
- package/dist/ai/tools/check-rule-freshness-signals.js.map +1 -0
- package/dist/ai/tools/check-rule-json-ld-valid.d.ts +54 -0
- package/dist/ai/tools/check-rule-json-ld-valid.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-json-ld-valid.js +44 -0
- package/dist/ai/tools/check-rule-json-ld-valid.js.map +1 -0
- package/dist/ai/tools/check-rule-missing-author.d.ts +54 -0
- package/dist/ai/tools/check-rule-missing-author.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-missing-author.js +45 -0
- package/dist/ai/tools/check-rule-missing-author.js.map +1 -0
- package/dist/ai/tools/check-rule-near-duplicate.d.ts +82 -0
- package/dist/ai/tools/check-rule-near-duplicate.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-near-duplicate.js +63 -0
- package/dist/ai/tools/check-rule-near-duplicate.js.map +1 -0
- package/dist/ai/tools/check-rule-required-fields.d.ts +50 -0
- package/dist/ai/tools/check-rule-required-fields.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-required-fields.js +38 -0
- package/dist/ai/tools/check-rule-required-fields.js.map +1 -0
- package/dist/ai/tools/check-rule-schema-consistency.d.ts +54 -0
- package/dist/ai/tools/check-rule-schema-consistency.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-schema-consistency.js +44 -0
- package/dist/ai/tools/check-rule-schema-consistency.js.map +1 -0
- package/dist/ai/tools/check-rule-summary-bait.d.ts +54 -0
- package/dist/ai/tools/check-rule-summary-bait.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-summary-bait.js +39 -0
- package/dist/ai/tools/check-rule-summary-bait.js.map +1 -0
- package/dist/ai/tools/check-rule-thin-content.d.ts +66 -0
- package/dist/ai/tools/check-rule-thin-content.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-thin-content.js +58 -0
- package/dist/ai/tools/check-rule-thin-content.js.map +1 -0
- package/dist/ai/tools/detect-templates.d.ts +60 -0
- package/dist/ai/tools/detect-templates.d.ts.map +1 -0
- package/dist/ai/tools/detect-templates.js +43 -0
- package/dist/ai/tools/detect-templates.js.map +1 -0
- package/dist/ai/tools/fetch-page.d.ts +70 -0
- package/dist/ai/tools/fetch-page.d.ts.map +1 -0
- package/dist/ai/tools/fetch-page.js +93 -0
- package/dist/ai/tools/fetch-page.js.map +1 -0
- package/dist/ai/tools/fetch-sitemap.d.ts +60 -0
- package/dist/ai/tools/fetch-sitemap.d.ts.map +1 -0
- package/dist/ai/tools/fetch-sitemap.js +116 -0
- package/dist/ai/tools/fetch-sitemap.js.map +1 -0
- package/dist/ai/tools/index.d.ts +1555 -0
- package/dist/ai/tools/index.d.ts.map +1 -0
- package/dist/ai/tools/index.js +119 -0
- package/dist/ai/tools/index.js.map +1 -0
- package/dist/ai/tools/parse-page.d.ts +94 -0
- package/dist/ai/tools/parse-page.d.ts.map +1 -0
- package/dist/ai/tools/parse-page.js +108 -0
- package/dist/ai/tools/parse-page.js.map +1 -0
- package/dist/ai/tools/query-serp.d.ts +113 -0
- package/dist/ai/tools/query-serp.d.ts.map +1 -0
- package/dist/ai/tools/query-serp.js +131 -0
- package/dist/ai/tools/query-serp.js.map +1 -0
- package/dist/ai/tools/sample-template.d.ts +67 -0
- package/dist/ai/tools/sample-template.d.ts.map +1 -0
- package/dist/ai/tools/sample-template.js +75 -0
- package/dist/ai/tools/sample-template.js.map +1 -0
- package/dist/ai/tools/types.d.ts +73 -0
- package/dist/ai/tools/types.d.ts.map +1 -0
- package/dist/ai/tools/types.js +64 -0
- package/dist/ai/tools/types.js.map +1 -0
- package/dist/ai/tools/validate-jsonld.d.ts +62 -0
- package/dist/ai/tools/validate-jsonld.d.ts.map +1 -0
- package/dist/ai/tools/validate-jsonld.js +84 -0
- package/dist/ai/tools/validate-jsonld.js.map +1 -0
- package/dist/auditor.d.ts +16 -1
- package/dist/auditor.d.ts.map +1 -1
- package/dist/auditor.js +862 -88
- package/dist/auditor.js.map +1 -1
- package/dist/backpressure.d.ts.map +1 -1
- package/dist/backpressure.js +10 -3
- package/dist/backpressure.js.map +1 -1
- package/dist/enrich-findings.d.ts.map +1 -1
- package/dist/enrich-findings.js +15 -1
- package/dist/enrich-findings.js.map +1 -1
- package/dist/formatters/bucket-findings.d.ts +43 -0
- package/dist/formatters/bucket-findings.d.ts.map +1 -0
- package/dist/formatters/bucket-findings.js +110 -0
- package/dist/formatters/bucket-findings.js.map +1 -0
- package/dist/formatters/console.d.ts.map +1 -1
- package/dist/formatters/console.js +116 -34
- package/dist/formatters/console.js.map +1 -1
- package/dist/formatters/fixplan.d.ts +13 -0
- package/dist/formatters/fixplan.d.ts.map +1 -0
- package/dist/formatters/fixplan.js +328 -0
- package/dist/formatters/fixplan.js.map +1 -0
- package/dist/formatters/html.d.ts.map +1 -1
- package/dist/formatters/html.js +27 -0
- package/dist/formatters/html.js.map +1 -1
- package/dist/formatters/index.d.ts +2 -0
- package/dist/formatters/index.d.ts.map +1 -1
- package/dist/formatters/index.js +1 -0
- package/dist/formatters/index.js.map +1 -1
- package/dist/formatters/markdown.d.ts.map +1 -1
- package/dist/formatters/markdown.js +97 -9
- package/dist/formatters/markdown.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/page-filter.d.ts +64 -6
- package/dist/page-filter.d.ts.map +1 -1
- package/dist/page-filter.js +124 -3
- package/dist/page-filter.js.map +1 -1
- package/dist/rule-references.d.ts.map +1 -1
- package/dist/rule-references.js +5 -0
- package/dist/rule-references.js.map +1 -1
- package/dist/rules/aeo/answer-first.d.ts.map +1 -1
- package/dist/rules/aeo/answer-first.js +17 -3
- package/dist/rules/aeo/answer-first.js.map +1 -1
- package/dist/rules/aeo/citable-facts.d.ts.map +1 -1
- package/dist/rules/aeo/citable-facts.js +12 -1
- package/dist/rules/aeo/citable-facts.js.map +1 -1
- package/dist/rules/aeo/content-modularity.d.ts.map +1 -1
- package/dist/rules/aeo/content-modularity.js +3 -0
- package/dist/rules/aeo/content-modularity.js.map +1 -1
- package/dist/rules/aeo/crawler-access.d.ts.map +1 -1
- package/dist/rules/aeo/crawler-access.js +6 -0
- package/dist/rules/aeo/crawler-access.js.map +1 -1
- package/dist/rules/aeo/faq-coverage.d.ts.map +1 -1
- package/dist/rules/aeo/faq-coverage.js +4 -0
- package/dist/rules/aeo/faq-coverage.js.map +1 -1
- package/dist/rules/aeo/freshness-signals.d.ts.map +1 -1
- package/dist/rules/aeo/freshness-signals.js +9 -2
- package/dist/rules/aeo/freshness-signals.js.map +1 -1
- package/dist/rules/aeo/llms-txt.d.ts.map +1 -1
- package/dist/rules/aeo/llms-txt.js +6 -1
- package/dist/rules/aeo/llms-txt.js.map +1 -1
- package/dist/rules/aeo/summary-bait.d.ts.map +1 -1
- package/dist/rules/aeo/summary-bait.js +5 -2
- package/dist/rules/aeo/summary-bait.js.map +1 -1
- package/dist/rules/content/heading-structure.d.ts +21 -0
- package/dist/rules/content/heading-structure.d.ts.map +1 -0
- package/dist/rules/content/heading-structure.js +56 -0
- package/dist/rules/content/heading-structure.js.map +1 -0
- package/dist/rules/content/image-alt-text.d.ts +18 -0
- package/dist/rules/content/image-alt-text.d.ts.map +1 -0
- package/dist/rules/content/image-alt-text.js +77 -0
- package/dist/rules/content/image-alt-text.js.map +1 -0
- package/dist/rules/content/missing-author.d.ts.map +1 -1
- package/dist/rules/content/missing-author.js +10 -2
- package/dist/rules/content/missing-author.js.map +1 -1
- package/dist/rules/content/title-uniqueness.d.ts +18 -0
- package/dist/rules/content/title-uniqueness.d.ts.map +1 -0
- package/dist/rules/content/title-uniqueness.js +70 -0
- package/dist/rules/content/title-uniqueness.js.map +1 -0
- package/dist/rules/links/host-section-divergence.d.ts +3 -0
- package/dist/rules/links/host-section-divergence.d.ts.map +1 -0
- package/dist/rules/links/host-section-divergence.js +158 -0
- package/dist/rules/links/host-section-divergence.js.map +1 -0
- package/dist/rules/links/link-depth.d.ts +12 -1
- package/dist/rules/links/link-depth.d.ts.map +1 -1
- package/dist/rules/links/link-depth.js +25 -12
- package/dist/rules/links/link-depth.js.map +1 -1
- package/dist/rules/scope.d.ts.map +1 -1
- package/dist/rules/scope.js +5 -0
- package/dist/rules/scope.js.map +1 -1
- package/dist/rules/spam/doorway-pattern.d.ts.map +1 -1
- package/dist/rules/spam/doorway-pattern.js +27 -4
- package/dist/rules/spam/doorway-pattern.js.map +1 -1
- package/dist/rules/spam/publication-velocity.d.ts +1 -1
- package/dist/rules/spam/publication-velocity.d.ts.map +1 -1
- package/dist/rules/spam/publication-velocity.js +9 -4
- package/dist/rules/spam/publication-velocity.js.map +1 -1
- package/dist/rules/spam/template-coverage.js +1 -1
- package/dist/rules/spam/template-coverage.js.map +1 -1
- package/dist/rules/spam/template-diversity.js +1 -1
- package/dist/rules/spam/template-diversity.js.map +1 -1
- package/dist/rules/spam/thin-content.d.ts.map +1 -1
- package/dist/rules/spam/thin-content.js +9 -1
- package/dist/rules/spam/thin-content.js.map +1 -1
- package/dist/rules/tech/hreflang-consistency.d.ts.map +1 -1
- package/dist/rules/tech/hreflang-consistency.js +33 -4
- package/dist/rules/tech/hreflang-consistency.js.map +1 -1
- package/dist/rules/tech/og-completeness.d.ts +11 -0
- package/dist/rules/tech/og-completeness.d.ts.map +1 -1
- package/dist/rules/tech/og-completeness.js +22 -23
- package/dist/rules/tech/og-completeness.js.map +1 -1
- package/dist/ruleset-version.d.ts +8 -0
- package/dist/ruleset-version.d.ts.map +1 -0
- package/dist/ruleset-version.js +8 -0
- package/dist/ruleset-version.js.map +1 -0
- package/dist/scrape-strategy.d.ts +42 -0
- package/dist/scrape-strategy.d.ts.map +1 -0
- package/dist/scrape-strategy.js +101 -0
- package/dist/scrape-strategy.js.map +1 -0
- package/dist/site-classifier.d.ts +1 -1
- package/dist/site-classifier.d.ts.map +1 -1
- package/dist/site-classifier.js +217 -0
- package/dist/site-classifier.js.map +1 -1
- package/dist/state.d.ts +36 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +3 -1
- package/dist/state.js.map +1 -1
- package/dist/stratified-sample.d.ts +9 -1
- package/dist/stratified-sample.d.ts.map +1 -1
- package/dist/stratified-sample.js +23 -6
- package/dist/stratified-sample.js.map +1 -1
- package/dist/types.d.ts +179 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/url-normalize.d.ts.map +1 -1
- package/dist/url-normalize.js +13 -1
- package/dist/url-normalize.js.map +1 -1
- package/package.json +90 -90
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { inferUrlTemplate } from "../stratified-sample.js";
|
|
2
|
+
const CONFIDENCE_RANK = {
|
|
3
|
+
speculative: 1,
|
|
4
|
+
low: 2,
|
|
5
|
+
medium: 3,
|
|
6
|
+
high: 4,
|
|
7
|
+
};
|
|
8
|
+
function confidenceCaveat(c) {
|
|
9
|
+
if (c === "low")
|
|
10
|
+
return "low confidence — known false-positive risk on this site type";
|
|
11
|
+
if (c === "speculative")
|
|
12
|
+
return "speculative — heuristic match; verify before acting";
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const SEVERITY_RANK = {
|
|
16
|
+
critical: 0,
|
|
17
|
+
error: 1,
|
|
18
|
+
warning: 2,
|
|
19
|
+
info: 3,
|
|
20
|
+
};
|
|
21
|
+
const EFFORT_ORDER = [
|
|
22
|
+
"quick",
|
|
23
|
+
"moderate",
|
|
24
|
+
"structural",
|
|
25
|
+
"other",
|
|
26
|
+
];
|
|
27
|
+
const EFFORT_HEADING = {
|
|
28
|
+
quick: "Quick wins (≤ 30 min each)",
|
|
29
|
+
moderate: "Moderate fixes (1-2 hours each)",
|
|
30
|
+
structural: "Structural changes (deeper refactor)",
|
|
31
|
+
other: "Other fixes",
|
|
32
|
+
};
|
|
33
|
+
/** Approximate hours-per-fix used in the footer estimate. */
|
|
34
|
+
const EFFORT_HOURS = {
|
|
35
|
+
quick: 0.5,
|
|
36
|
+
moderate: 1.5,
|
|
37
|
+
structural: 4,
|
|
38
|
+
other: 1,
|
|
39
|
+
};
|
|
40
|
+
const VERDICT_LABEL = {
|
|
41
|
+
ready: "ready",
|
|
42
|
+
caution: "caution",
|
|
43
|
+
concerning: "concerning",
|
|
44
|
+
critical: "critical",
|
|
45
|
+
};
|
|
46
|
+
function shortenUrl(url) {
|
|
47
|
+
if (!url)
|
|
48
|
+
return "";
|
|
49
|
+
try {
|
|
50
|
+
return new URL(url).pathname || "/";
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return url;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolve a template signature for bucketing. Prefer the enrichment-pipeline
|
|
58
|
+
* field (`templateSignature` populated post Agent C), else derive one from the
|
|
59
|
+
* page URL via `inferUrlTemplate`. Findings with no `pageUrl` (corpus-scoped
|
|
60
|
+
* rules) get a synthetic `__corpus__` signature so they each land in their
|
|
61
|
+
* own per-rule bucket.
|
|
62
|
+
*/
|
|
63
|
+
function templateSigFor(f) {
|
|
64
|
+
const sig = f.templateSignature;
|
|
65
|
+
if (sig && sig.length > 0)
|
|
66
|
+
return sig;
|
|
67
|
+
if (f.pageUrl)
|
|
68
|
+
return inferUrlTemplate(f.pageUrl);
|
|
69
|
+
return "__corpus__";
|
|
70
|
+
}
|
|
71
|
+
function bucketByTemplate(findings) {
|
|
72
|
+
const map = new Map();
|
|
73
|
+
for (const f of findings) {
|
|
74
|
+
const sig = templateSigFor(f);
|
|
75
|
+
const key = `${f.ruleId} ${sig}`;
|
|
76
|
+
let b = map.get(key);
|
|
77
|
+
const rank = SEVERITY_RANK[f.severity] ?? 3;
|
|
78
|
+
if (!b) {
|
|
79
|
+
b = {
|
|
80
|
+
ruleId: f.ruleId,
|
|
81
|
+
templateSignature: sig,
|
|
82
|
+
count: 0,
|
|
83
|
+
worstSeverityRank: rank,
|
|
84
|
+
worstSeverity: f.severity,
|
|
85
|
+
effort: f.effort ?? "other",
|
|
86
|
+
exemplar: f,
|
|
87
|
+
urls: [],
|
|
88
|
+
worstConfidence: f.confidence,
|
|
89
|
+
};
|
|
90
|
+
map.set(key, b);
|
|
91
|
+
}
|
|
92
|
+
b.count += 1;
|
|
93
|
+
if (rank < b.worstSeverityRank) {
|
|
94
|
+
b.worstSeverityRank = rank;
|
|
95
|
+
b.worstSeverity = f.severity;
|
|
96
|
+
}
|
|
97
|
+
// Promote effort if the bucket was "other" but a later finding declares one.
|
|
98
|
+
if (b.effort === "other" && f.effort) {
|
|
99
|
+
b.effort = f.effort;
|
|
100
|
+
}
|
|
101
|
+
if (f.confidence !== undefined) {
|
|
102
|
+
const cur = b.worstConfidence;
|
|
103
|
+
if (cur === undefined || CONFIDENCE_RANK[f.confidence] < CONFIDENCE_RANK[cur]) {
|
|
104
|
+
b.worstConfidence = f.confidence;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (f.pageUrl && !b.urls.includes(f.pageUrl)) {
|
|
108
|
+
b.urls.push(f.pageUrl);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return Array.from(map.values());
|
|
112
|
+
}
|
|
113
|
+
function isTemplateBucket(b) {
|
|
114
|
+
// A "template" bucket is one whose signature contains a generalised segment
|
|
115
|
+
// (`:slug`, `:num`, `:id`, `:date`). Single-page or corpus buckets render
|
|
116
|
+
// without the "x N instances on `<template>`" suffix.
|
|
117
|
+
return /:slug|:num|:id|:date/.test(b.templateSignature);
|
|
118
|
+
}
|
|
119
|
+
function bucketHeadline(b) {
|
|
120
|
+
const code = `\`${b.ruleId}\``;
|
|
121
|
+
if (b.count > 1 && isTemplateBucket(b)) {
|
|
122
|
+
return `**${code} × ${b.count} instances on \`${b.templateSignature}\` template**`;
|
|
123
|
+
}
|
|
124
|
+
if (b.count > 1) {
|
|
125
|
+
return `**${code} × ${b.count} affected pages**`;
|
|
126
|
+
}
|
|
127
|
+
if (b.exemplar.pageUrl) {
|
|
128
|
+
return `**${code} on \`${shortenUrl(b.exemplar.pageUrl)}\`**`;
|
|
129
|
+
}
|
|
130
|
+
return `**${code}**`;
|
|
131
|
+
}
|
|
132
|
+
function bucketNarrative(b) {
|
|
133
|
+
// Prefer the explicit `fix` narrative when present; else paraphrase the
|
|
134
|
+
// message. Hard-wrap the narrative onto a single bullet line.
|
|
135
|
+
const text = (b.exemplar.fix ?? b.exemplar.message).trim();
|
|
136
|
+
return text.endsWith(".") ? text : `${text}.`;
|
|
137
|
+
}
|
|
138
|
+
function renderBucketLines(b) {
|
|
139
|
+
const lines = [];
|
|
140
|
+
lines.push(`- [ ] ${bucketHeadline(b)} — ${bucketNarrative(b)}`);
|
|
141
|
+
const caveat = confidenceCaveat(b.worstConfidence);
|
|
142
|
+
if (caveat) {
|
|
143
|
+
lines.push(` - _${caveat}_`);
|
|
144
|
+
}
|
|
145
|
+
// Nested bullet: first concrete URL example (only useful when we have one).
|
|
146
|
+
if (b.exemplar.pageUrl) {
|
|
147
|
+
if (b.count > 1 && isTemplateBucket(b) && b.urls.length > 0) {
|
|
148
|
+
const first = shortenUrl(b.urls[0]);
|
|
149
|
+
const allShort = b.urls.slice(0, 4).map((u) => `\`${shortenUrl(u)}\``).join(", ");
|
|
150
|
+
const more = b.urls.length > 4 ? `, +${b.urls.length - 4} more` : "";
|
|
151
|
+
lines.push(` - First instance: \`${first}\` — ${b.exemplar.message}`);
|
|
152
|
+
lines.push(` - Pages: ${allShort}${more}`);
|
|
153
|
+
}
|
|
154
|
+
else if (b.count === 1) {
|
|
155
|
+
// Single-finding bucket: URL is already in the headline; show the raw
|
|
156
|
+
// message as a secondary line so the user has the engine's verbatim
|
|
157
|
+
// explanation alongside the fix narrative.
|
|
158
|
+
if (b.exemplar.fix && b.exemplar.message && b.exemplar.fix !== b.exemplar.message) {
|
|
159
|
+
lines.push(` - ${b.exemplar.message}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return lines;
|
|
164
|
+
}
|
|
165
|
+
function renderEffortSection(effort, buckets) {
|
|
166
|
+
if (buckets.length === 0)
|
|
167
|
+
return [];
|
|
168
|
+
const lines = [];
|
|
169
|
+
lines.push(`## ${EFFORT_HEADING[effort]}`);
|
|
170
|
+
lines.push("");
|
|
171
|
+
for (const b of buckets) {
|
|
172
|
+
lines.push(...renderBucketLines(b));
|
|
173
|
+
}
|
|
174
|
+
lines.push("");
|
|
175
|
+
return lines;
|
|
176
|
+
}
|
|
177
|
+
function summarizeSkips(summary) {
|
|
178
|
+
const out = { noindex: 0, authDetected: 0, contentHashUnchanged: 0, other: 0 };
|
|
179
|
+
const total = summary.skippedUrls?.length ?? 0;
|
|
180
|
+
if (total === 0)
|
|
181
|
+
return out;
|
|
182
|
+
const policyFinding = summary.diagnostics?.auditFindings?.find((f) => f.ruleId === "audit/skipped-by-policy");
|
|
183
|
+
if (policyFinding) {
|
|
184
|
+
// The policy finding's message embeds counts like "3 marked noindex,
|
|
185
|
+
// 2 detected as auth". Parse them out: cheap heuristic that matches the
|
|
186
|
+
// auditor's own emit format.
|
|
187
|
+
const noindex = /(\d+)\s+marked noindex/i.exec(policyFinding.message);
|
|
188
|
+
const auth = /(\d+)\s+detected as auth/i.exec(policyFinding.message);
|
|
189
|
+
if (noindex)
|
|
190
|
+
out.noindex = Number(noindex[1]);
|
|
191
|
+
if (auth)
|
|
192
|
+
out.authDetected = Number(auth[1]);
|
|
193
|
+
}
|
|
194
|
+
// Whatever's left in skippedUrls but not accounted for by policy is most
|
|
195
|
+
// likely state-cache (`--since` skipped contentHash-unchanged URLs).
|
|
196
|
+
const policyTotal = out.noindex + out.authDetected;
|
|
197
|
+
const remainder = Math.max(0, total - policyTotal);
|
|
198
|
+
out.contentHashUnchanged = remainder;
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
function renderSkippedSection(summary) {
|
|
202
|
+
const total = summary.skippedUrls?.length ?? 0;
|
|
203
|
+
if (total === 0)
|
|
204
|
+
return [];
|
|
205
|
+
const breakdown = summarizeSkips(summary);
|
|
206
|
+
const lines = [];
|
|
207
|
+
lines.push(`## Skipped this run`);
|
|
208
|
+
lines.push("");
|
|
209
|
+
if (breakdown.noindex > 0) {
|
|
210
|
+
lines.push(`- ${breakdown.noindex} page${breakdown.noindex === 1 ? "" : "s"} skipped (noindex)`);
|
|
211
|
+
}
|
|
212
|
+
if (breakdown.authDetected > 0) {
|
|
213
|
+
lines.push(`- ${breakdown.authDetected} page${breakdown.authDetected === 1 ? "" : "s"} skipped (auth-detected)`);
|
|
214
|
+
}
|
|
215
|
+
if (breakdown.contentHashUnchanged > 0) {
|
|
216
|
+
lines.push(`- ${breakdown.contentHashUnchanged} page${breakdown.contentHashUnchanged === 1 ? "" : "s"} skipped (unchanged since prior run)`);
|
|
217
|
+
}
|
|
218
|
+
if (breakdown.noindex === 0 &&
|
|
219
|
+
breakdown.authDetected === 0 &&
|
|
220
|
+
breakdown.contentHashUnchanged === 0) {
|
|
221
|
+
lines.push(`- ${total} page${total === 1 ? "" : "s"} skipped`);
|
|
222
|
+
}
|
|
223
|
+
lines.push("");
|
|
224
|
+
return lines;
|
|
225
|
+
}
|
|
226
|
+
function todayUtc() {
|
|
227
|
+
return new Date().toISOString().slice(0, 10);
|
|
228
|
+
}
|
|
229
|
+
function auditedAsFixplanLine(c) {
|
|
230
|
+
if (!c)
|
|
231
|
+
return null;
|
|
232
|
+
const confPct = Math.round(c.confidence * 100);
|
|
233
|
+
const suppressed = c.suppressedRules.length;
|
|
234
|
+
const suppressedPart = suppressed > 0
|
|
235
|
+
? ` ${suppressed} pSEO-only rule${suppressed === 1 ? "" : "s"} suppressed.`
|
|
236
|
+
: "";
|
|
237
|
+
return `> Audited as **${c.type}** (${confPct}% confidence).${suppressedPart}`;
|
|
238
|
+
}
|
|
239
|
+
function estimateHours(buckets) {
|
|
240
|
+
let h = 0;
|
|
241
|
+
for (const b of buckets) {
|
|
242
|
+
h += EFFORT_HOURS[b.effort];
|
|
243
|
+
}
|
|
244
|
+
return Math.round(h * 10) / 10;
|
|
245
|
+
}
|
|
246
|
+
function formatHours(h) {
|
|
247
|
+
if (h <= 0)
|
|
248
|
+
return "0 hours";
|
|
249
|
+
if (h < 1)
|
|
250
|
+
return `~${Math.round(h * 60)} minutes`;
|
|
251
|
+
if (h < 10)
|
|
252
|
+
return `~${h} hours`;
|
|
253
|
+
return `~${Math.round(h)} hours`;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Render an `AuditSummary` as a GitHub-flavoured markdown checklist suitable
|
|
257
|
+
* for pasting into a PR description, issue body, or commit message. Findings
|
|
258
|
+
* are bucketed by `(ruleId, templateSignature)` so a 47-page near-duplicate
|
|
259
|
+
* cluster collapses to a single checkbox the user ticks once.
|
|
260
|
+
*/
|
|
261
|
+
export function formatFixplan(summary, options) {
|
|
262
|
+
const lines = [];
|
|
263
|
+
const date = options?.generatedDate ?? todayUtc();
|
|
264
|
+
lines.push(`# pseolint fix plan`);
|
|
265
|
+
lines.push("");
|
|
266
|
+
const verdict = VERDICT_LABEL[summary.verdict];
|
|
267
|
+
lines.push(`> Generated ${date}. Verdict: **${verdict}** (risk ${summary.risk}/100). ${summary.pageCount} pages audited.`);
|
|
268
|
+
// v0.4.3 — surface the scoring profile so plan readers know which
|
|
269
|
+
// site-type-aware overrides shaped the plan.
|
|
270
|
+
const auditedLine = auditedAsFixplanLine(summary.siteClassification);
|
|
271
|
+
if (auditedLine) {
|
|
272
|
+
lines.push(`>`);
|
|
273
|
+
lines.push(auditedLine);
|
|
274
|
+
}
|
|
275
|
+
lines.push(`>`);
|
|
276
|
+
lines.push(`> Run \`pseolint <source> --fixplan plan.md\` after each fix round to refresh`);
|
|
277
|
+
lines.push(`> this list — \`[x]\` items are inferred from finding hashes that no longer`);
|
|
278
|
+
lines.push(`> appear in the new audit.`);
|
|
279
|
+
lines.push("");
|
|
280
|
+
// Aggregate every actionable finding into a single flat list, then bucket.
|
|
281
|
+
// (`audit/*` findings are diagnostics, never appear in `summary.issues`.)
|
|
282
|
+
const allFindings = [
|
|
283
|
+
...summary.issues.blockers,
|
|
284
|
+
...summary.issues.shouldFix,
|
|
285
|
+
...summary.issues.informational,
|
|
286
|
+
];
|
|
287
|
+
const buckets = bucketByTemplate(allFindings);
|
|
288
|
+
if (buckets.length === 0) {
|
|
289
|
+
lines.push(`No findings to fix — site looks clean.`);
|
|
290
|
+
const skipLines = renderSkippedSection(summary);
|
|
291
|
+
if (skipLines.length > 0) {
|
|
292
|
+
lines.push("");
|
|
293
|
+
lines.push(...skipLines);
|
|
294
|
+
}
|
|
295
|
+
while (lines.length > 0 && lines[lines.length - 1] === "")
|
|
296
|
+
lines.pop();
|
|
297
|
+
return lines.join("\n");
|
|
298
|
+
}
|
|
299
|
+
// Group by effort, then sort within each group by count DESC, severity ASC.
|
|
300
|
+
const byEffort = new Map();
|
|
301
|
+
for (const b of buckets) {
|
|
302
|
+
const arr = byEffort.get(b.effort) ?? [];
|
|
303
|
+
arr.push(b);
|
|
304
|
+
byEffort.set(b.effort, arr);
|
|
305
|
+
}
|
|
306
|
+
for (const arr of byEffort.values()) {
|
|
307
|
+
arr.sort((a, b) => {
|
|
308
|
+
if (b.count !== a.count)
|
|
309
|
+
return b.count - a.count;
|
|
310
|
+
return a.worstSeverityRank - b.worstSeverityRank;
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
for (const effort of EFFORT_ORDER) {
|
|
314
|
+
const arr = byEffort.get(effort) ?? [];
|
|
315
|
+
lines.push(...renderEffortSection(effort, arr));
|
|
316
|
+
}
|
|
317
|
+
// Skipped section.
|
|
318
|
+
lines.push(...renderSkippedSection(summary));
|
|
319
|
+
// Footer.
|
|
320
|
+
const totalItems = buckets.length;
|
|
321
|
+
const hours = estimateHours(buckets);
|
|
322
|
+
lines.push(`---`);
|
|
323
|
+
lines.push(`*Total: ${totalItems} fix-plan item${totalItems === 1 ? "" : "s"}. Estimated time-to-\`ready\`: ${formatHours(hours)}.*`);
|
|
324
|
+
while (lines.length > 0 && lines[lines.length - 1] === "")
|
|
325
|
+
lines.pop();
|
|
326
|
+
return lines.join("\n");
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=fixplan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixplan.js","sourceRoot":"","sources":["../../src/formatters/fixplan.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/formatters/html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/formatters/html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAQb,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,iBAAiB;IAChC,mGAAmG;IACnG,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAsOD,wBAAgB,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,CA+MtF"}
|
package/dist/formatters/html.js
CHANGED
|
@@ -82,6 +82,13 @@ function renderCategoryTiles(categories) {
|
|
|
82
82
|
})
|
|
83
83
|
.join("");
|
|
84
84
|
}
|
|
85
|
+
function confidenceCaveat(c) {
|
|
86
|
+
if (c === "low")
|
|
87
|
+
return "low confidence — known false-positive risk on this site type";
|
|
88
|
+
if (c === "speculative")
|
|
89
|
+
return "speculative — heuristic match; verify before acting";
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
85
92
|
function renderFindingRow(f) {
|
|
86
93
|
const tone = severityTone(f.severity);
|
|
87
94
|
const effortPill = f.effort
|
|
@@ -90,6 +97,10 @@ function renderFindingRow(f) {
|
|
|
90
97
|
const url = f.pageUrl ? `<span class="finding-url mono">${escapeHtml(shortenUrl(f.pageUrl))}</span>` : "";
|
|
91
98
|
const fix = f.fix ? `<div class="fix"><span class="fix-label">Fix</span>${escapeHtml(f.fix)}</div>` : "";
|
|
92
99
|
const docsHref = f.docsUrl ?? `https://pseolint.dev/rules/${f.ruleId.split("/").pop() ?? f.ruleId}`;
|
|
100
|
+
const caveat = confidenceCaveat(f.confidence);
|
|
101
|
+
const caveatPill = caveat
|
|
102
|
+
? `<div class="caveat">${escapeHtml(caveat)}</div>`
|
|
103
|
+
: "";
|
|
93
104
|
// Cluster context (collapsed details) — only on findings that carry one.
|
|
94
105
|
let cluster = "";
|
|
95
106
|
if (f.context?.type === "cluster") {
|
|
@@ -115,11 +126,23 @@ function renderFindingRow(f) {
|
|
|
115
126
|
${url}
|
|
116
127
|
</div>
|
|
117
128
|
<p class="finding-msg">${escapeHtml(f.message)}</p>
|
|
129
|
+
${caveatPill}
|
|
118
130
|
${fix}
|
|
119
131
|
${cluster}
|
|
120
132
|
<a class="docs-link" href="${escapeHtml(docsHref)}" target="_blank" rel="noopener">${escapeHtml(docsHref.replace(/^https?:\/\//, ""))} ↗</a>
|
|
121
133
|
</li>`;
|
|
122
134
|
}
|
|
135
|
+
/** v0.4.3 — "Audited as <type>" line shown under the verdict badge. */
|
|
136
|
+
function auditedAsHtml(c) {
|
|
137
|
+
if (!c)
|
|
138
|
+
return "";
|
|
139
|
+
const confPct = Math.round(c.confidence * 100);
|
|
140
|
+
const suppressed = c.suppressedRules.length;
|
|
141
|
+
const suppressedPart = suppressed > 0
|
|
142
|
+
? ` ${suppressed} pSEO-only rule${suppressed === 1 ? "" : "s"} suppressed.`
|
|
143
|
+
: "";
|
|
144
|
+
return `<div class="audited-as">Audited as <strong>${escapeHtml(c.type)}</strong> (${confPct}% confidence).${escapeHtml(suppressedPart)}</div>`;
|
|
145
|
+
}
|
|
123
146
|
function renderBucketSection(label, items, tone) {
|
|
124
147
|
if (items.length === 0) {
|
|
125
148
|
return `<section class="bucket bucket-empty">
|
|
@@ -311,6 +334,9 @@ export function formatHtml(summary, _options) {
|
|
|
311
334
|
.sev.sev-warning{background:color-mix(in oklab,var(--warning) 14%,transparent);color:var(--warning);border-color:color-mix(in oklab,var(--warning) 35%,transparent)}
|
|
312
335
|
.sev.sev-muted{background:var(--card-2);color:var(--muted);border-color:var(--border-strong)}
|
|
313
336
|
|
|
337
|
+
.caveat{margin-top:6px;padding:6px 10px;border-radius:8px;background:color-mix(in oklab,var(--warning) 8%,transparent);color:var(--warning);font-size:12px;line-height:1.4;border:1px solid color-mix(in oklab,var(--warning) 22%,transparent)}
|
|
338
|
+
.audited-as{display:block;margin-top:10px;font-size:13px;color:var(--muted);font-family:ui-monospace,"SFMono-Regular",Menlo,Consolas,monospace}
|
|
339
|
+
.audited-as strong{color:var(--fg)}
|
|
314
340
|
.fix{margin-top:8px;padding:10px 12px;background:var(--card-2);border-radius:10px;color:var(--muted);font-size:13px;line-height:1.55}
|
|
315
341
|
.fix-label{display:inline-block;margin-right:8px;padding:1px 6px;border-radius:4px;
|
|
316
342
|
background:color-mix(in oklab,var(--primary) 18%,transparent);color:var(--primary);
|
|
@@ -361,6 +387,7 @@ export function formatHtml(summary, _options) {
|
|
|
361
387
|
|
|
362
388
|
<section class="card">
|
|
363
389
|
<span class="verdict-badge tone-${verdictTone}"><span class="verdict-dot"></span>${escapeHtml(VERDICT_LABEL[verdict])}</span>
|
|
390
|
+
${auditedAsHtml(summary.siteClassification)}
|
|
364
391
|
<span class="verdict-headline">${escapeHtml(summary.headline)}</span>
|
|
365
392
|
<div class="cat-grid">${renderCategoryTiles(summary.categories)}</div>
|
|
366
393
|
</section>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/formatters/html.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/formatters/html.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,4 +6,6 @@ export { formatMarkdown } from "./markdown.js";
|
|
|
6
6
|
export type { MarkdownFormatOptions } from "./markdown.js";
|
|
7
7
|
export { formatHtml } from "./html.js";
|
|
8
8
|
export type { HtmlFormatOptions } from "./html.js";
|
|
9
|
+
export { formatFixplan } from "./fixplan.js";
|
|
10
|
+
export type { FixplanFormatOptions } from "./fixplan.js";
|
|
9
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/formatters/index.js
CHANGED
|
@@ -2,4 +2,5 @@ export { formatConsole, aeoScoreLabel } from "./console.js";
|
|
|
2
2
|
export { formatJson } from "./json.js";
|
|
3
3
|
export { formatMarkdown } from "./markdown.js";
|
|
4
4
|
export { formatHtml } from "./html.js";
|
|
5
|
+
export { formatFixplan } from "./fixplan.js";
|
|
5
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/formatters/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAQb,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,qBAAqB;IACpC,oIAAoI;IACpI,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAuBD,iBAAS,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAOnD;AA0ID,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,MAAM,CA0ER;AAGD,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bucketByTemplate } from "./bucket-findings.js";
|
|
1
2
|
const VERDICT_GLYPH = {
|
|
2
3
|
ready: "✅",
|
|
3
4
|
caution: "⚠️",
|
|
@@ -26,10 +27,33 @@ function shortenUrl(url) {
|
|
|
26
27
|
return url;
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
function
|
|
30
|
-
const url =
|
|
30
|
+
function bucketDocsLink(b) {
|
|
31
|
+
const url = b.representativeDocsUrl ??
|
|
32
|
+
`https://pseolint.dev/rules/${b.ruleId.split("/").pop() ?? b.ruleId}`;
|
|
31
33
|
return `[docs](${url})`;
|
|
32
34
|
}
|
|
35
|
+
function effortPrefix(effort) {
|
|
36
|
+
return effort ? `[${effort}] ` : "";
|
|
37
|
+
}
|
|
38
|
+
/** v0.4.3 — caveat suffix for low-confidence findings, rendered inline. */
|
|
39
|
+
function confidenceCaveat(c) {
|
|
40
|
+
if (c === "low")
|
|
41
|
+
return "low confidence — known false-positive risk on this site type";
|
|
42
|
+
if (c === "speculative")
|
|
43
|
+
return "speculative — heuristic match; verify before acting";
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/** v0.4.3 — "Audited as <type>" line shown under the verdict header. */
|
|
47
|
+
function auditedAsLine(c) {
|
|
48
|
+
if (!c)
|
|
49
|
+
return null;
|
|
50
|
+
const confPct = Math.round(c.confidence * 100);
|
|
51
|
+
const suppressed = c.suppressedRules.length;
|
|
52
|
+
const suppressedPart = suppressed > 0
|
|
53
|
+
? ` ${suppressed} pSEO-only rule${suppressed === 1 ? "" : "s"} suppressed.`
|
|
54
|
+
: "";
|
|
55
|
+
return `_Audited as **${c.type}** (${confPct}% confidence).${suppressedPart}_`;
|
|
56
|
+
}
|
|
33
57
|
function renderTriageMarkdown(triage) {
|
|
34
58
|
const lines = ["", "## AI Triage", ""];
|
|
35
59
|
const cost = triage.estimatedCostUsd !== undefined ? `, est $${triage.estimatedCostUsd.toFixed(2)}` : "";
|
|
@@ -55,17 +79,58 @@ function renderTriageMarkdown(triage) {
|
|
|
55
79
|
}
|
|
56
80
|
return lines.join("\n");
|
|
57
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Render a severity bucket. Findings are first collapsed by template
|
|
84
|
+
* signature so a single template bug surfaces once with a "Fix once,
|
|
85
|
+
* resolve all N" callout instead of N near-identical lines.
|
|
86
|
+
*
|
|
87
|
+
* Single-instance findings keep the legacy bullet format (no `### header`)
|
|
88
|
+
* so simple, low-volume reports still read like a flat list.
|
|
89
|
+
*/
|
|
58
90
|
function renderBucket(label, items) {
|
|
59
91
|
const lines = [];
|
|
60
92
|
if (items.length === 0)
|
|
61
93
|
return lines;
|
|
62
94
|
lines.push(`## ${label} (${items.length})`);
|
|
63
|
-
for (const f of items) {
|
|
64
|
-
const target = f.pageUrl ? ` — ${f.pageUrl}` : "";
|
|
65
|
-
const message = f.fix ?? f.message;
|
|
66
|
-
lines.push(`- **\`${f.ruleId}\`**${target} — ${message} ${docsLink(f)}`);
|
|
67
|
-
}
|
|
68
95
|
lines.push("");
|
|
96
|
+
const buckets = bucketByTemplate(items);
|
|
97
|
+
for (const b of buckets) {
|
|
98
|
+
const caveat = confidenceCaveat(b.representativeConfidence);
|
|
99
|
+
if (b.count === 1) {
|
|
100
|
+
const target = b.representativeUrl !== "<site-wide>" ? ` — ${b.representativeUrl}` : "";
|
|
101
|
+
const message = b.representativeFix ?? b.representativeMessage;
|
|
102
|
+
const eff = effortPrefix(b.effort);
|
|
103
|
+
lines.push(`- **\`${b.ruleId}\`**${target} — ${eff}${message} ${bucketDocsLink(b)}`);
|
|
104
|
+
if (caveat)
|
|
105
|
+
lines.push(` - _${caveat}_`);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
// Multi-instance bucket: dedicated header + body block.
|
|
109
|
+
const isTemplateBucket = b.templateSignature !== null;
|
|
110
|
+
const eff = effortPrefix(b.effort);
|
|
111
|
+
const countLabel = isTemplateBucket
|
|
112
|
+
? `× ${b.count} instances on \`${b.templateSignature}\` template`
|
|
113
|
+
: `× ${b.count} affected pages`;
|
|
114
|
+
lines.push(`### ${eff}\`${b.ruleId}\` ${countLabel}`);
|
|
115
|
+
lines.push("");
|
|
116
|
+
const moreSuffix = isTemplateBucket
|
|
117
|
+
? ` — and ${b.count - 1} more page${b.count - 1 === 1 ? "" : "s"} match${b.count - 1 === 1 ? "es" : ""} this template.`
|
|
118
|
+
: ` — affecting ${b.count} pages total.`;
|
|
119
|
+
lines.push(`\`${b.representativeUrl}\` ${b.representativeMessage}${moreSuffix}`);
|
|
120
|
+
lines.push("");
|
|
121
|
+
if (caveat) {
|
|
122
|
+
lines.push(`> _${caveat}_`);
|
|
123
|
+
lines.push("");
|
|
124
|
+
}
|
|
125
|
+
if (b.representativeFix) {
|
|
126
|
+
const fixOnce = isTemplateBucket ? ` Fix once, resolve all ${b.count}.` : "";
|
|
127
|
+
lines.push(`**Fix:** ${b.representativeFix}${fixOnce} ${bucketDocsLink(b)}`);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
lines.push(bucketDocsLink(b));
|
|
131
|
+
}
|
|
132
|
+
lines.push("");
|
|
133
|
+
}
|
|
69
134
|
return lines;
|
|
70
135
|
}
|
|
71
136
|
function categoryRows(categories) {
|
|
@@ -89,6 +154,11 @@ export function formatMarkdown(summary, _options) {
|
|
|
89
154
|
lines.push(`# pseolint report`);
|
|
90
155
|
lines.push("");
|
|
91
156
|
lines.push(`**Verdict:** ${VERDICT_GLYPH[summary.verdict]} ${VERDICT_LABEL[summary.verdict]}`);
|
|
157
|
+
// v0.4.3 — show "Audited as <type>" right under the verdict so the
|
|
158
|
+
// operator knows which scoring profile produced the verdict.
|
|
159
|
+
const audited = auditedAsLine(summary.siteClassification);
|
|
160
|
+
if (audited)
|
|
161
|
+
lines.push(audited);
|
|
92
162
|
lines.push(`**Risk:** ${summary.risk} / 100 (lower is better)`);
|
|
93
163
|
lines.push("");
|
|
94
164
|
lines.push(`**Headline:** ${summary.headline}`);
|
|
@@ -110,10 +180,28 @@ export function formatMarkdown(summary, _options) {
|
|
|
110
180
|
lines.push(`_Crawl: ${crawl.fetched} fetched · ${crawl.discovered} discovered · ${crawl.skipped} skipped._`);
|
|
111
181
|
lines.push("");
|
|
112
182
|
}
|
|
113
|
-
// Issue buckets
|
|
183
|
+
// Issue buckets — blockers and should-fix render inline because they're
|
|
184
|
+
// the actionable items. Informational findings collapse behind a
|
|
185
|
+
// <details> on by default — they're often high-volume on catalog and
|
|
186
|
+
// template-driven sites (118 info findings on Webflow's templates
|
|
187
|
+
// gallery, 134 on Ramp's spend-management directory) where surfacing
|
|
188
|
+
// every entry as a fresh markdown bullet drowns the actionable signal.
|
|
189
|
+
// The user can expand the block to see all entries, or run with
|
|
190
|
+
// `--explain` (console) for the full dump.
|
|
114
191
|
lines.push(...renderBucket("Blockers", summary.issues.blockers));
|
|
115
192
|
lines.push(...renderBucket("Should fix", summary.issues.shouldFix));
|
|
116
|
-
|
|
193
|
+
if (summary.issues.informational.length > 0) {
|
|
194
|
+
const infoLines = renderBucket("Informational", summary.issues.informational);
|
|
195
|
+
lines.push(`<details>`);
|
|
196
|
+
lines.push(`<summary><strong>Informational (${summary.issues.informational.length})</strong> — low-confidence or context-dependent findings. Click to expand.</summary>`);
|
|
197
|
+
lines.push("");
|
|
198
|
+
// Strip the duplicate ## header that renderBucket added; the <summary>
|
|
199
|
+
// already labels the section.
|
|
200
|
+
lines.push(...infoLines.slice(2));
|
|
201
|
+
lines.push("");
|
|
202
|
+
lines.push(`</details>`);
|
|
203
|
+
lines.push("");
|
|
204
|
+
}
|
|
117
205
|
// AI Triage (if present)
|
|
118
206
|
if (summary.triage) {
|
|
119
207
|
lines.push(renderTriageMarkdown(summary.triage));
|