Skip to content

feat: visual HTML report (--reporter html) - #47

Merged
oekazuma merged 15 commits into
mainfrom
feat/html-report
Jun 23, 2026
Merged

oekazuma merged 15 commits into
mainfrom
feat/html-report

Conversation

@oekazuma

@oekazuma oekazuma commented Jun 23, 2026 •

Copy link
Copy Markdown
Owner

Add a visual HTML report — the "Lighthouse-like visualization" pillar of the 1.0 thesis. svelte-vitals --reporter html writes a single, self-contained, styled HTML page (Health gauge, per-category and per-route scores, findings with fixes) you open in a browser.

This is sub-project A: the shared renderer + the CLI reporter. A future vite live-UI mode (sub-project B, vitest --ui-style) will reuse the same renderer — designed in, not built here.

What's in it

  • Core renderer (@svelte-vitals/core, packages/core/src/reporter/html.ts) — buildHtmlDocument(report, meta) / formatHtmlReport(results, config, meta) turn the existing JsonReport into a full self-contained HTML string. Server-side templating: data is rendered into the markup, with inline <style> and inline <script> for styling and light interactivity. Pure string function — no node: imports, no I/O, deterministic output.
  • CLI (svelte-vitals --reporter html) — writes svelte-vitals-report.html by default; --out-file <path> to change it; --out-file - to stream to stdout. Prints wrote report to <path> to stderr. The file write is the CLI's job (node:fs); core never touches the filesystem. Exit codes unchanged (HTML is output, not a gate).
  • The report shows a Health gauge (animated on load, respects prefers-reduced-motion), severity tallies, per-category score bars with weights, a route list (native <details>, expandable), and finding cards with the rule id, severity, location, recommendation, fix snippet, and a docs link. Filter chips (severity/category) work client-side.

Design choices

  • Self-contained: inline CSS/JS, no CDN/fonts/remote anything. The only external links are per-finding docsUrl anchors. A guard test enforces this.
  • No new dependencies — no syntax highlighter, chart lib, or framework. Fix snippets render as plain (uncolored) monospace in v1.
  • Brand vs. semantics: Svelte orange #FF3E00 is brand chrome only (wordmark, ↯, links); the red/amber/green score bands are a separate functional scale.
  • Escaping: all project/rule-derived strings are HTML-escaped.

Out of scope (follow-ups)

The vite live-UI mode (sub-project B), syntax highlighting, dark mode, and a per-route sort toggle (routes already arrive sorted by path) — all deferred.

Release

@svelte-vitals/core + svelte-vitals minor changeset. @svelte-vitals/vite / @svelte-vitals/mcp cascade a patch via workspace:*.

Validation

  • pnpm -r typecheck, pnpm -r test (core 11/11 new + full suite), pnpm build, pnpm --filter docs build (39 pages), pnpm lint, publint — all green.
  • attw fails locally only (sandbox npm pack) — known pre-existing, CI-unaffected.

Process

Built subagent-driven: 5 tasks (each spec + quality reviewed) + a whole-branch review on Opus (verdict: ready to merge). Docs guides (Reporters + CLI, en + ja) updated.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added --reporter html to generate a self-contained styled HTML report with health score, per-category/route breakdowns, and findings (including suggested fixes).
    • Introduced --out-file <path> to choose where the HTML is written (use - to print to stdout).
    • Improved reporter selection via explicit flag, environment override, and auto-detection (with guidance when auto-selected).
  • Documentation

    • Updated CLI and reporters documentation (English + Japanese) to include the new HTML reporter and output options.
  • Tests

    • Added unit and CLI tests for HTML rendering and safety/escaping behavior.

oekazuma and others added 11 commits June 23, 2026 17:20
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds escapeHtml, scoreBand, BAND_COLOR, buildHtmlDocument, and
formatHtmlReport to packages/core. The renderer is pure string
building — no node: imports, no I/O, no external resources.
STYLE/SCRIPT placeholders are empty strings pending Tasks 2–3.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fills the STYLE constant with the approved instrument-report design CSS,
targeting all classes emitted in Task 1. Adds styling test to verify
CSS presence and self-containment (no external resource references).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Fill SCRIPT constant with gauge animation (respecting prefers-reduced-motion) and filter logic
- Gauge animates on page load with cubic-bezier easing over 1.1s
- Finding cards filter by severity/category via chip interaction
- Wire test assertions for interactivity behavior

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wires the HTML reporter into the CLI: adds 'html' to ReporterName/isReporterName, parses --out-file in resolve-args, adds outFile/writeFile to RunOptions, dispatches to formatHtmlReport in run(), and updates HELP + mri string options in bin.ts. Also fixes a TypeScript strict-null error in packages/core/src/reporter/html.ts (location/recommendation are optional).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mport

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 23, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@oekazuma, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 50 minutes and 9 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses rolling per-developer review limits. Reviews become available again as older review attempts age out of the rolling limit window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fe2a850a-4918-4067-9040-bfa2c67ac50f

📥 Commits

Reviewing files that changed from the base of the PR and between 9f98ead and fadded6.

📒 Files selected for processing (1)
  • packages/core/test/html-report.test.ts
📝 Walkthrough

Walkthrough

Adds an html reporter to svelte-vitals (--reporter html). A new packages/core/src/reporter/html.ts converts a JsonReport into a self-contained HTML document with inlined CSS and JS. The CLI is extended with --out-file to control the output destination (default svelte-vitals-report.html, or - for stdout). Tests and English/Japanese documentation are updated accordingly.

Changes

HTML Reporter Feature

Layer / File(s) Summary
Core HTML renderer
packages/core/src/reporter/html.ts
Adds severity band helpers (BAND_COLOR, scoreBand), escapeHtml, safeHref, HTML fragment builders for findings/topbar/hero/routes/site-checks/filter-chips, embedded STYLE (inline CSS) and SCRIPT (inline JS with gauge animation and finding filtering) constants, and exported buildHtmlDocument/formatHtmlReport.
Core public API
packages/core/src/index.ts
Re-exports buildHtmlDocument, formatHtmlReport, escapeHtml, safeHref, scoreBand, and BAND_COLOR from the new html reporter module.
CLI wiring
packages/cli/src/reporter-resolve.ts, packages/cli/src/resolve-args.ts, packages/cli/src/bin.ts, packages/cli/src/index.ts
Adds isAgentEnv, isGithubActionsEnv, resolveReporter, and auto-detection predicates to reporter-resolve; parses --out-file in bin and resolve-args; adds outFile/writeFile to RunOptions; dispatches html reporter via formatHtmlReport writing to file or stdout.
Core tests
packages/core/test/html-report.test.ts
Tests cover document structure, HTML escaping of attacker-controlled content, self-contained output (no external http(s) refs except per-finding docsUrl), inline CSS/JS presence, escapeHtml and scoreBand unit tests, security hardening (unsafe URL schemes, category key escaping), and category filter rendering.
CLI tests
packages/cli/test/html-reporter.test.ts
Tests cover isReporterName acceptance, default output path behavior (svelte-vitals-report.html), custom --out-file paths, stdout output via '-', empty-string fallback, and nested directory creation.
Docs, changeset, design artifacts
docs/src/content/docs/guides/cli.md, docs/src/content/docs/guides/reporters.md, docs/src/content/docs/ja/guides/..., docs/superpowers/specs/..., docs/superpowers/plans/..., .changeset/visual-html-report.md, .gitignore
Updates English and Japanese CLI/reporters guides for --reporter html and --out-file; adds minor-version changeset; adds design spec and implementation plan; ignores .superpowers/ scratch directory.

Sequence Diagram(s)

sequenceDiagram
  participant User as User (CLI)
  participant bin as bin.ts (mri)
  participant resolveArgs as resolve-args.ts
  participant run as index.ts run()
  participant formatHtmlReport as formatHtmlReport (core)
  participant fs as writeFileSync / stdout

  User->>bin: svelte-vitals --reporter html --out-file report.html
  bin->>resolveArgs: argv with reporter, out-file
  resolveArgs-->>bin: RunOptions { reporter: 'html', outFile: 'report.html' }
  bin->>run: RunOptions
  run->>formatHtmlReport: results, config, { version }
  formatHtmlReport-->>run: HTML string
  alt outFile === '-'
    run->>fs: log(html) to stdout
  else outFile provided or default
    run->>fs: writeFileSync(outFile, html)
    run->>fs: errorLog("Report written to outFile")
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • oekazuma/svelte-vitals#22: Modifies the same reporter-resolve.ts and CLI reporter dispatch machinery that this PR extends, adding sarif/github reporters and GitHub Actions auto-detection which this PR builds upon.
  • oekazuma/svelte-vitals#36: Extended the JsonReport shape to include issue category, line, and top-level categories data that the new HTML renderer consumes for per-category scoring and line-aware findings.

Poem

🐇 Hop, hop — the rabbit taps away,
HTML blooms from a JsonReport today!
Inline CSS, a gauge that glows,
--out-file - for wherever stdout goes.
Six reporters now, the warren grows! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: visual HTML report (--reporter html)' accurately summarizes the main change—introducing a new HTML reporter feature to the CLI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/html-report

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@oekazuma oekazuma self-assigned this Jun 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/core/test/html-report.test.ts (1)

108-120: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace as never with a properly typed Config object.

The as never cast at line 114 completely bypasses TypeScript's type checking. If the Config type evolves, this test won't catch breaking changes. Consider creating a minimal valid Config fixture or using a builder function instead.

♻️ Suggested approach
 describe('formatHtmlReport', () => {
   it('matches buildHtmlDocument over the built JsonReport (smoke)', () => {
     // formatHtmlReport builds the JsonReport internally; here we only assert it returns a full doc.
     // A fuller integration check lives in the CLI tests.
+    const minimalConfig: Config = {
+      treatDynamicAs: 'pass',
+      metaComponents: [],
+      rules: {},
+      failOn: 'critical'
+    } as Config;
     const out = formatHtmlReport(
       [],
-      { treatDynamicAs: 'pass', metaComponents: [], rules: {}, failOn: 'critical' } as never,
+      minimalConfig,
       { version: '9.9.9' }
     );

Alternatively, if Config requires many fields, create a buildTestConfig() helper in a test utilities module.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/test/html-report.test.ts` around lines 108 - 120, The `as
never` type cast in the call to formatHtmlReport bypasses TypeScript's type
checking, which means changes to the Config interface won't be caught by this
test. Replace the `as never` cast with a properly typed Config object by either
providing all required Config fields in the object literal passed to
formatHtmlReport, or create a test utility helper function (such as
buildTestConfig) that constructs a minimal valid Config fixture and use that
instead of the cast.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/reporter/html.ts`:
- Around line 84-85: The `name` variable at line 84 in the buildHtmlDocument
function is being inserted directly into HTML without escaping, creating an XSS
vulnerability if untrusted JsonReport data is provided. Escape the `name`
variable using an appropriate HTML escaping function (such as a utility that
converts special HTML characters like <, >, &, ", ' to their entity equivalents)
before inserting it into the HTML string template where it appears in the span
with class "name".
- Line 44: The code on line 44 in the `docs` variable assignment uses escapeHtml
to escape HTML metacharacters in the `docsUrl`, but this does not prevent
malicious URLs with `javascript:` scheme from executing. Add URL scheme
validation before rendering the link to ensure only safe schemes like `https:`
and `http:` are allowed. Modify the condition that checks `issue.docsUrl` to
also validate that the URL has a safe protocol scheme before constructing the
anchor element with the docsUrl in the href attribute.

---

Nitpick comments:
In `@packages/core/test/html-report.test.ts`:
- Around line 108-120: The `as never` type cast in the call to formatHtmlReport
bypasses TypeScript's type checking, which means changes to the Config interface
won't be caught by this test. Replace the `as never` cast with a properly typed
Config object by either providing all required Config fields in the object
literal passed to formatHtmlReport, or create a test utility helper function
(such as buildTestConfig) that constructs a minimal valid Config fixture and use
that instead of the cast.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4509dd8b-b91e-4e77-bd3c-1437c763e7c5

📥 Commits

Reviewing files that changed from the base of the PR and between ceb5691 and 26d6efe.

📒 Files selected for processing (16)
  • .changeset/visual-html-report.md
  • .gitignore
  • docs/src/content/docs/guides/cli.md
  • docs/src/content/docs/guides/reporters.md
  • docs/src/content/docs/ja/guides/cli.md
  • docs/src/content/docs/ja/guides/reporters.md
  • docs/superpowers/plans/2026-06-23-visual-html-report.md
  • docs/superpowers/specs/2026-06-23-visual-html-report-design.md
  • packages/cli/src/bin.ts
  • packages/cli/src/index.ts
  • packages/cli/src/reporter-resolve.ts
  • packages/cli/src/resolve-args.ts
  • packages/cli/test/html-reporter.test.ts
  • packages/core/src/index.ts
  • packages/core/src/reporter/html.ts
  • packages/core/test/html-report.test.ts

Comment thread packages/core/src/reporter/html.ts Outdated
Comment thread packages/core/src/reporter/html.ts Outdated
…gory XSS

Address CodeRabbit review on PR #47 — buildHtmlDocument is a public API and
JsonReport is loosely typed (docsUrl?: string, categories: Record<string,...>):

- safeHref(): render a finding's docsUrl link only when it cleanly resolves to
  http(s) after stripping whitespace (browsers strip tab/newline before scheme
  resolution), so javascript:/data: hrefs are dropped. escapeHtml guards
  attribute breakout but not the scheme.
- Escape the category label before inserting it into the hero markup.
- Tests for both, plus safeHref unit cases; replace test's 'as never' scoreModel
  casts with a properly typed ScoreModel helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new self-contained HTML reporter to svelte-vitals, backed by a runtime-agnostic HTML renderer in @svelte-vitals/core, plus tests, docs, and a release changeset.

Changes:

  • Implement @svelte-vitals/core HTML renderer (buildHtmlDocument / formatHtmlReport) with inline CSS/JS.
  • Wire svelte-vitals --reporter html with --out-file <path> (including - for stdout) and add CLI tests.
  • Document the new reporter/flags (EN/JA) and add a changeset.

Reviewed changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/core/src/reporter/html.ts New pure string renderer that builds a full HTML report (markup + inline CSS/JS).
packages/core/src/index.ts Exports the new HTML report APIs from @svelte-vitals/core.
packages/core/test/html-report.test.ts Adds core-level tests for HTML rendering, self-contained guard, and safety helpers.
packages/cli/src/index.ts Adds html reporter branch that writes the report (or prints to stdout when --out-file -).
packages/cli/src/reporter-resolve.ts Extends reporter name union + validation to include html.
packages/cli/src/resolve-args.ts Parses --out-file and updates reporter validation error message.
packages/cli/src/bin.ts Updates CLI help and mri option parsing to include --out-file and html.
packages/cli/test/html-reporter.test.ts Adds CLI tests covering default output file, custom output path, and stdout mode.
docs/src/content/docs/guides/reporters.md Documents the new HTML reporter (EN).
docs/src/content/docs/guides/cli.md Documents html reporter and --out-file flag (EN).
docs/src/content/docs/ja/guides/reporters.md Documents the new HTML reporter (JA).
docs/src/content/docs/ja/guides/cli.md Documents html reporter and --out-file flag (JA).
docs/superpowers/specs/2026-06-23-visual-html-report-design.md Adds the design spec for the visual HTML report.
docs/superpowers/plans/2026-06-23-visual-html-report.md Adds the implementation plan and verification checklist.
.changeset/visual-html-report.md Declares minor releases for @svelte-vitals/core and svelte-vitals.
.gitignore Adjusts ignore entry for .superpowers/ scratch directory.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/reporter/html.ts Outdated
Comment thread packages/core/src/reporter/html.ts Outdated
Comment thread packages/core/src/reporter/html.ts
Comment thread packages/core/test/html-report.test.ts Outdated
Comment thread packages/core/test/html-report.test.ts Outdated
Comment thread packages/core/test/html-report.test.ts Outdated
oekazuma and others added 2 commits June 23, 2026 18:57
…uard

Address Copilot review on PR #47:
- Clamp issue.severity to the known set (critical/warning/info) before it flows
  into class/data attributes — buildHtmlDocument is public, input may be malformed.
- Make the footer text non-clickable so the report's only external links are the
  per-finding docsUrl anchors (matches the stated self-contained constraint).
- Narrow the self-contained guard regex to the per-finding docsUrl rules pattern
  so any other external href still trips the assertion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Derive category filter chips from report.categories (was hardcoded
  SEO/Performance) so they stay in sync with the hero bars; filter by an
  explicit data-filter value instead of chip label text.
- CLI: mkdir -p the parent dir before writing the HTML report, and fall
  back to the default path when --out-file is an empty string.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/core/test/html-report.test.ts (2)

152-178: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider verifying selective filtering of unsafe docsUrl.

The test verifies that an unsafe javascript: docsUrl is dropped, but doesn't verify that a safe docsUrl in another finding would still be rendered. Adding a second finding with a valid https:// docsUrl would confirm the filtering is selective rather than blanket, catching potential regressions where all docsUrl values are accidentally dropped.

📋 Example mixed safe/unsafe test structure
       issues: [
         {
           id: 'SEO001',
           category: 'seo',
           title: 't',
           detection: { presence: 'none', value: 'absent' },
           location: 'f.svelte',
           recommendation: 'r',
           docsUrl: 'javascript:alert(1)',
           severity: 'critical'
-        }
+        },
+        {
+          id: 'SEO002',
+          category: 'seo',
+          title: 'safe finding',
+          detection: { presence: 'present', value: 'static' },
+          location: 'g.svelte',
+          recommendation: 'check docs',
+          docsUrl: 'https://example.com/docs',
+          severity: 'warning'
+        }
       ]
     }
   ],
   siteIssues: []
 };
 const html = buildHtmlDocument(evil, { version: '0' });
 expect(html).not.toContain('javascript:alert(1)');
 expect(html).not.toContain('href="javascript:');
+expect(html).toContain('href="https://example.com/docs"'); // safe link still rendered
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/test/html-report.test.ts` around lines 152 - 178, The test for
unsafe docsUrl filtering only verifies that the dangerous javascript: URL is
removed, but it does not verify that safe docsUrl values are still rendered,
making it impossible to detect if the filtering is selective or if all docsUrl
values are being blanket dropped. Add a second finding with a valid https://
docsUrl to the issues array in the evil JsonReport object, then add a positive
assertion to verify that this safe URL is present in the generated HTML,
ensuring the filtering is selective rather than blanket.

92-93: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider making the docsUrl domain assumption more robust.

The regex hardcodes oekazuma\.github\.io\/svelte-vitals\/rules/ to strip docsUrl anchors. While this matches the current implementation, it creates test brittleness: if a future docsUrl points to a different domain (e.g., a CDN or documentation host migration), the test will fail even though the behavior is correct.

Consider either:

  1. Documenting the assumption that all docsUrl values must start with this specific base URL, or
  2. Deriving the pattern from the actual docsUrl values in the test fixture to make the coupling explicit.

Also applies to: 133-134, 145-146

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/test/html-report.test.ts` around lines 92 - 93, The test uses a
hardcoded regex pattern to strip docsUrl anchors at lines 92-93 (and similarly
at 133-134 and 145-146), which assumes the domain will always be
oekazuma.github.io/svelte-vitals/rules/. To make this more robust, extract the
actual docsUrl base from the test fixture data and dynamically construct the
regex pattern from that value instead of hardcoding the domain. This way, if the
docsUrl domain changes in the future, the test will automatically adapt to the
new domain without requiring manual regex updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/test/html-report.test.ts`:
- Around line 193-199: The test for safeHref function is missing coverage for
important security behaviors: whitespace-stripping and case-insensitive scheme
validation. Add three additional expect statements to the safeHref test case to
verify these security-critical features: test that safeHref rejects schemes with
embedded whitespace like 'java\tscript:alert(1)' returning null, rejects
uppercase dangerous schemes like 'JavaScript:alert(1)' returning null, and
accepts valid https schemes even when uppercase like 'HTTPS://example.com'.
These test cases ensure the documented attack-surface reduction behaviors are
verified and protected against regression.

---

Nitpick comments:
In `@packages/core/test/html-report.test.ts`:
- Around line 152-178: The test for unsafe docsUrl filtering only verifies that
the dangerous javascript: URL is removed, but it does not verify that safe
docsUrl values are still rendered, making it impossible to detect if the
filtering is selective or if all docsUrl values are being blanket dropped. Add a
second finding with a valid https:// docsUrl to the issues array in the evil
JsonReport object, then add a positive assertion to verify that this safe URL is
present in the generated HTML, ensuring the filtering is selective rather than
blanket.
- Around line 92-93: The test uses a hardcoded regex pattern to strip docsUrl
anchors at lines 92-93 (and similarly at 133-134 and 145-146), which assumes the
domain will always be oekazuma.github.io/svelte-vitals/rules/. To make this more
robust, extract the actual docsUrl base from the test fixture data and
dynamically construct the regex pattern from that value instead of hardcoding
the domain. This way, if the docsUrl domain changes in the future, the test will
automatically adapt to the new domain without requiring manual regex updates.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 671cda5d-165d-4fa6-9fb8-4e53e31b4255

📥 Commits

Reviewing files that changed from the base of the PR and between 26d6efe and 9f98ead.

📒 Files selected for processing (5)
  • packages/cli/src/index.ts
  • packages/cli/test/html-reporter.test.ts
  • packages/core/src/index.ts
  • packages/core/src/reporter/html.ts
  • packages/core/test/html-report.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/core/src/index.ts
  • packages/cli/test/html-reporter.test.ts
  • packages/cli/src/index.ts
  • packages/core/src/reporter/html.ts

Comment thread packages/core/test/html-report.test.ts
Per CodeRabbit review on PR #47: assert the security-critical behaviors
(java\tscript:/java\nscript: and JavaScript: rejected; uppercase HTTPS:// accepted)
so the documented attack-surface reduction can't regress.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants