From f5c281cfde360ee4b914b46fb80bb09d793a1d48 Mon Sep 17 00:00:00 2001 From: LyraZeta <123644337+LyraZeta@users.noreply.github.com> Date: Thu, 13 Aug 2026 14:20:56 +0800 Subject: [PATCH] feat: add pull request finding comparison --- .github/ISSUE_TEMPLATE/bug.yml | 2 +- .github/workflows/action-smoke.yml | 42 +++ .github/workflows/release-smoke.yml | 4 +- CHANGELOG.md | 18 ++ README.md | 66 +++- action.yml | 6 + dist/cli.js | 82 ++++- dist/cli.js.map | 2 +- dist/compare.d.ts | 13 + dist/compare.d.ts.map | 1 + dist/compare.js | 309 +++++++++++++++++++ dist/compare.js.map | 1 + dist/report.d.ts.map | 2 +- dist/report.js | 42 ++- dist/report.js.map | 2 +- dist/sarif.d.ts | 3 +- dist/sarif.d.ts.map | 2 +- dist/sarif.js | 8 + dist/sarif.js.map | 2 +- dist/scanner.js | 4 +- dist/types.d.ts | 19 ++ dist/types.d.ts.map | 2 +- dist/types.js.map | 2 +- docs/recipes.md | 85 ++++- package.json | 2 +- src/cli.ts | 103 ++++++- src/compare.ts | 461 ++++++++++++++++++++++++++++ src/report.ts | 44 ++- src/sarif.ts | 17 +- src/scanner.ts | 4 +- src/types.ts | 21 ++ test/cli-compare.test.ts | 251 +++++++++++++++ test/compare.test.ts | 239 ++++++++++++++ test/report.test.ts | 32 +- 34 files changed, 1819 insertions(+), 74 deletions(-) create mode 100644 dist/compare.d.ts create mode 100644 dist/compare.d.ts.map create mode 100644 dist/compare.js create mode 100644 dist/compare.js.map create mode 100644 src/compare.ts create mode 100644 test/cli-compare.test.ts create mode 100644 test/compare.test.ts diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 87e38b3..bf51abd 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -25,7 +25,7 @@ body: id: version attributes: label: LayoutScope version - placeholder: 0.3.0 + placeholder: 0.4.0 validations: required: true - type: dropdown diff --git a/.github/workflows/action-smoke.yml b/.github/workflows/action-smoke.yml index ab4d58e..a32df29 100644 --- a/.github/workflows/action-smoke.yml +++ b/.github/workflows/action-smoke.yml @@ -50,6 +50,38 @@ jobs: if (report.options.paths?.length !== 1 || report.options.paths[0] !== "/") process.exit(1); if (report.options.viewports?.length !== 1 || report.options.viewports[0]?.name !== "mobile") process.exit(1); if (report.options.waitMs !== 0) process.exit(1); + if (report.comparison !== undefined) process.exit(1); + NODE + - id: layoutscope-compare + uses: ./layoutscope-action + with: + target: layoutscope-action/demo/broken/index.html + config: layoutscope-action/demo/broken/layoutscope.config.json + compare: ${{ steps.layoutscope.outputs.json-report }} + output: .layoutscope-compare + fail-on: error + artifact-name: layoutscope-compare-report + - name: Verify baseline comparison outputs + env: + BASELINE_REPORT: ${{ steps.layoutscope.outputs.json-report }} + HTML_REPORT: ${{ steps.layoutscope-compare.outputs.html-report }} + JSON_REPORT: ${{ steps.layoutscope-compare.outputs.json-report }} + SARIF_REPORT: ${{ steps.layoutscope-compare.outputs.sarif-report }} + run: | + test "$HTML_REPORT" = "$(realpath -m .layoutscope-compare/report.html)" + test "$JSON_REPORT" = "$(realpath -m .layoutscope-compare/report.json)" + test "$SARIF_REPORT" = "$(realpath -m .layoutscope-compare/report.sarif.json)" + test -s "$HTML_REPORT" && test -s "$JSON_REPORT" && test -s "$SARIF_REPORT" + node --input-type=commonjs <<'NODE' + const report = require(process.env.JSON_REPORT); + if (report.summary.error < 1) process.exit(1); + if (!report.comparison) process.exit(1); + const counts = report.comparison.counts; + if (counts?.new !== 0 || report.comparison.new?.length !== 0) process.exit(1); + if (counts?.resolved !== 0 || report.comparison.resolved?.length !== 0) process.exit(1); + if (counts?.existing !== report.summary.total) process.exit(1); + if (report.comparison.existing?.length !== counts.existing) process.exit(1); + if (report.comparison.baseline?.source !== process.env.BASELINE_REPORT) process.exit(1); NODE - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -61,6 +93,16 @@ jobs: test -s .artifact-download/report.json test -s .artifact-download/report.sarif.json test "$(find .artifact-download/screenshots -type f -name '*.png' | wc -l)" -ge 2 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: layoutscope-compare-report + path: .compare-artifact-download + - name: Verify comparison artifact + run: | + test -s .compare-artifact-download/report.html + test -s .compare-artifact-download/report.json + test -s .compare-artifact-download/report.sarif.json + test "$(find .compare-artifact-download/screenshots -type f -name '*.png' | wc -l)" -ge 2 failure-threshold: runs-on: ubuntu-latest diff --git a/.github/workflows/release-smoke.yml b/.github/workflows/release-smoke.yml index cae8905..849aaec 100644 --- a/.github/workflows/release-smoke.yml +++ b/.github/workflows/release-smoke.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - id: layoutscope - uses: LyraZeta/layoutscope@v0.3.0 + uses: LyraZeta/layoutscope@v0.4.0 with: target: demo/broken/index.html config: demo/broken/layoutscope.config.json @@ -28,6 +28,6 @@ jobs: test -s "$SARIF_REPORT" node --input-type=commonjs <<'NODE' const report = require(process.env.JSON_REPORT); - if (report.tool?.version !== "0.3.0") process.exit(1); + if (report.tool?.version !== "0.4.0") process.exit(1); if (report.summary?.suppressed !== 1 || report.suppressions?.total !== 1) process.exit(1); NODE diff --git a/CHANGELOG.md b/CHANGELOG.md index 663fbbc..7f173a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ All notable changes to LayoutScope are documented here. +## 0.4.0 - 2026-08-13 + +### Added + +- Optional `--compare ` fingerprint comparison for pull-request visual gates without pixel baselines. +- `new`, `existing`, and `resolved` finding groups in JSON, a comparison summary in the interactive HTML report, and comparison metadata in SARIF. +- A matching GitHub Action `compare` input plus a recipe for downloading the latest successful main-branch report. + +### Changed + +- In comparison mode, terminal output and `--fail-on` consider only new findings. The complete current scan remains available in every report for audit and debugging. +- Finding comparison uses route, full viewport identity, rule ID, and fingerprint, with multiset matching for repeated findings. + +### Safety + +- Baseline reports are parsed and structurally validated before config loading, browser launch, or report output. +- Comparison excludes suppression audit samples and never writes resolved baseline findings into the current page results. + ## 0.3.0 - 2026-08-13 ### Added diff --git a/README.md b/README.md index 198a354..177a1a3 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ LayoutScope needs no baseline. It inspects the live DOM, open Shadow DOM, comput Try LayoutScope on a public page without setting up a local project: ```bash -npx --yes github:LyraZeta/layoutscope#v0.3.0 \ +npx --yes github:LyraZeta/layoutscope#v0.4.0 \ 'https://marmelab.com/react-admin-demo/#/login' \ --viewport mobile --wait 1500 --fail-on never ``` @@ -35,20 +35,20 @@ npx --yes github:LyraZeta/layoutscope#v0.3.0 \ Scan your app: ```bash -npx --yes github:LyraZeta/layoutscope#v0.3.0 http://localhost:3000 +npx --yes github:LyraZeta/layoutscope#v0.4.0 http://localhost:3000 ``` Scan a local HTML file: ```bash -npx --yes github:LyraZeta/layoutscope#v0.3.0 ./dist/index.html +npx --yes github:LyraZeta/layoutscope#v0.4.0 ./dist/index.html ``` After your app server is listening in the same GitHub Actions job, run the LayoutScope step against its loopback URL: ```yaml -- uses: LyraZeta/layoutscope@v0.3.0 +- uses: LyraZeta/layoutscope@v0.4.0 with: target: http://127.0.0.1:3000 ``` @@ -66,7 +66,7 @@ For complete copy-paste workflows, see the Use specific routes and viewports: ```bash -npx --yes github:LyraZeta/layoutscope#v0.3.0 http://localhost:3000 \ +npx --yes github:LyraZeta/layoutscope#v0.4.0 http://localhost:3000 \ --path / --path /pricing --path /dashboard \ --viewport desktop --viewport mobile --viewport 768x1024:tablet ``` @@ -83,10 +83,10 @@ screenshots/ Raw and annotated screenshots LayoutScope uses an installed Chrome or Edge automatically when available. Otherwise install the Playwright browser once after cloning: ```bash -npx --yes --package github:LyraZeta/layoutscope#v0.3.0 playwright-core install chromium +npx --yes --package github:LyraZeta/layoutscope#v0.4.0 playwright-core install chromium ``` -The default failure threshold is `error`, so finding a real problem returns a non-zero exit code. Use `--fail-on never` while exploring. +The default failure threshold is `error`, so finding a real problem returns a non-zero exit code. Use `--fail-on never` while exploring. LayoutScope uses exit code `1` for findings at the configured threshold and `2` for configuration, baseline, browser, or scan errors. ## What It Finds @@ -110,21 +110,21 @@ Every rule is deterministic and runs locally. LayoutScope understands modern CSS LayoutScope exits non-zero when an error is found by default: ```bash -npx --yes github:LyraZeta/layoutscope#v0.3.0 http://127.0.0.1:3000 --no-open --fail-on error +npx --yes github:LyraZeta/layoutscope#v0.4.0 http://127.0.0.1:3000 --no-open --fail-on error ``` Choose a threshold: ```bash -npx --yes github:LyraZeta/layoutscope#v0.3.0 ./site --fail-on critical -npx --yes github:LyraZeta/layoutscope#v0.3.0 ./site --fail-on warning -npx --yes github:LyraZeta/layoutscope#v0.3.0 ./site --fail-on never +npx --yes github:LyraZeta/layoutscope#v0.4.0 ./site --fail-on critical +npx --yes github:LyraZeta/layoutscope#v0.4.0 ./site --fail-on warning +npx --yes github:LyraZeta/layoutscope#v0.4.0 ./site --fail-on never ``` Authenticated page: ```bash -npx --yes github:LyraZeta/layoutscope#v0.3.0 https://app.example.com/dashboard \ +npx --yes github:LyraZeta/layoutscope#v0.4.0 https://app.example.com/dashboard \ --storage-state ./playwright/.auth/user.json \ --ready '[data-dashboard-ready]' ``` @@ -132,8 +132,8 @@ npx --yes github:LyraZeta/layoutscope#v0.3.0 https://app.example.com/dashboard \ Manual GitHub Actions steps: ```yaml -- run: npx --yes --package github:LyraZeta/layoutscope#v0.3.0 playwright-core install --with-deps chromium -- run: npx --yes github:LyraZeta/layoutscope#v0.3.0 http://127.0.0.1:3000 --no-open +- run: npx --yes --package github:LyraZeta/layoutscope#v0.4.0 playwright-core install --with-deps chromium +- run: npx --yes github:LyraZeta/layoutscope#v0.4.0 http://127.0.0.1:3000 --no-open - uses: actions/upload-artifact@v7 if: always() with: @@ -143,6 +143,41 @@ Manual GitHub Actions steps: Upload `report.sarif.json` with `github/codeql-action/upload-sarif` to surface findings in Code Scanning. +### Block only new findings + +Adopt LayoutScope without fixing the entire existing backlog first. Save a +normal JSON report from the main branch, then compare the pull request against +that report: + +```bash +# Main branch inventory: detection itself still needs no reference screenshot. +npx --yes github:LyraZeta/layoutscope#v0.4.0 http://127.0.0.1:3000 \ + --output .layoutscope-main --no-open --fail-on never + +# Pull request gate: fail only when a new finding meets the threshold. +npx --yes github:LyraZeta/layoutscope#v0.4.0 http://127.0.0.1:3000 \ + --compare .layoutscope-main/report.json --output .layoutscope-pr --no-open +``` + +Comparison mode matches deterministic findings by route, viewport, rule, and +fingerprint. Terminal output focuses on new findings, while `report.json` +retains the complete current scan plus `new`, `existing`, and `resolved` +groups. The HTML and SARIF reports include the same comparison counts. Use the +same paths, viewports, and config on both runs for a meaningful comparison. + +The Action exposes the same option: + +```yaml +- uses: LyraZeta/layoutscope@v0.4.0 + with: + target: http://127.0.0.1:3000 + compare: .layoutscope-main/report.json +``` + +See the [pull-request baseline recipe](docs/recipes.md#pull-request-baseline-gate) +for a complete workflow that stores the latest successful main-branch report +as a GitHub Actions artifact. + ### Suppress reviewed findings Create `layoutscope.config.ts`, `.js`, or `.json` when a deterministic finding @@ -196,6 +231,7 @@ layoutscope [options] -c, --config Config file; auto-detects layoutscope.config.* --no-auto-config Disable automatic config discovery + --compare Compare findings with an earlier JSON report -o, --output Report directory (default: .layoutscope) -v, --viewport desktop, mobile, tablet, wide, or WIDTHxHEIGHT -p, --path Route to scan; repeatable @@ -249,7 +285,7 @@ The demo intentionally contains responsive overflow, clipped content, a collisio ## Roadmap -- GitHub Action PR summaries and SARIF upload examples +- Native GitHub pull-request summaries and annotations - Inline suppression comments for fixture-heavy projects - Multi-page discovery from a sitemap - Fixed/sticky occlusion and focus-ring clipping rules diff --git a/action.yml b/action.yml index b7eab05..8bcb55c 100644 --- a/action.yml +++ b/action.yml @@ -56,6 +56,10 @@ inputs: description: "CI threshold. Omit to use the config or CLI default." required: false default: "" + compare: + description: Existing LayoutScope report.json to compare against. Omit to report all current findings. + required: false + default: "" upload-artifact: description: Upload the report as a workflow artifact. required: false @@ -103,6 +107,7 @@ runs: INPUT_MAX_FINDINGS: ${{ inputs['max-findings'] }} INPUT_INCLUDE_INFO: ${{ inputs['include-info'] }} INPUT_FAIL_ON: ${{ inputs['fail-on'] }} + INPUT_COMPARE: ${{ inputs.compare }} run: | set -euo pipefail args=("$INPUT_TARGET" --output "$INPUT_OUTPUT" --no-open --no-auto-config) @@ -122,6 +127,7 @@ runs: [[ -n "$INPUT_EXECUTABLE_PATH" ]] && args+=(--executable-path "$INPUT_EXECUTABLE_PATH") [[ -n "$INPUT_MAX_FINDINGS" ]] && args+=(--max-findings "$INPUT_MAX_FINDINGS") [[ -n "$INPUT_FAIL_ON" ]] && args+=(--fail-on "$INPUT_FAIL_ON") + [[ -n "$INPUT_COMPARE" ]] && args+=(--compare "$INPUT_COMPARE") [[ "$INPUT_INCLUDE_INFO" == "true" ]] && args+=(--include-info) node "$GITHUB_ACTION_PATH/dist/cli.js" "${args[@]}" - name: Expose report paths diff --git a/dist/cli.js b/dist/cli.js index f81edf6..9f5cdae 100644 --- a/dist/cli.js +++ b/dist/cli.js @@ -5,9 +5,10 @@ import path from "node:path"; import { promisify } from "node:util"; import chalk from "chalk"; import { Command, Option } from "commander"; +import { compareReports, loadBaselineReport } from "./compare.js"; import { loadLayoutScopeConfig } from "./config.js"; import { scan } from "./scanner.js"; -import { SEVERITY_RANK } from "./types.js"; +import { SEVERITY_RANK, } from "./types.js"; import { DEFAULT_VIEWPORTS, parseViewportList } from "./utils.js"; const execFileAsync = promisify(execFile); function collect(value, previous) { @@ -31,6 +32,29 @@ function severityColor(severity, text) { return chalk.yellow.bold(text); return chalk.blue(text); } +function countFindings(findings) { + const counts = { + critical: 0, + error: 0, + warning: 0, + info: 0, + }; + for (const finding of findings) + counts[finding.severity] += 1; + return counts; +} +function findingsForPage(findings, page) { + return findings.filter((finding) => finding.pageUrl === page.pageUrl && + finding.pagePath === page.pagePath && + finding.viewport.name === page.viewport.name && + finding.viewport.width === page.viewport.width && + finding.viewport.height === page.viewport.height && + (finding.viewport.deviceScaleFactor ?? 1) === + (page.viewport.deviceScaleFactor ?? 1) && + (finding.viewport.isMobile ?? false) === + (page.viewport.isMobile ?? false) && + (finding.viewport.hasTouch ?? false) === (page.viewport.hasTouch ?? false)); +} function printReport(report, artifactPaths) { printBanner(); const score = report.summary.score; @@ -41,6 +65,12 @@ function printReport(report, artifactPaths) { : chalk.red.bold(`${score}/100`); process.stdout.write(`\n${chalk.bold(report.target)}\n`); process.stdout.write(`${report.pages.length} renders · ${report.durationMs} ms · score ${scoreText}\n\n`); + if (report.comparison) { + const newCount = String(report.comparison.counts.new); + process.stdout.write(`${report.comparison.counts.new ? chalk.red.bold(newCount) : chalk.green.bold(newCount)} new ` + + `${chalk.blue.bold(String(report.comparison.counts.existing))} existing ` + + `${chalk.green(String(report.comparison.counts.resolved))} resolved\n\n`); + } if (report.suppressions) { const source = report.suppressions.source ? ` from ${report.suppressions.source}` @@ -48,28 +78,39 @@ function printReport(report, artifactPaths) { process.stdout.write(`${chalk.yellow(String(report.suppressions.total))} findings suppressed by ` + `${report.suppressions.active.length} active entries${source}\n\n`); } - if (report.summary.total === 0) { + const displayedFindings = report.comparison + ? report.comparison.new + : report.pages.flatMap((page) => page.findings); + if (displayedFindings.length === 0) { const message = report.suppressions?.total - ? "No active visual findings; review the suppression audit." - : "No visual findings detected."; + ? report.comparison + ? "No new visual findings; review the suppression audit." + : "No active visual findings; review the suppression audit." + : report.comparison + ? "No new visual findings detected." + : "No visual findings detected."; process.stdout.write(`${chalk.green.bold("PASS")} ${message}\n`); } else { - process.stdout.write(`${severityColor("critical", String(report.summary.critical))} critical ` + - `${severityColor("error", String(report.summary.error))} errors ` + - `${severityColor("warning", String(report.summary.warning))} warnings ` + - `${chalk.blue(String(report.summary.info))} info\n\n`); + const counts = countFindings(displayedFindings); + process.stdout.write(`${severityColor("critical", String(counts.critical))} critical ` + + `${severityColor("error", String(counts.error))} errors ` + + `${severityColor("warning", String(counts.warning))} warnings ` + + `${chalk.blue(String(counts.info))} info\n\n`); for (const page of report.pages) { - if (page.findings.length === 0) + const findings = report.comparison + ? findingsForPage(displayedFindings, page) + : page.findings; + if (findings.length === 0) continue; process.stdout.write(`${chalk.bold(page.pagePath)} ${chalk.dim(`${page.viewport.name} ${page.viewport.width}x${page.viewport.height}`)}\n`); - for (const finding of page.findings.slice(0, 12)) { + for (const finding of findings.slice(0, 12)) { const badge = severityColor(finding.severity, finding.ruleId); process.stdout.write(` ${badge} ${finding.title}\n`); process.stdout.write(` ${finding.evidence.selector}${finding.evidence.text ? chalk.dim(` · ${finding.evidence.text.slice(0, 72)}`) : ""}\n`); } - if (page.findings.length > 12) - process.stdout.write(chalk.dim(` ... ${page.findings.length - 12} more in the HTML report\n`)); + if (findings.length > 12) + process.stdout.write(chalk.dim(` ... ${findings.length - 12} more in the HTML report\n`)); process.stdout.write("\n"); } } @@ -94,12 +135,19 @@ function shouldFail(report, threshold) { if (threshold === "never") return false; const minimum = SEVERITY_RANK[threshold]; - return report.pages.some((page) => page.findings.some((finding) => SEVERITY_RANK[finding.severity] >= minimum)); + const findings = report.comparison + ? report.comparison.new + : report.pages.flatMap((page) => page.findings); + return findings.some((finding) => SEVERITY_RANK[finding.severity] >= minimum); } async function loadReportWriter() { return import("./report.js"); } async function main(target, cli) { + const baselineSource = cli.compare; + const baseline = baselineSource + ? await loadBaselineReport(baselineSource) + : undefined; const loadedConfig = await loadLayoutScopeConfig({ ...(cli.config ? { configPath: cli.config } : {}), autoDiscover: cli.autoConfig !== false, @@ -139,6 +187,9 @@ async function main(target, cli) { suppressionSource: loadedConfig?.source, }; const report = await scan(scanOptions); + if (baseline && baselineSource) { + report.comparison = compareReports(report, baseline, { baselineSource }); + } const { writeReportArtifacts } = await loadReportWriter(); const artifacts = await writeReportArtifacts(report, outputDir, { canonicalUrl: cli.canonicalUrl, @@ -162,6 +213,7 @@ program .argument("", "URL, local HTML file, or directory containing index.html") .option("-c, --config ", "config file (auto-detects layoutscope.config.ts, .js, or .json)") .option("--no-auto-config", "disable automatic config discovery (an explicit --config still loads)") + .option("--compare ", "compare against a previous LayoutScope JSON report") .option("-o, --output ", "report output directory", ".layoutscope") .option("-v, --viewport ", "viewport preset or WIDTHxHEIGHT; repeatable", collect, []) .option("-p, --path ", "URL path to scan; repeatable", collect, []) @@ -183,13 +235,13 @@ program .addOption(new Option("--format ", "terminal output format") .choices(["text", "json"]) .default("text")) - .version("0.3.0") + .version("0.4.0") .showHelpAfterError() .action((target, options) => main(target, options)); program.parseAsync().catch(async (error) => { const message = error instanceof Error ? error.message : String(error); if (/Executable doesn't exist|browserType\.launch/i.test(message)) { - process.stderr.write(`${chalk.red.bold("Browser unavailable.")} Run ${chalk.cyan("npx --yes --package github:LyraZeta/layoutscope#v0.3.0 playwright-core install chromium")} once, or pass ${chalk.cyan("--browser chrome")} / ${chalk.cyan("--browser msedge")} to use an installed browser.\n`); + process.stderr.write(`${chalk.red.bold("Browser unavailable.")} Run ${chalk.cyan("npx --yes --package github:LyraZeta/layoutscope#v0.4.0 playwright-core install chromium")} once, or pass ${chalk.cyan("--browser chrome")} / ${chalk.cyan("--browser msedge")} to use an installed browser.\n`); } else { process.stderr.write(`${chalk.red.bold("LayoutScope failed:")} ${message}\n`); diff --git a/dist/cli.js.map b/dist/cli.js.map index d78bd05..1331ce1 100644 --- a/dist/cli.js.map +++ b/dist/cli.js.map @@ -1 +1 @@ -{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/compare.d.ts b/dist/compare.d.ts new file mode 100644 index 0000000..f52e590 --- /dev/null +++ b/dist/compare.d.ts @@ -0,0 +1,13 @@ +import type { Finding, ReportComparison, ScanReport } from "./types.js"; +export interface CompareReportOptions { + baselineSource?: string; +} +/** Validate a JSON value as a LayoutScope report that can be used as a baseline. */ +export declare function validateBaselineReport(value: unknown, source?: string): asserts value is ScanReport; +/** Load and validate a LayoutScope JSON report for use as a comparison baseline. */ +export declare function loadBaselineReport(reportPath: string): Promise; +/** Build the stable identity used to match one active finding across reports. */ +export declare function findingIdentity(finding: Finding): string; +/** Compare active findings in a current report with a validated baseline. */ +export declare function compareReports(current: ScanReport, baseline: unknown, options?: CompareReportOptions): ReportComparison; +//# sourceMappingURL=compare.d.ts.map \ No newline at end of file diff --git a/dist/compare.d.ts.map b/dist/compare.d.ts.map new file mode 100644 index 0000000..daeb34d --- /dev/null +++ b/dist/compare.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../src/compare.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,OAAO,EACP,gBAAgB,EAEhB,UAAU,EAEX,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAqUD,oFAAoF;AACpF,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EACd,MAAM,SAAoB,GACzB,OAAO,CAAC,KAAK,IAAI,UAAU,CAoB7B;AAED,oFAAoF;AACpF,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAqBhF;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAaxD;AAMD,6EAA6E;AAC7E,wBAAgB,cAAc,CAC5B,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,OAAO,EACjB,OAAO,GAAE,oBAAyB,GACjC,gBAAgB,CA+ClB"} \ No newline at end of file diff --git a/dist/compare.js b/dist/compare.js new file mode 100644 index 0000000..910830c --- /dev/null +++ b/dist/compare.js @@ -0,0 +1,309 @@ +import { readFile } from "node:fs/promises"; +import path from "node:path"; +const RULE_IDS = new Set([ + "LS001", + "LS002", + "LS003", + "LS004", + "LS005", + "LS006", + "LS007", + "LS008", + "LS009", + "LS010", +]); +const SEVERITIES = new Set([ + "critical", + "error", + "warning", + "info", +]); +function isRecord(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} +function fail(source, property, expectation) { + throw new Error(`${source}.${property} ${expectation}.`); +} +function requireRecord(value, source, property) { + if (!isRecord(value)) + fail(source, property, "must be an object"); + return value; +} +function requireArray(value, source, property) { + if (!Array.isArray(value)) + fail(source, property, "must be an array"); + return value; +} +function requireString(value, source, property) { + if (typeof value !== "string" || !value.trim()) { + fail(source, property, "must be a non-empty string"); + } + return value; +} +function requireBoolean(value, source, property) { + if (typeof value !== "boolean") + fail(source, property, "must be a boolean"); + return value; +} +function requireFiniteNumber(value, source, property) { + if (typeof value !== "number" || !Number.isFinite(value)) { + fail(source, property, "must be a finite number"); + } + return value; +} +function requireNonNegativeNumber(value, source, property) { + const number = requireFiniteNumber(value, source, property); + if (number < 0) + fail(source, property, "must be zero or greater"); + return number; +} +function requirePositiveNumber(value, source, property) { + const number = requireFiniteNumber(value, source, property); + if (number <= 0) + fail(source, property, "must be greater than zero"); + return number; +} +function requireOptionalString(value, source, property) { + if (value !== undefined && typeof value !== "string") { + fail(source, property, "must be a string"); + } +} +function requireOptionalBoolean(value, source, property) { + if (value !== undefined) + requireBoolean(value, source, property); +} +function validateViewport(value, source, property) { + const viewport = requireRecord(value, source, property); + requireString(viewport.name, source, `${property}.name`); + requirePositiveNumber(viewport.width, source, `${property}.width`); + requirePositiveNumber(viewport.height, source, `${property}.height`); + if (viewport.deviceScaleFactor !== undefined) { + requirePositiveNumber(viewport.deviceScaleFactor, source, `${property}.deviceScaleFactor`); + } + requireOptionalBoolean(viewport.isMobile, source, `${property}.isMobile`); + requireOptionalBoolean(viewport.hasTouch, source, `${property}.hasTouch`); +} +function validateRect(value, source, property) { + const rect = requireRecord(value, source, property); + for (const key of [ + "x", + "y", + "width", + "height", + "top", + "right", + "bottom", + "left", + ]) { + requireFiniteNumber(rect[key], source, `${property}.${key}`); + } +} +function validateEvidence(value, source, property) { + const evidence = requireRecord(value, source, property); + requireString(evidence.selector, source, `${property}.selector`); + requireString(evidence.tag, source, `${property}.tag`); + requireOptionalString(evidence.text, source, `${property}.text`); + requireOptionalString(evidence.role, source, `${property}.role`); + validateRect(evidence.rect, source, `${property}.rect`); + requireOptionalString(evidence.relatedSelector, source, `${property}.relatedSelector`); + if (evidence.relatedRect !== undefined) { + validateRect(evidence.relatedRect, source, `${property}.relatedRect`); + } + if (evidence.details !== undefined) { + const details = requireRecord(evidence.details, source, `${property}.details`); + for (const [key, detail] of Object.entries(details)) { + if (detail !== null && + typeof detail !== "string" && + typeof detail !== "number" && + typeof detail !== "boolean") { + fail(source, `${property}.details.${key}`, "must be a string, number, boolean, or null"); + } + if (typeof detail === "number" && !Number.isFinite(detail)) { + fail(source, `${property}.details.${key}`, "must be a finite number"); + } + } + } +} +function validateFinding(value, source, property) { + const finding = requireRecord(value, source, property); + requireString(finding.id, source, `${property}.id`); + const ruleId = requireString(finding.ruleId, source, `${property}.ruleId`); + if (!RULE_IDS.has(ruleId)) { + fail(source, `${property}.ruleId`, "must be a supported LayoutScope rule ID"); + } + const severity = requireString(finding.severity, source, `${property}.severity`); + if (!SEVERITIES.has(severity)) { + fail(source, `${property}.severity`, "must be critical, error, warning, or info"); + } + requireString(finding.title, source, `${property}.title`); + requireString(finding.message, source, `${property}.message`); + requireString(finding.help, source, `${property}.help`); + requireString(finding.pageUrl, source, `${property}.pageUrl`); + requireString(finding.pagePath, source, `${property}.pagePath`); + validateViewport(finding.viewport, source, `${property}.viewport`); + validateEvidence(finding.evidence, source, `${property}.evidence`); + requireString(finding.fingerprint, source, `${property}.fingerprint`); +} +function validatePage(value, source, property) { + const page = requireRecord(value, source, property); + requireString(page.pageUrl, source, `${property}.pageUrl`); + requireString(page.pagePath, source, `${property}.pagePath`); + if (typeof page.title !== "string") { + fail(source, `${property}.title`, "must be a string"); + } + validateViewport(page.viewport, source, `${property}.viewport`); + const findings = requireArray(page.findings, source, `${property}.findings`); + findings.forEach((finding, index) => validateFinding(finding, source, `${property}.findings[${index}]`)); + if (page.suppressedCount !== undefined) { + requireNonNegativeNumber(page.suppressedCount, source, `${property}.suppressedCount`); + } + const metrics = requireRecord(page.metrics, source, `${property}.metrics`); + for (const key of [ + "documentWidth", + "documentHeight", + "viewportWidth", + "viewportHeight", + "elementsInspected", + "loadTimeMs", + ]) { + requireNonNegativeNumber(metrics[key], source, `${property}.metrics.${key}`); + } + if (typeof page.screenshotPath !== "string") { + fail(source, `${property}.screenshotPath`, "must be a string"); + } + if (typeof page.annotatedScreenshotPath !== "string") { + fail(source, `${property}.annotatedScreenshotPath`, "must be a string"); + } +} +function validateSummary(value, source, property) { + const summary = requireRecord(value, source, property); + for (const key of [ + "critical", + "error", + "warning", + "info", + "total", + "pages", + "viewports", + "score", + ]) { + requireNonNegativeNumber(summary[key], source, `${property}.${key}`); + } + if (summary.suppressed !== undefined) { + requireNonNegativeNumber(summary.suppressed, source, `${property}.suppressed`); + } +} +function validateOptions(value, source, property) { + const options = requireRecord(value, source, property); + const viewports = requireArray(options.viewports, source, `${property}.viewports`); + viewports.forEach((viewport, index) => validateViewport(viewport, source, `${property}.viewports[${index}]`)); + const paths = requireArray(options.paths, source, `${property}.paths`); + paths.forEach((pagePath, index) => requireString(pagePath, source, `${property}.paths[${index}]`)); + requireNonNegativeNumber(options.waitMs, source, `${property}.waitMs`); + requireOptionalString(options.readySelector, source, `${property}.readySelector`); +} +/** Validate a JSON value as a LayoutScope report that can be used as a baseline. */ +export function validateBaselineReport(value, source = "Baseline report") { + const report = requireRecord(value, source, "root"); + if (report.schemaVersion !== "1.0") { + fail(source, "schemaVersion", 'must be the supported value "1.0"'); + } + const tool = requireRecord(report.tool, source, "tool"); + if (tool.name !== "layoutscope") { + fail(source, "tool.name", 'must be "layoutscope"'); + } + requireString(tool.version, source, "tool.version"); + requireString(report.runId, source, "runId"); + requireString(report.startedAt, source, "startedAt"); + requireNonNegativeNumber(report.durationMs, source, "durationMs"); + requireString(report.target, source, "target"); + const pages = requireArray(report.pages, source, "pages"); + pages.forEach((page, index) => validatePage(page, source, `pages[${index}]`)); + validateSummary(report.summary, source, "summary"); + validateOptions(report.options, source, "options"); +} +/** Load and validate a LayoutScope JSON report for use as a comparison baseline. */ +export async function loadBaselineReport(reportPath) { + const absolutePath = path.resolve(reportPath); + let contents; + try { + contents = await readFile(absolutePath, "utf8"); + } + catch (error) { + const detail = error instanceof Error ? error.message : String(error); + throw new Error(`Unable to read baseline report "${absolutePath}": ${detail}`); + } + let parsed; + try { + parsed = JSON.parse(contents); + } + catch (error) { + const detail = error instanceof Error ? error.message : String(error); + throw new Error(`Baseline report "${absolutePath}" contains invalid JSON: ${detail}`); + } + validateBaselineReport(parsed, `Baseline report "${absolutePath}"`); + return parsed; +} +/** Build the stable identity used to match one active finding across reports. */ +export function findingIdentity(finding) { + const viewport = finding.viewport; + return JSON.stringify([ + finding.pagePath, + viewport.name, + viewport.width, + viewport.height, + viewport.deviceScaleFactor ?? 1, + viewport.isMobile ?? false, + viewport.hasTouch ?? false, + finding.ruleId, + finding.fingerprint, + ]); +} +function activeFindings(report) { + return report.pages.flatMap((page) => page.findings); +} +/** Compare active findings in a current report with a validated baseline. */ +export function compareReports(current, baseline, options = {}) { + validateBaselineReport(baseline); + const baselineFindings = activeFindings(baseline); + const baselineBuckets = new Map(); + for (const [index, finding] of baselineFindings.entries()) { + const identity = findingIdentity(finding); + const bucket = baselineBuckets.get(identity) ?? []; + bucket.push(index); + baselineBuckets.set(identity, bucket); + } + const newFindings = []; + const existingFindings = []; + const matchedBaselineIndexes = new Set(); + for (const finding of activeFindings(current)) { + const bucket = baselineBuckets.get(findingIdentity(finding)); + if (!bucket?.length) { + newFindings.push(finding); + continue; + } + existingFindings.push(finding); + const baselineIndex = bucket.shift(); + if (baselineIndex !== undefined) + matchedBaselineIndexes.add(baselineIndex); + } + const resolvedFindings = baselineFindings.filter((_finding, index) => !matchedBaselineIndexes.has(index)); + return { + baseline: { + ...(options.baselineSource ? { source: options.baselineSource } : {}), + schemaVersion: baseline.schemaVersion, + toolVersion: baseline.tool.version, + runId: baseline.runId, + startedAt: baseline.startedAt, + }, + counts: { + new: newFindings.length, + existing: existingFindings.length, + resolved: resolvedFindings.length, + }, + new: newFindings, + existing: existingFindings, + resolved: resolvedFindings, + }; +} +//# sourceMappingURL=compare.js.map \ No newline at end of file diff --git a/dist/compare.js.map b/dist/compare.js.map new file mode 100644 index 0000000..3240e26 --- /dev/null +++ b/dist/compare.js.map @@ -0,0 +1 @@ +{"version":3,"file":"compare.js","sourceRoot":"","sources":["../src/compare.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/report.d.ts.map b/dist/report.d.ts.map index 2ec8944..b8d82b1 100644 --- a/dist/report.d.ts.map +++ b/dist/report.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAIV,eAAe,EACf,UAAU,EAGX,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA6lBD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,iBAAsB,GAC9B,MAAM,CAyLR;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAM,GACvD,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,UAAU,EAClB,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,eAAe,CAAC,CAoB1B"} \ No newline at end of file +{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAIV,eAAe,EACf,UAAU,EAGX,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAkoBD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,iBAAsB,GAC9B,MAAM,CA0LR;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAM,GACvD,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,UAAU,EAClB,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,eAAe,CAAC,CAoB1B"} \ No newline at end of file diff --git a/dist/report.js b/dist/report.js index 74a722f..11e9cf3 100644 --- a/dist/report.js +++ b/dist/report.js @@ -368,13 +368,13 @@ const REPORT_STYLES = String.raw ` .topbar{min-height:68px;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:12px clamp(18px,3vw,44px);background:var(--surface);border-bottom:1px solid var(--border)}.brand{display:flex;align-items:center;gap:11px;flex:none}.brand-mark{position:relative;width:28px;height:28px;border:2px solid var(--brand);border-radius:6px}.brand-mark:before,.brand-mark:after{content:"";position:absolute;background:var(--brand);border-radius:1px}.brand-mark:before{width:12px;height:3px;left:6px;top:6px}.brand-mark:after{width:3px;height:9px;left:6px;top:12px}.brand-name{font-size:18px;font-weight:750}.brand-version,.run-sub{color:var(--subtle);font-size:12px}.project-link{min-height:32px;display:inline-flex;align-items:center;margin-left:4px;padding:5px 9px;border:1px solid var(--border);border-radius:5px;color:var(--text);font-size:12px;font-weight:650;text-decoration:none}.project-link:hover{border-color:var(--strong);background:var(--muted)}.run{text-align:right;min-width:0}.target{display:block;max-width:min(58vw,760px);overflow:hidden;color:var(--text);font-weight:650;text-overflow:ellipsis;text-decoration:none;white-space:nowrap} .layout{width:min(1680px,100%);margin:auto;padding:28px clamp(16px,3vw,44px) 56px;display:grid;grid-template-columns:244px minmax(0,1fr);gap:28px;align-items:start}.sidebar{position:sticky;top:18px;display:grid;gap:16px}.score,.filters{background:var(--surface);border:1px solid var(--border);border-radius:8px}.score{padding:20px}.eyebrow,.filter-title{color:var(--subtle);font-size:11px;font-weight:750;text-transform:uppercase}.score-row{display:flex;align-items:flex-end;gap:5px;margin:3px 0 4px}.score-value{font-size:54px;line-height:1;font-weight:760}.score-total{padding-bottom:6px;color:var(--subtle);font-size:16px}.score.excellent .score-value{color:var(--brand2)}.score.good .score-value{color:var(--info)}.score.fair .score-value{color:var(--warning)}.score.poor .score-value{color:var(--critical)}.score p{margin:0;color:var(--subtle)} .filters{padding:16px}.filters h2{margin:0 0 14px;font-size:14px}.filter-group{padding:14px 0;border-top:1px solid var(--border)}.filter-group:first-of-type{border-top:0;padding-top:0}.filter-title{display:block;margin-bottom:8px}.severity-options{display:grid;gap:3px}.severity-filter{position:relative;min-height:34px;display:grid;grid-template-columns:14px 1fr auto;align-items:center;gap:9px;padding:5px 7px;border-radius:5px;cursor:pointer;text-transform:capitalize;color:var(--severity)}.severity-filter:hover{background:var(--muted)}.severity-filter input{position:absolute;opacity:0}.check{width:13px;height:13px;border:1px solid currentColor;border-radius:3px}.severity-filter input:checked+.check{box-shadow:inset 0 0 0 3px var(--surface);background:currentColor}.severity-filter span:nth-of-type(2),.severity-filter strong{color:var(--text)}.severity-filter strong{font-size:12px}.severity-critical{--severity:var(--critical)}.severity-error{--severity:var(--error)}.severity-warning{--severity:var(--warning)}.severity-info{--severity:var(--info)}.filter-select{width:100%;min-height:38px;padding:7px 9px;border:1px solid var(--strong);border-radius:5px;background:var(--raised)}.overlay-toggle{display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:pointer}.switch{position:relative;width:34px;height:20px;flex:none}.switch input{position:absolute;opacity:0}.switch span{display:block;width:100%;height:100%;border-radius:10px;background:var(--strong)}.switch span:after{content:"";position:absolute;width:14px;height:14px;top:3px;left:3px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.3);transition:transform .14s}.switch input:checked+span{background:var(--brand)}.switch input:checked+span:after{transform:translateX(14px)}.reset{width:100%;min-height:36px;border:1px solid var(--strong);border-radius:5px;background:var(--surface);cursor:pointer;font-weight:650}.reset:hover{background:var(--muted)} -main{min-width:0}.summary{display:grid;grid-template-columns:repeat(4,minmax(100px,1fr));gap:10px}.summary button{position:relative;min-height:78px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;padding:12px 14px 12px 17px;border:1px solid var(--border);border-radius:7px;background:var(--surface);cursor:pointer;text-align:left;overflow:hidden}.summary button:before{content:"";position:absolute;inset:0 auto 0 0;width:4px;background:var(--severity)}.summary button:hover{border-color:var(--strong)}.summary strong{font-size:24px;line-height:1.1}.summary span{color:var(--subtle);text-transform:capitalize}.results-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin:28px 0 12px}.results-head h1{margin:0;font-size:20px}.results-head p{margin:0;color:var(--subtle)}.empty{padding:56px 24px;border:1px dashed var(--strong);border-radius:8px;background:var(--surface);text-align:center}.empty strong{display:block;font-size:17px}.empty span{color:var(--subtle)} +main{min-width:0}.summary{display:grid;grid-template-columns:repeat(4,minmax(100px,1fr));gap:10px}.summary button{position:relative;min-height:78px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;padding:12px 14px 12px 17px;border:1px solid var(--border);border-radius:7px;background:var(--surface);cursor:pointer;text-align:left;overflow:hidden}.summary button:before{content:"";position:absolute;inset:0 auto 0 0;width:4px;background:var(--severity)}.summary button:hover{border-color:var(--strong)}.summary strong{font-size:24px;line-height:1.1}.summary span{color:var(--subtle);text-transform:capitalize}.comparison{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-top:18px;padding:15px 18px;border:1px solid var(--border);border-radius:8px;background:var(--surface)}.comparison-title{min-width:0}.comparison h2{margin:2px 0 1px;font-size:17px}.comparison p{margin:0;color:var(--subtle);font-size:12px;overflow-wrap:anywhere}.comparison dl{display:grid;grid-template-columns:repeat(3,minmax(76px,1fr));min-width:min(100%,300px);margin:0}.comparison dl>div{padding:2px 14px;border-left:1px solid var(--border)}.comparison dt{color:var(--subtle);font-size:11px;text-transform:uppercase}.comparison dd{margin:0;font-size:22px;font-weight:750}.comparison-new dd{color:var(--error)}.comparison-resolved dd{color:var(--brand2)}.results-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin:28px 0 12px}.results-head h1{margin:0;font-size:20px}.results-head p{margin:0;color:var(--subtle)}.empty{padding:56px 24px;border:1px dashed var(--strong);border-radius:8px;background:var(--surface);text-align:center}.empty strong{display:block;font-size:17px}.empty span{color:var(--subtle)} .page{margin-top:18px;border:1px solid var(--border);border-radius:8px;background:var(--surface);box-shadow:var(--shadow);overflow:hidden}.page-head{display:flex;justify-content:space-between;align-items:center;gap:18px;padding:16px 18px;border-bottom:1px solid var(--border)}.page-id{min-width:0;display:flex;align-items:center;gap:12px}.page-id>span{color:var(--subtle);font:650 12px/1 "SFMono-Regular",Consolas,monospace}.page-id h2{margin:0;font-size:16px;overflow-wrap:anywhere}.page-id a{display:block;max-width:min(58vw,680px);margin-top:2px;overflow:hidden;color:var(--subtle);font-size:12px;text-overflow:ellipsis;white-space:nowrap}.viewport{flex:none;padding:5px 8px;border:1px solid var(--border);border-radius:5px;background:var(--muted);text-align:right;font-size:11px}.viewport span{display:block;color:var(--subtle)}.viewport strong{font-size:12px}.metrics{display:flex;flex-wrap:wrap;gap:7px 18px;padding:9px 18px;border-bottom:1px solid var(--border);color:var(--subtle);font-size:11px}.metrics strong{color:var(--text)}.workbench{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(310px,.75fr);min-height:420px}.visual,.findings{min-width:0}.visual{border-right:1px solid var(--border)}.panel-head{min-height:47px;display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:13px 15px;border-bottom:1px solid var(--border)}.panel-head h3{margin:0;font-size:13px}.panel-head span{color:var(--subtle);font-size:11px} .shot-scroll{position:relative;max-height:70vh;min-height:320px;overflow:auto;overscroll-behavior:contain;background:var(--muted)}.shot-stage{position:relative;width:100%;line-height:0}.shot-stage img{display:block;width:100%;height:auto;min-height:160px}.markers{position:absolute;inset:0;pointer-events:none}.marker{position:absolute;z-index:2;min-width:20px;min-height:20px;padding:0;border:2px solid var(--severity);border-radius:3px;background:color-mix(in srgb,var(--severity) 15%,transparent);box-shadow:0 0 0 1px rgba(255,255,255,.8),0 2px 6px rgba(0,0,0,.25);color:#fff;cursor:pointer;line-height:1;pointer-events:auto}.marker>span{position:absolute;top:-12px;left:-2px;min-width:19px;height:19px;display:grid;place-items:center;padding:0 3px;border-radius:3px 3px 3px 0;background:var(--severity);color:#fff;font-size:10px;font-weight:800}.marker-related{z-index:1;border-style:dashed;background:transparent}.marker-related>span{display:none}.marker:hover,.marker.is-active{z-index:4;box-shadow:0 0 0 3px color-mix(in srgb,var(--severity) 36%,transparent),0 2px 8px rgba(0,0,0,.3)}body.overlays-hidden .markers{display:none}.image-error,.missing{min-height:320px;display:grid;align-content:center;justify-items:center;gap:4px;padding:24px;color:var(--subtle);text-align:center;line-height:1.5}.image-error strong,.missing strong{color:var(--text)}.image-error span{max-width:100%;overflow-wrap:anywhere;font-size:11px} .finding-list{max-height:calc(70vh + 47px);overflow:auto;overscroll-behavior:contain}.finding{--severity:var(--info);padding:14px 15px 15px;border-bottom:1px solid var(--border);border-left:3px solid transparent;scroll-margin:20px}.finding:last-child{border-bottom:0}.finding.is-active{border-left-color:var(--severity);background:color-mix(in srgb,var(--severity) 7%,var(--surface))}.finding-focus{width:100%;display:grid;grid-template-columns:24px minmax(0,1fr) 18px;align-items:start;gap:9px;padding:0;border:0;background:transparent;cursor:pointer;text-align:left}.finding-number{width:22px;height:22px;display:grid;place-items:center;border-radius:4px;background:var(--severity);color:#fff;font-size:11px;font-weight:800}.finding-title{display:block;line-height:1.35}.finding-tags{display:flex;align-items:center;gap:7px;margin-top:4px}.finding-tags b{color:var(--severity);font-size:10px;text-transform:uppercase}.finding-tags code{padding:1px 4px;border-radius:3px;background:var(--muted);color:var(--subtle);font-size:10px}.locate{color:var(--subtle);font-size:17px}.message{margin:10px 0 8px 33px;line-height:1.55}.selector{margin-left:33px;color:var(--subtle);overflow-wrap:anywhere}.selector>code{padding:2px 4px;border-radius:3px;background:var(--muted);color:var(--text)}.related{display:block;margin-top:5px;font-size:11px}.details{margin:10px 0 0 33px;color:var(--subtle);font-size:11px}.details summary{cursor:pointer;font-weight:650}.details dl{margin:7px 0 0}.detail-row{display:grid;grid-template-columns:minmax(70px,.45fr) minmax(0,1fr);gap:8px;padding:3px 0}.detail-row dt,.detail-row dd{overflow-wrap:anywhere}.detail-row dd{margin:0;color:var(--text)}.help{margin:11px 0 0 33px;padding:8px 9px;border-radius:5px;background:var(--muted);color:var(--subtle);font-size:11px}.help strong{color:var(--text)}.clean{min-height:320px;display:grid;place-content:center;text-align:center}.clean strong{font-size:16px}.clean span{color:var(--subtle)}.suppression-audit{margin-top:18px;border:1px solid var(--border);border-radius:8px;background:var(--surface);overflow:hidden}.suppression-title{display:flex;align-items:end;justify-content:space-between;gap:18px;padding:15px 18px;background:var(--muted);border-bottom:1px solid var(--border)}.suppression-title h2{margin:2px 0 0;font-size:16px}.suppression-title p{margin:0;color:var(--subtle);font-size:12px}.suppression-entry{padding:13px 18px;border-bottom:1px solid var(--border)}.suppression-entry:last-child{border-bottom:0}.suppression-head{display:flex;justify-content:space-between;gap:16px}.suppression-head span{min-width:0;overflow-wrap:anywhere}.suppression-head strong{flex:none;font-size:12px}.suppression-entry>p{margin:5px 0;color:var(--subtle)}.suppression-entry details{margin-top:7px;color:var(--subtle);font-size:11px}.suppression-entry summary{cursor:pointer}.suppression-entry ul{margin:7px 0 0;padding-left:20px}.suppression-entry li{margin:3px 0;overflow-wrap:anywhere}.unused-suppression{font-style:italic}.report-footer{display:flex;justify-content:space-between;gap:18px;margin-top:28px;padding-top:18px;border-top:1px solid var(--border);color:var(--subtle);font-size:11px} @media(max-width:1180px){.workbench{grid-template-columns:1fr}.visual{border-right:0;border-bottom:1px solid var(--border)}.finding-list{max-height:none}} @media(max-width:820px){.topbar{align-items:flex-start}.run{text-align:left}.target{max-width:55vw}.layout{grid-template-columns:1fr;padding-top:18px}.sidebar{position:static;grid-template-columns:minmax(150px,.45fr) minmax(0,1fr)}.filters{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 15px}.filters h2{grid-column:1/-1}.filter-group{border-top:1px solid var(--border)}} -@media(max-width:560px){.topbar{display:block}.brand{flex-wrap:wrap}.run{margin-top:10px}.target{max-width:100%;white-space:normal;overflow-wrap:anywhere}.sidebar,.filters{grid-template-columns:1fr}.summary{grid-template-columns:repeat(2,minmax(0,1fr))}.results-head,.suppression-title,.suppression-head{display:block}.page-head{align-items:flex-start}.page-id a{max-width:48vw}.metrics span{flex:1 1 42%}.panel-head>span{display:none}.shot-scroll{min-height:240px}.message,.selector,.details,.help{margin-left:0}.suppression-title p,.suppression-head strong{display:block;margin-top:5px}.report-footer{display:block}} +@media(max-width:560px){.topbar{display:block}.brand{flex-wrap:wrap}.run{margin-top:10px}.target{max-width:100%;white-space:normal;overflow-wrap:anywhere}.sidebar,.filters{grid-template-columns:1fr}.summary{grid-template-columns:repeat(2,minmax(0,1fr))}.comparison{display:block}.comparison dl{width:100%;min-width:0;margin-top:13px}.comparison dl>div:first-child{border-left:0;padding-left:0}.results-head,.suppression-title,.suppression-head{display:block}.page-head{align-items:flex-start}.page-id a{max-width:48vw}.metrics span{flex:1 1 42%}.panel-head>span{display:none}.shot-scroll{min-height:240px}.message,.selector,.details,.help{margin-left:0}.suppression-title p,.suppression-head strong{display:block;margin-top:5px}.report-footer{display:block}} @media print{:root{color-scheme:light}body{background:#fff}.sidebar,.summary,.results-head p{display:none!important}.layout{display:block;width:100%;padding:16px}.page{break-inside:avoid;box-shadow:none}.workbench{display:block}.visual{border:0}.shot-scroll,.finding-list{max-height:none;overflow:visible}} `; const REPORT_SCRIPT = String.raw ` @@ -531,6 +531,41 @@ function renderSummary(report) { "", ].join("")).join(""); } +function renderComparison(report) { + const comparison = report.comparison; + if (!comparison) + return ""; + const baselineLabel = comparison.baseline.source + ? '' + + escapeHtml(shorten(comparison.baseline.source, 80)) + + "" + : "run " + escapeHtml(comparison.baseline.runId) + ""; + const headline = comparison.counts.new + ? formatNumber(comparison.counts.new) + + (comparison.counts.new === 1 ? " new finding" : " new findings") + : "No new findings"; + return [ + '
', + 'Baseline comparison

', + headline, + "

Compared with ", + baselineLabel, + " from ", + escapeHtml(formatTimestamp(comparison.baseline.startedAt)), + ".

", + '
New
', + formatNumber(comparison.counts.new), + "
", + '
Existing
', + formatNumber(comparison.counts.existing), + "
", + '
Resolved
', + formatNumber(comparison.counts.resolved), + "
", + ].join(""); +} export function createHtmlReport(report, options = {}) { const score = clamp(Math.round(finite(report.summary.score)), 0, 100); const state = scoreState(score); @@ -668,7 +703,8 @@ export function createHtmlReport(report, options = {}) { '', '
' + renderSummary(report) + - "
", + "" + + renderComparison(report), '

Inspection results

' + formatNumber(findings.length) + ' findings across ' + diff --git a/dist/report.js.map b/dist/report.js.map index 3c296ca..3247b53 100644 --- a/dist/report.js.map +++ b/dist/report.js.map @@ -1 +1 @@ -{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/sarif.d.ts b/dist/sarif.d.ts index 40b9b72..6872467 100644 --- a/dist/sarif.d.ts +++ b/dist/sarif.d.ts @@ -1,4 +1,4 @@ -import type { Finding, RuleId, ScanReport, Severity } from "./types.js"; +import type { Finding, ReportComparison, RuleId, ScanReport, Severity } from "./types.js"; export type SarifLevel = "error" | "warning" | "note" | "none"; export interface SarifLog { $schema: string; @@ -30,6 +30,7 @@ export interface SarifRun { score: number; pages: number; viewports: number; + comparison?: Pick; suppressed?: number; suppressionAudit?: Array<{ ruleId: RuleId; diff --git a/dist/sarif.d.ts.map b/dist/sarif.d.ts.map index 0dc29d0..f6fb50a 100644 --- a/dist/sarif.d.ts.map +++ b/dist/sarif.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../src/sarif.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../src/sarif.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,OAAO,EACP,gBAAgB,EAChB,MAAM,EACN,UAAU,EACV,QAAQ,EACT,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/D,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE;QACJ,MAAM,EAAE;YACN,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;YAChB,cAAc,EAAE,MAAM,CAAC;YACvB,KAAK,EAAE,SAAS,EAAE,CAAC;SACpB,CAAC;KACH,CAAC;IACF,WAAW,EAAE,KAAK,CAAC;QACjB,mBAAmB,EAAE,OAAO,CAAC;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE;YACV,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;KACH,CAAC,CAAC;IACH,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,UAAU,EAAE;QACV,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;QAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,gBAAgB,CAAC,EAAE,KAAK,CAAC;YACvB,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,MAAM,EAAE,MAAM,CAAC;YACf,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC,CAAC;KACJ,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,eAAe,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvB,oBAAoB,EAAE;QAAE,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IAC5C,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,eAAe,EAAE,QAAQ,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,SAAS,EAAE,KAAK,CAAC;QACf,gBAAgB,EAAE;YAChB,gBAAgB,EAAE;gBAChB,GAAG,EAAE,MAAM,CAAC;aACb,CAAC;SACH,CAAC;QACF,gBAAgB,EAAE,KAAK,CAAC;YACtB,IAAI,EAAE,MAAM,CAAC;YACb,kBAAkB,EAAE,MAAM,CAAC;YAC3B,IAAI,EAAE,SAAS,CAAC;SACjB,CAAC,CAAC;KACJ,CAAC,CAAC;IACH,mBAAmB,EAAE;QACnB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,YAAY,CAAC,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,UAAU,CAAC;QACjB,MAAM,EAAE,UAAU,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;IACH,UAAU,EAAE;QACV,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,QAAQ,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;YACd,MAAM,EAAE,MAAM,CAAC;YACf,iBAAiB,EAAE,MAAM,CAAC;SAC3B,CAAC;QACF,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QAC9B,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAkGD,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,QAAQ,CA0E3D;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9F"} \ No newline at end of file diff --git a/dist/sarif.js b/dist/sarif.js index ab1dcc8..af0d74f 100644 --- a/dist/sarif.js +++ b/dist/sarif.js @@ -140,6 +140,14 @@ export function createSarifLog(report) { score: report.summary.score, pages: report.summary.pages, viewports: report.summary.viewports, + ...(report.comparison + ? { + comparison: { + baseline: report.comparison.baseline, + counts: report.comparison.counts, + }, + } + : {}), ...(report.suppressions ? { suppressed: report.suppressions.total, diff --git a/dist/sarif.js.map b/dist/sarif.js.map index 4106ddb..58a49b9 100644 --- a/dist/sarif.js.map +++ b/dist/sarif.js.map @@ -1 +1 @@ -{"version":3,"file":"sarif.js","sourceRoot":"","sources":["../src/sarif.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"sarif.js","sourceRoot":"","sources":["../src/sarif.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AA6GnC,MAAM,YAAY,GAAG,+CAA+C,CAAC;AACrE,MAAM,eAAe,GAAG,yCAAyC,CAAC;AAElE,SAAS,eAAe,CAAC,QAAkB;IACzC,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,UAAU,CAAC;QAChB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,MAAc;IAChC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK;SACvB,OAAO,CAAC,mBAAmB,EAAE,CAAC,MAAM,EAAE,SAAiB,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;SACpF,OAAO,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,MAAM,CAAC,MAAc;IAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC;QACxB,gBAAgB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;QACtC,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE;QACvC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;QACzB,oBAAoB,EAAE,EAAE,KAAK,EAAE,eAAe,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE;QACtE,UAAU,EAAE;YACV,IAAI,EAAE,CAAC,QAAQ,EAAE,mBAAmB,EAAE,gBAAgB,CAAC;YACvD,eAAe,EAAE,IAAI,CAAC,eAAe;SACtC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CACf,OAAgB,EAChB,SAAiB,EACjB,WAAgC;IAEhC,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,IAAI,GAAG,CAAC;IAC/D,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,SAAS;QACT,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC;QACxC,OAAO,EAAE;YACP,IAAI,EAAE,OAAO,CAAC,OAAO;SACtB;QACD,SAAS,EAAE;YACT;gBACE,gBAAgB,EAAE;oBAChB,gBAAgB,EAAE;wBAChB,GAAG,EAAE,WAAW;qBACjB;iBACF;gBACD,gBAAgB,EAAE;oBAChB;wBACE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ;wBAC/B,kBAAkB,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ;wBAC7C,IAAI,EAAE,SAAS;qBAChB;iBACF;aACF;SACF;QACD,mBAAmB,EAAE;YACnB,gBAAgB,EAAE,OAAO,CAAC,WAAW;SACtC;QACD,GAAG,CAAC,WAAW;YACb,CAAC,CAAC;gBACE,YAAY,EAAE;oBACZ;wBACE,IAAI,EAAE,UAAmB;wBACzB,MAAM,EAAE,UAAmB;wBAC3B,aAAa,EAAE,WAAW,CAAC,MAAM;qBAClC;iBACF;aACF;YACH,CAAC,CAAC,EAAE,CAAC;QACP,UAAU,EAAE;YACV,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,QAAQ,EAAE;gBACR,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAC3B,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAC7B,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAC/B,iBAAiB,EAAE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,IAAI,CAAC;aAC3D;YACD,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAkB;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAa,CAAC;IAC/C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAC5C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC5B,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACtC,CAAC,CAAC,CACH,CAAC;IACF,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;YACnD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAClD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YACjE,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAElE,OAAO;QACL,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACJ;gBACE,IAAI,EAAE;oBACJ,MAAM,EAAE;wBACN,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI;wBACtB,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO;wBAC5B,cAAc,EAAE,eAAe;wBAC/B,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;qBAC3B;iBACF;gBACD,WAAW,EAAE;oBACX;wBACE,mBAAmB,EAAE,IAAI;wBACzB,YAAY,EAAE,SAAS,CAAC,WAAW,EAAE;wBACrC,UAAU,EAAE,OAAO,CAAC,WAAW,EAAE;wBACjC,UAAU,EAAE;4BACV,KAAK,EAAE,MAAM,CAAC,KAAK;4BACnB,MAAM,EAAE,MAAM,CAAC,MAAM;4BACrB,UAAU,EAAE,MAAM,CAAC,UAAU;yBAC9B;qBACF;iBACF;gBACD,OAAO;gBACP,UAAU,EAAE;oBACV,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK;oBAC3B,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK;oBAC3B,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS;oBACnC,GAAG,CAAC,MAAM,CAAC,UAAU;wBACnB,CAAC,CAAC;4BACE,UAAU,EAAE;gCACV,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ;gCACpC,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM;6BACjC;yBACF;wBACH,CAAC,CAAC,EAAE,CAAC;oBACP,GAAG,CAAC,MAAM,CAAC,YAAY;wBACrB,CAAC,CAAC;4BACE,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,KAAK;4BACrC,gBAAgB,EAAE,MAAM,CAAC,YAAY,CAAC,MAAM;yBAC7C;wBACH,CAAC,CAAC,EAAE,CAAC;iBACR;aACF;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAkB,EAAE,UAAkB;IAC3E,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5F,OAAO,UAAU,CAAC;AACpB,CAAC"} \ No newline at end of file diff --git a/dist/scanner.js b/dist/scanner.js index 7ead342..93ae3a5 100644 --- a/dist/scanner.js +++ b/dist/scanner.js @@ -273,10 +273,10 @@ async function toolVersion() { const packageJson = JSON.parse(await readFile(packageUrl, "utf8")); return typeof packageJson.version === "string" ? packageJson.version - : "0.3.0"; + : "0.4.0"; } catch { - return "0.3.0"; + return "0.4.0"; } } const INSTALLED_BROWSER_CANDIDATES = [ diff --git a/dist/types.d.ts b/dist/types.d.ts index 8eae8bc..e928a05 100644 --- a/dist/types.d.ts +++ b/dist/types.d.ts @@ -116,6 +116,24 @@ export interface SummaryCounts { score: number; suppressed?: number; } +export interface FindingComparisonSummary { + new: number; + existing: number; + resolved: number; +} +export interface ReportComparison { + baseline: { + source?: string; + schemaVersion: string; + toolVersion: string; + runId: string; + startedAt: string; + }; + counts: FindingComparisonSummary; + new: Finding[]; + existing: Finding[]; + resolved: Finding[]; +} export interface ScanReport { schemaVersion: "1.0"; tool: { @@ -129,6 +147,7 @@ export interface ScanReport { pages: PageResult[]; summary: SummaryCounts; suppressions?: SuppressionAudit; + comparison?: ReportComparison; options: { viewports: ViewportSpec[]; paths: string[]; diff --git a/dist/types.d.ts.map b/dist/types.d.ts.map index 7572c55..2e09502 100644 --- a/dist/types.d.ts.map +++ b/dist/types.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/types.js.map b/dist/types.js.map index 071f735..5017153 100644 --- a/dist/types.js.map +++ b/dist/types.js.map @@ -1 +1 @@ -{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAyKA,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,QAAQ,EAAE,EAAE;IACZ,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,CAAC;CACR,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAA6B;IACrD,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,CAAC;CACR,CAAC"} \ No newline at end of file +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA8LA,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,QAAQ,EAAE,EAAE;IACZ,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,CAAC;CACR,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAA6B;IACrD,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,CAAC;CACR,CAAC"} \ No newline at end of file diff --git a/docs/recipes.md b/docs/recipes.md index 8f9eed6..cb99d61 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -3,7 +3,7 @@ Copy one of these workflows to `.github/workflows/layoutscope.yml`. They target GitHub.com-hosted `ubuntu-latest` runners. Each recipe starts the built site on a loopback address, waits until it is reachable, and runs the released -LayoutScope Action at `v0.3.0`. +LayoutScope Action at `v0.4.0`. The Action scans desktop and mobile viewports and fails on `error` findings by default. When findings meet the failure threshold, it still uploads the @@ -49,7 +49,7 @@ jobs: done cat /tmp/vite.log exit 1 - - uses: LyraZeta/layoutscope@v0.3.0 + - uses: LyraZeta/layoutscope@v0.4.0 with: target: http://127.0.0.1:4173 paths: / @@ -95,7 +95,7 @@ jobs: done cat /tmp/next.log exit 1 - - uses: LyraZeta/layoutscope@v0.3.0 + - uses: LyraZeta/layoutscope@v0.4.0 with: target: http://127.0.0.1:3000 paths: / @@ -136,7 +136,7 @@ jobs: done cat /tmp/static-site.log exit 1 - - uses: LyraZeta/layoutscope@v0.3.0 + - uses: LyraZeta/layoutscope@v0.4.0 with: target: http://127.0.0.1:4173 paths: / @@ -165,3 +165,80 @@ with: Set `fail-on: never` for an initial audit, then remove it to restore the default `error` threshold once the existing findings have been reviewed. + +## Pull-request baseline gate + +This workflow keeps the latest successful main-branch report as an artifact. +Pull requests download that report when one exists and fail only on new +findings. The first run works without a baseline and publishes the initial +inventory with `fail-on: never`. + +Keep the build, routes, viewports, wait conditions, and config identical between +main and pull requests. A comparison is meaningful only when both reports scan +the same surface. + +```yaml +name: LayoutScope PR gate + +on: + push: + branches: [main] + pull_request: + +permissions: + actions: read + contents: read + +jobs: + visual-lint: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run build + - name: Start app + run: npm run preview -- --host 127.0.0.1 --port 4173 >/tmp/app.log 2>&1 & + - name: Wait for app + run: | + for attempt in {1..40}; do + curl --fail --silent --max-time 2 http://127.0.0.1:4173/ \ + >/dev/null && exit 0 + sleep 0.5 + done + cat /tmp/app.log + exit 1 + - name: Find latest main-branch report + if: github.event_name == 'pull_request' + id: baseline + env: + GH_TOKEN: ${{ github.token }} + REPOSITORY: ${{ github.repository }} + run: | + artifact_id="$(gh api \ + "repos/$REPOSITORY/actions/artifacts?name=layoutscope-main-report&per_page=100" \ + --jq '[.artifacts[] | select(.expired == false)] | sort_by(.created_at) | reverse | .[0].id // empty')" + if [[ -n "$artifact_id" ]]; then + gh api "repos/$REPOSITORY/actions/artifacts/$artifact_id/zip" > baseline.zip + unzip -q baseline.zip -d .layoutscope-main + baseline_path="$(find .layoutscope-main -type f -name report.json -print -quit)" + [[ -n "$baseline_path" ]] && echo "path=$baseline_path" >> "$GITHUB_OUTPUT" + fi + - uses: LyraZeta/layoutscope@v0.4.0 + with: + target: http://127.0.0.1:4173 + paths: / + viewports: desktop,mobile + compare: ${{ steps.baseline.outputs.path }} + fail-on: ${{ steps.baseline.outputs.path && 'error' || 'never' }} + artifact-name: ${{ github.event_name == 'push' && 'layoutscope-main-report' || 'layoutscope-pr-report' }} +``` + +The baseline is a finding inventory, not a pixel reference image. LayoutScope +still analyzes the current DOM, geometry, styles, and pixels independently on +every run. The comparison only classifies stable finding identities after the +scan. diff --git a/package.json b/package.json index 2e6ca1c..5d8723a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "layoutscope", - "version": "0.3.0", + "version": "0.4.0", "description": "Baseline-free visual linting for web interfaces. Catch what users see before they do.", "type": "module", "bin": { diff --git a/src/cli.ts b/src/cli.ts index 718effa..ca7dba4 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -8,9 +8,15 @@ import { promisify } from "node:util"; import chalk from "chalk"; import { Command, Option } from "commander"; +import { compareReports, loadBaselineReport } from "./compare.js"; import { loadLayoutScopeConfig } from "./config.js"; import { scan } from "./scanner.js"; -import { SEVERITY_RANK, type ScanOptions, type Severity } from "./types.js"; +import { + SEVERITY_RANK, + type Finding, + type ScanOptions, + type Severity, +} from "./types.js"; import { DEFAULT_VIEWPORTS, parseViewportList } from "./utils.js"; const execFileAsync = promisify(execFile); @@ -18,6 +24,7 @@ const execFileAsync = promisify(execFile); interface CliOptions { config?: string; autoConfig?: boolean; + compare?: string; output: string; viewport?: string[]; path?: string[]; @@ -61,6 +68,36 @@ function severityColor(severity: Severity, text: string): string { return chalk.blue(text); } +function countFindings(findings: Finding[]): Record { + const counts: Record = { + critical: 0, + error: 0, + warning: 0, + info: 0, + }; + for (const finding of findings) counts[finding.severity] += 1; + return counts; +} + +function findingsForPage( + findings: Finding[], + page: Awaited>["pages"][number], +): Finding[] { + return findings.filter( + (finding) => + finding.pageUrl === page.pageUrl && + finding.pagePath === page.pagePath && + finding.viewport.name === page.viewport.name && + finding.viewport.width === page.viewport.width && + finding.viewport.height === page.viewport.height && + (finding.viewport.deviceScaleFactor ?? 1) === + (page.viewport.deviceScaleFactor ?? 1) && + (finding.viewport.isMobile ?? false) === + (page.viewport.isMobile ?? false) && + (finding.viewport.hasTouch ?? false) === (page.viewport.hasTouch ?? false), + ); +} + function printReport( report: Awaited>, artifactPaths: { htmlPath: string; jsonPath: string; sarifPath: string }, @@ -77,6 +114,14 @@ function printReport( process.stdout.write( `${report.pages.length} renders · ${report.durationMs} ms · score ${scoreText}\n\n`, ); + if (report.comparison) { + const newCount = String(report.comparison.counts.new); + process.stdout.write( + `${report.comparison.counts.new ? chalk.red.bold(newCount) : chalk.green.bold(newCount)} new ` + + `${chalk.blue.bold(String(report.comparison.counts.existing))} existing ` + + `${chalk.green(String(report.comparison.counts.resolved))} resolved\n\n`, + ); + } if (report.suppressions) { const source = report.suppressions.source ? ` from ${report.suppressions.source}` @@ -87,34 +132,46 @@ function printReport( ); } - if (report.summary.total === 0) { + const displayedFindings = report.comparison + ? report.comparison.new + : report.pages.flatMap((page) => page.findings); + + if (displayedFindings.length === 0) { const message = report.suppressions?.total - ? "No active visual findings; review the suppression audit." - : "No visual findings detected."; + ? report.comparison + ? "No new visual findings; review the suppression audit." + : "No active visual findings; review the suppression audit." + : report.comparison + ? "No new visual findings detected." + : "No visual findings detected."; process.stdout.write(`${chalk.green.bold("PASS")} ${message}\n`); } else { + const counts = countFindings(displayedFindings); process.stdout.write( - `${severityColor("critical", String(report.summary.critical))} critical ` + - `${severityColor("error", String(report.summary.error))} errors ` + - `${severityColor("warning", String(report.summary.warning))} warnings ` + - `${chalk.blue(String(report.summary.info))} info\n\n`, + `${severityColor("critical", String(counts.critical))} critical ` + + `${severityColor("error", String(counts.error))} errors ` + + `${severityColor("warning", String(counts.warning))} warnings ` + + `${chalk.blue(String(counts.info))} info\n\n`, ); for (const page of report.pages) { - if (page.findings.length === 0) continue; + const findings = report.comparison + ? findingsForPage(displayedFindings, page) + : page.findings; + if (findings.length === 0) continue; process.stdout.write( `${chalk.bold(page.pagePath)} ${chalk.dim(`${page.viewport.name} ${page.viewport.width}x${page.viewport.height}`)}\n`, ); - for (const finding of page.findings.slice(0, 12)) { + for (const finding of findings.slice(0, 12)) { const badge = severityColor(finding.severity, finding.ruleId); process.stdout.write(` ${badge} ${finding.title}\n`); process.stdout.write( ` ${finding.evidence.selector}${finding.evidence.text ? chalk.dim(` · ${finding.evidence.text.slice(0, 72)}`) : ""}\n`, ); } - if (page.findings.length > 12) + if (findings.length > 12) process.stdout.write( chalk.dim( - ` ... ${page.findings.length - 12} more in the HTML report\n`, + ` ... ${findings.length - 12} more in the HTML report\n`, ), ); process.stdout.write("\n"); @@ -144,8 +201,11 @@ function shouldFail( ): boolean { if (threshold === "never") return false; const minimum = SEVERITY_RANK[threshold]; - return report.pages.some((page) => - page.findings.some((finding) => SEVERITY_RANK[finding.severity] >= minimum), + const findings = report.comparison + ? report.comparison.new + : report.pages.flatMap((page) => page.findings); + return findings.some( + (finding) => SEVERITY_RANK[finding.severity] >= minimum, ); } @@ -154,6 +214,10 @@ async function loadReportWriter(): Promise { } async function main(target: string, cli: CliOptions): Promise { + const baselineSource = cli.compare; + const baseline = baselineSource + ? await loadBaselineReport(baselineSource) + : undefined; const loadedConfig = await loadLayoutScopeConfig({ ...(cli.config ? { configPath: cli.config } : {}), autoDiscover: cli.autoConfig !== false, @@ -197,6 +261,9 @@ async function main(target: string, cli: CliOptions): Promise { }; const report = await scan(scanOptions); + if (baseline && baselineSource) { + report.comparison = compareReports(report, baseline, { baselineSource }); + } const { writeReportArtifacts } = await loadReportWriter(); const artifacts = await writeReportArtifacts(report, outputDir, { canonicalUrl: cli.canonicalUrl, @@ -231,6 +298,10 @@ program "--no-auto-config", "disable automatic config discovery (an explicit --config still loads)", ) + .option( + "--compare ", + "compare against a previous LayoutScope JSON report", + ) .option("-o, --output ", "report output directory", ".layoutscope") .option( "-v, --viewport ", @@ -277,7 +348,7 @@ program .choices(["text", "json"]) .default("text"), ) - .version("0.3.0") + .version("0.4.0") .showHelpAfterError() .action((target: string, options: CliOptions) => main(target, options)); @@ -285,7 +356,7 @@ program.parseAsync().catch(async (error: unknown) => { const message = error instanceof Error ? error.message : String(error); if (/Executable doesn't exist|browserType\.launch/i.test(message)) { process.stderr.write( - `${chalk.red.bold("Browser unavailable.")} Run ${chalk.cyan("npx --yes --package github:LyraZeta/layoutscope#v0.3.0 playwright-core install chromium")} once, or pass ${chalk.cyan("--browser chrome")} / ${chalk.cyan("--browser msedge")} to use an installed browser.\n`, + `${chalk.red.bold("Browser unavailable.")} Run ${chalk.cyan("npx --yes --package github:LyraZeta/layoutscope#v0.4.0 playwright-core install chromium")} once, or pass ${chalk.cyan("--browser chrome")} / ${chalk.cyan("--browser msedge")} to use an installed browser.\n`, ); } else { process.stderr.write( diff --git a/src/compare.ts b/src/compare.ts new file mode 100644 index 0000000..15b01a5 --- /dev/null +++ b/src/compare.ts @@ -0,0 +1,461 @@ +import { readFile } from "node:fs/promises"; +import path from "node:path"; + +import type { + Finding, + ReportComparison, + RuleId, + ScanReport, + Severity, +} from "./types.js"; + +export interface CompareReportOptions { + baselineSource?: string; +} + +const RULE_IDS = new Set([ + "LS001", + "LS002", + "LS003", + "LS004", + "LS005", + "LS006", + "LS007", + "LS008", + "LS009", + "LS010", +]); +const SEVERITIES = new Set([ + "critical", + "error", + "warning", + "info", +]); + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function fail(source: string, property: string, expectation: string): never { + throw new Error(`${source}.${property} ${expectation}.`); +} + +function requireRecord( + value: unknown, + source: string, + property: string, +): Record { + if (!isRecord(value)) fail(source, property, "must be an object"); + return value; +} + +function requireArray( + value: unknown, + source: string, + property: string, +): unknown[] { + if (!Array.isArray(value)) fail(source, property, "must be an array"); + return value; +} + +function requireString( + value: unknown, + source: string, + property: string, +): string { + if (typeof value !== "string" || !value.trim()) { + fail(source, property, "must be a non-empty string"); + } + return value; +} + +function requireBoolean( + value: unknown, + source: string, + property: string, +): boolean { + if (typeof value !== "boolean") fail(source, property, "must be a boolean"); + return value; +} + +function requireFiniteNumber( + value: unknown, + source: string, + property: string, +): number { + if (typeof value !== "number" || !Number.isFinite(value)) { + fail(source, property, "must be a finite number"); + } + return value; +} + +function requireNonNegativeNumber( + value: unknown, + source: string, + property: string, +): number { + const number = requireFiniteNumber(value, source, property); + if (number < 0) fail(source, property, "must be zero or greater"); + return number; +} + +function requirePositiveNumber( + value: unknown, + source: string, + property: string, +): number { + const number = requireFiniteNumber(value, source, property); + if (number <= 0) fail(source, property, "must be greater than zero"); + return number; +} + +function requireOptionalString( + value: unknown, + source: string, + property: string, +): void { + if (value !== undefined && typeof value !== "string") { + fail(source, property, "must be a string"); + } +} + +function requireOptionalBoolean( + value: unknown, + source: string, + property: string, +): void { + if (value !== undefined) requireBoolean(value, source, property); +} + +function validateViewport( + value: unknown, + source: string, + property: string, +): void { + const viewport = requireRecord(value, source, property); + requireString(viewport.name, source, `${property}.name`); + requirePositiveNumber(viewport.width, source, `${property}.width`); + requirePositiveNumber(viewport.height, source, `${property}.height`); + if (viewport.deviceScaleFactor !== undefined) { + requirePositiveNumber( + viewport.deviceScaleFactor, + source, + `${property}.deviceScaleFactor`, + ); + } + requireOptionalBoolean(viewport.isMobile, source, `${property}.isMobile`); + requireOptionalBoolean(viewport.hasTouch, source, `${property}.hasTouch`); +} + +function validateRect( + value: unknown, + source: string, + property: string, +): void { + const rect = requireRecord(value, source, property); + for (const key of [ + "x", + "y", + "width", + "height", + "top", + "right", + "bottom", + "left", + ]) { + requireFiniteNumber(rect[key], source, `${property}.${key}`); + } +} + +function validateEvidence( + value: unknown, + source: string, + property: string, +): void { + const evidence = requireRecord(value, source, property); + requireString(evidence.selector, source, `${property}.selector`); + requireString(evidence.tag, source, `${property}.tag`); + requireOptionalString(evidence.text, source, `${property}.text`); + requireOptionalString(evidence.role, source, `${property}.role`); + validateRect(evidence.rect, source, `${property}.rect`); + requireOptionalString( + evidence.relatedSelector, + source, + `${property}.relatedSelector`, + ); + if (evidence.relatedRect !== undefined) { + validateRect(evidence.relatedRect, source, `${property}.relatedRect`); + } + if (evidence.details !== undefined) { + const details = requireRecord( + evidence.details, + source, + `${property}.details`, + ); + for (const [key, detail] of Object.entries(details)) { + if ( + detail !== null && + typeof detail !== "string" && + typeof detail !== "number" && + typeof detail !== "boolean" + ) { + fail( + source, + `${property}.details.${key}`, + "must be a string, number, boolean, or null", + ); + } + if (typeof detail === "number" && !Number.isFinite(detail)) { + fail(source, `${property}.details.${key}`, "must be a finite number"); + } + } + } +} + +function validateFinding( + value: unknown, + source: string, + property: string, +): void { + const finding = requireRecord(value, source, property); + requireString(finding.id, source, `${property}.id`); + const ruleId = requireString(finding.ruleId, source, `${property}.ruleId`); + if (!RULE_IDS.has(ruleId as RuleId)) { + fail(source, `${property}.ruleId`, "must be a supported LayoutScope rule ID"); + } + const severity = requireString( + finding.severity, + source, + `${property}.severity`, + ); + if (!SEVERITIES.has(severity as Severity)) { + fail( + source, + `${property}.severity`, + "must be critical, error, warning, or info", + ); + } + requireString(finding.title, source, `${property}.title`); + requireString(finding.message, source, `${property}.message`); + requireString(finding.help, source, `${property}.help`); + requireString(finding.pageUrl, source, `${property}.pageUrl`); + requireString(finding.pagePath, source, `${property}.pagePath`); + validateViewport(finding.viewport, source, `${property}.viewport`); + validateEvidence(finding.evidence, source, `${property}.evidence`); + requireString(finding.fingerprint, source, `${property}.fingerprint`); +} + +function validatePage( + value: unknown, + source: string, + property: string, +): void { + const page = requireRecord(value, source, property); + requireString(page.pageUrl, source, `${property}.pageUrl`); + requireString(page.pagePath, source, `${property}.pagePath`); + if (typeof page.title !== "string") { + fail(source, `${property}.title`, "must be a string"); + } + validateViewport(page.viewport, source, `${property}.viewport`); + const findings = requireArray(page.findings, source, `${property}.findings`); + findings.forEach((finding, index) => + validateFinding(finding, source, `${property}.findings[${index}]`), + ); + if (page.suppressedCount !== undefined) { + requireNonNegativeNumber( + page.suppressedCount, + source, + `${property}.suppressedCount`, + ); + } + const metrics = requireRecord(page.metrics, source, `${property}.metrics`); + for (const key of [ + "documentWidth", + "documentHeight", + "viewportWidth", + "viewportHeight", + "elementsInspected", + "loadTimeMs", + ]) { + requireNonNegativeNumber(metrics[key], source, `${property}.metrics.${key}`); + } + if (typeof page.screenshotPath !== "string") { + fail(source, `${property}.screenshotPath`, "must be a string"); + } + if (typeof page.annotatedScreenshotPath !== "string") { + fail(source, `${property}.annotatedScreenshotPath`, "must be a string"); + } +} + +function validateSummary( + value: unknown, + source: string, + property: string, +): void { + const summary = requireRecord(value, source, property); + for (const key of [ + "critical", + "error", + "warning", + "info", + "total", + "pages", + "viewports", + "score", + ]) { + requireNonNegativeNumber(summary[key], source, `${property}.${key}`); + } + if (summary.suppressed !== undefined) { + requireNonNegativeNumber( + summary.suppressed, + source, + `${property}.suppressed`, + ); + } +} + +function validateOptions( + value: unknown, + source: string, + property: string, +): void { + const options = requireRecord(value, source, property); + const viewports = requireArray( + options.viewports, + source, + `${property}.viewports`, + ); + viewports.forEach((viewport, index) => + validateViewport(viewport, source, `${property}.viewports[${index}]`), + ); + const paths = requireArray(options.paths, source, `${property}.paths`); + paths.forEach((pagePath, index) => + requireString(pagePath, source, `${property}.paths[${index}]`), + ); + requireNonNegativeNumber(options.waitMs, source, `${property}.waitMs`); + requireOptionalString(options.readySelector, source, `${property}.readySelector`); +} + +/** Validate a JSON value as a LayoutScope report that can be used as a baseline. */ +export function validateBaselineReport( + value: unknown, + source = "Baseline report", +): asserts value is ScanReport { + const report = requireRecord(value, source, "root"); + if (report.schemaVersion !== "1.0") { + fail(source, "schemaVersion", 'must be the supported value "1.0"'); + } + const tool = requireRecord(report.tool, source, "tool"); + if (tool.name !== "layoutscope") { + fail(source, "tool.name", 'must be "layoutscope"'); + } + requireString(tool.version, source, "tool.version"); + requireString(report.runId, source, "runId"); + requireString(report.startedAt, source, "startedAt"); + requireNonNegativeNumber(report.durationMs, source, "durationMs"); + requireString(report.target, source, "target"); + const pages = requireArray(report.pages, source, "pages"); + pages.forEach((page, index) => + validatePage(page, source, `pages[${index}]`), + ); + validateSummary(report.summary, source, "summary"); + validateOptions(report.options, source, "options"); +} + +/** Load and validate a LayoutScope JSON report for use as a comparison baseline. */ +export async function loadBaselineReport(reportPath: string): Promise { + const absolutePath = path.resolve(reportPath); + let contents: string; + try { + contents = await readFile(absolutePath, "utf8"); + } catch (error) { + const detail = error instanceof Error ? error.message : String(error); + throw new Error(`Unable to read baseline report "${absolutePath}": ${detail}`); + } + + let parsed: unknown; + try { + parsed = JSON.parse(contents) as unknown; + } catch (error) { + const detail = error instanceof Error ? error.message : String(error); + throw new Error( + `Baseline report "${absolutePath}" contains invalid JSON: ${detail}`, + ); + } + validateBaselineReport(parsed, `Baseline report "${absolutePath}"`); + return parsed; +} + +/** Build the stable identity used to match one active finding across reports. */ +export function findingIdentity(finding: Finding): string { + const viewport = finding.viewport; + return JSON.stringify([ + finding.pagePath, + viewport.name, + viewport.width, + viewport.height, + viewport.deviceScaleFactor ?? 1, + viewport.isMobile ?? false, + viewport.hasTouch ?? false, + finding.ruleId, + finding.fingerprint, + ]); +} + +function activeFindings(report: ScanReport): Finding[] { + return report.pages.flatMap((page) => page.findings); +} + +/** Compare active findings in a current report with a validated baseline. */ +export function compareReports( + current: ScanReport, + baseline: unknown, + options: CompareReportOptions = {}, +): ReportComparison { + validateBaselineReport(baseline); + + const baselineFindings = activeFindings(baseline); + const baselineBuckets = new Map(); + for (const [index, finding] of baselineFindings.entries()) { + const identity = findingIdentity(finding); + const bucket = baselineBuckets.get(identity) ?? []; + bucket.push(index); + baselineBuckets.set(identity, bucket); + } + + const newFindings: Finding[] = []; + const existingFindings: Finding[] = []; + const matchedBaselineIndexes = new Set(); + for (const finding of activeFindings(current)) { + const bucket = baselineBuckets.get(findingIdentity(finding)); + if (!bucket?.length) { + newFindings.push(finding); + continue; + } + existingFindings.push(finding); + const baselineIndex = bucket.shift(); + if (baselineIndex !== undefined) matchedBaselineIndexes.add(baselineIndex); + } + + const resolvedFindings = baselineFindings.filter( + (_finding, index) => !matchedBaselineIndexes.has(index), + ); + + return { + baseline: { + ...(options.baselineSource ? { source: options.baselineSource } : {}), + schemaVersion: baseline.schemaVersion, + toolVersion: baseline.tool.version, + runId: baseline.runId, + startedAt: baseline.startedAt, + }, + counts: { + new: newFindings.length, + existing: existingFindings.length, + resolved: resolvedFindings.length, + }, + new: newFindings, + existing: existingFindings, + resolved: resolvedFindings, + }; +} diff --git a/src/report.ts b/src/report.ts index 25fa959..27ad334 100644 --- a/src/report.ts +++ b/src/report.ts @@ -465,13 +465,13 @@ const REPORT_STYLES = String.raw` .topbar{min-height:68px;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:12px clamp(18px,3vw,44px);background:var(--surface);border-bottom:1px solid var(--border)}.brand{display:flex;align-items:center;gap:11px;flex:none}.brand-mark{position:relative;width:28px;height:28px;border:2px solid var(--brand);border-radius:6px}.brand-mark:before,.brand-mark:after{content:"";position:absolute;background:var(--brand);border-radius:1px}.brand-mark:before{width:12px;height:3px;left:6px;top:6px}.brand-mark:after{width:3px;height:9px;left:6px;top:12px}.brand-name{font-size:18px;font-weight:750}.brand-version,.run-sub{color:var(--subtle);font-size:12px}.project-link{min-height:32px;display:inline-flex;align-items:center;margin-left:4px;padding:5px 9px;border:1px solid var(--border);border-radius:5px;color:var(--text);font-size:12px;font-weight:650;text-decoration:none}.project-link:hover{border-color:var(--strong);background:var(--muted)}.run{text-align:right;min-width:0}.target{display:block;max-width:min(58vw,760px);overflow:hidden;color:var(--text);font-weight:650;text-overflow:ellipsis;text-decoration:none;white-space:nowrap} .layout{width:min(1680px,100%);margin:auto;padding:28px clamp(16px,3vw,44px) 56px;display:grid;grid-template-columns:244px minmax(0,1fr);gap:28px;align-items:start}.sidebar{position:sticky;top:18px;display:grid;gap:16px}.score,.filters{background:var(--surface);border:1px solid var(--border);border-radius:8px}.score{padding:20px}.eyebrow,.filter-title{color:var(--subtle);font-size:11px;font-weight:750;text-transform:uppercase}.score-row{display:flex;align-items:flex-end;gap:5px;margin:3px 0 4px}.score-value{font-size:54px;line-height:1;font-weight:760}.score-total{padding-bottom:6px;color:var(--subtle);font-size:16px}.score.excellent .score-value{color:var(--brand2)}.score.good .score-value{color:var(--info)}.score.fair .score-value{color:var(--warning)}.score.poor .score-value{color:var(--critical)}.score p{margin:0;color:var(--subtle)} .filters{padding:16px}.filters h2{margin:0 0 14px;font-size:14px}.filter-group{padding:14px 0;border-top:1px solid var(--border)}.filter-group:first-of-type{border-top:0;padding-top:0}.filter-title{display:block;margin-bottom:8px}.severity-options{display:grid;gap:3px}.severity-filter{position:relative;min-height:34px;display:grid;grid-template-columns:14px 1fr auto;align-items:center;gap:9px;padding:5px 7px;border-radius:5px;cursor:pointer;text-transform:capitalize;color:var(--severity)}.severity-filter:hover{background:var(--muted)}.severity-filter input{position:absolute;opacity:0}.check{width:13px;height:13px;border:1px solid currentColor;border-radius:3px}.severity-filter input:checked+.check{box-shadow:inset 0 0 0 3px var(--surface);background:currentColor}.severity-filter span:nth-of-type(2),.severity-filter strong{color:var(--text)}.severity-filter strong{font-size:12px}.severity-critical{--severity:var(--critical)}.severity-error{--severity:var(--error)}.severity-warning{--severity:var(--warning)}.severity-info{--severity:var(--info)}.filter-select{width:100%;min-height:38px;padding:7px 9px;border:1px solid var(--strong);border-radius:5px;background:var(--raised)}.overlay-toggle{display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:pointer}.switch{position:relative;width:34px;height:20px;flex:none}.switch input{position:absolute;opacity:0}.switch span{display:block;width:100%;height:100%;border-radius:10px;background:var(--strong)}.switch span:after{content:"";position:absolute;width:14px;height:14px;top:3px;left:3px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.3);transition:transform .14s}.switch input:checked+span{background:var(--brand)}.switch input:checked+span:after{transform:translateX(14px)}.reset{width:100%;min-height:36px;border:1px solid var(--strong);border-radius:5px;background:var(--surface);cursor:pointer;font-weight:650}.reset:hover{background:var(--muted)} -main{min-width:0}.summary{display:grid;grid-template-columns:repeat(4,minmax(100px,1fr));gap:10px}.summary button{position:relative;min-height:78px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;padding:12px 14px 12px 17px;border:1px solid var(--border);border-radius:7px;background:var(--surface);cursor:pointer;text-align:left;overflow:hidden}.summary button:before{content:"";position:absolute;inset:0 auto 0 0;width:4px;background:var(--severity)}.summary button:hover{border-color:var(--strong)}.summary strong{font-size:24px;line-height:1.1}.summary span{color:var(--subtle);text-transform:capitalize}.results-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin:28px 0 12px}.results-head h1{margin:0;font-size:20px}.results-head p{margin:0;color:var(--subtle)}.empty{padding:56px 24px;border:1px dashed var(--strong);border-radius:8px;background:var(--surface);text-align:center}.empty strong{display:block;font-size:17px}.empty span{color:var(--subtle)} +main{min-width:0}.summary{display:grid;grid-template-columns:repeat(4,minmax(100px,1fr));gap:10px}.summary button{position:relative;min-height:78px;display:flex;flex-direction:column;justify-content:center;align-items:flex-start;padding:12px 14px 12px 17px;border:1px solid var(--border);border-radius:7px;background:var(--surface);cursor:pointer;text-align:left;overflow:hidden}.summary button:before{content:"";position:absolute;inset:0 auto 0 0;width:4px;background:var(--severity)}.summary button:hover{border-color:var(--strong)}.summary strong{font-size:24px;line-height:1.1}.summary span{color:var(--subtle);text-transform:capitalize}.comparison{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-top:18px;padding:15px 18px;border:1px solid var(--border);border-radius:8px;background:var(--surface)}.comparison-title{min-width:0}.comparison h2{margin:2px 0 1px;font-size:17px}.comparison p{margin:0;color:var(--subtle);font-size:12px;overflow-wrap:anywhere}.comparison dl{display:grid;grid-template-columns:repeat(3,minmax(76px,1fr));min-width:min(100%,300px);margin:0}.comparison dl>div{padding:2px 14px;border-left:1px solid var(--border)}.comparison dt{color:var(--subtle);font-size:11px;text-transform:uppercase}.comparison dd{margin:0;font-size:22px;font-weight:750}.comparison-new dd{color:var(--error)}.comparison-resolved dd{color:var(--brand2)}.results-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;margin:28px 0 12px}.results-head h1{margin:0;font-size:20px}.results-head p{margin:0;color:var(--subtle)}.empty{padding:56px 24px;border:1px dashed var(--strong);border-radius:8px;background:var(--surface);text-align:center}.empty strong{display:block;font-size:17px}.empty span{color:var(--subtle)} .page{margin-top:18px;border:1px solid var(--border);border-radius:8px;background:var(--surface);box-shadow:var(--shadow);overflow:hidden}.page-head{display:flex;justify-content:space-between;align-items:center;gap:18px;padding:16px 18px;border-bottom:1px solid var(--border)}.page-id{min-width:0;display:flex;align-items:center;gap:12px}.page-id>span{color:var(--subtle);font:650 12px/1 "SFMono-Regular",Consolas,monospace}.page-id h2{margin:0;font-size:16px;overflow-wrap:anywhere}.page-id a{display:block;max-width:min(58vw,680px);margin-top:2px;overflow:hidden;color:var(--subtle);font-size:12px;text-overflow:ellipsis;white-space:nowrap}.viewport{flex:none;padding:5px 8px;border:1px solid var(--border);border-radius:5px;background:var(--muted);text-align:right;font-size:11px}.viewport span{display:block;color:var(--subtle)}.viewport strong{font-size:12px}.metrics{display:flex;flex-wrap:wrap;gap:7px 18px;padding:9px 18px;border-bottom:1px solid var(--border);color:var(--subtle);font-size:11px}.metrics strong{color:var(--text)}.workbench{display:grid;grid-template-columns:minmax(0,1.45fr) minmax(310px,.75fr);min-height:420px}.visual,.findings{min-width:0}.visual{border-right:1px solid var(--border)}.panel-head{min-height:47px;display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:13px 15px;border-bottom:1px solid var(--border)}.panel-head h3{margin:0;font-size:13px}.panel-head span{color:var(--subtle);font-size:11px} .shot-scroll{position:relative;max-height:70vh;min-height:320px;overflow:auto;overscroll-behavior:contain;background:var(--muted)}.shot-stage{position:relative;width:100%;line-height:0}.shot-stage img{display:block;width:100%;height:auto;min-height:160px}.markers{position:absolute;inset:0;pointer-events:none}.marker{position:absolute;z-index:2;min-width:20px;min-height:20px;padding:0;border:2px solid var(--severity);border-radius:3px;background:color-mix(in srgb,var(--severity) 15%,transparent);box-shadow:0 0 0 1px rgba(255,255,255,.8),0 2px 6px rgba(0,0,0,.25);color:#fff;cursor:pointer;line-height:1;pointer-events:auto}.marker>span{position:absolute;top:-12px;left:-2px;min-width:19px;height:19px;display:grid;place-items:center;padding:0 3px;border-radius:3px 3px 3px 0;background:var(--severity);color:#fff;font-size:10px;font-weight:800}.marker-related{z-index:1;border-style:dashed;background:transparent}.marker-related>span{display:none}.marker:hover,.marker.is-active{z-index:4;box-shadow:0 0 0 3px color-mix(in srgb,var(--severity) 36%,transparent),0 2px 8px rgba(0,0,0,.3)}body.overlays-hidden .markers{display:none}.image-error,.missing{min-height:320px;display:grid;align-content:center;justify-items:center;gap:4px;padding:24px;color:var(--subtle);text-align:center;line-height:1.5}.image-error strong,.missing strong{color:var(--text)}.image-error span{max-width:100%;overflow-wrap:anywhere;font-size:11px} .finding-list{max-height:calc(70vh + 47px);overflow:auto;overscroll-behavior:contain}.finding{--severity:var(--info);padding:14px 15px 15px;border-bottom:1px solid var(--border);border-left:3px solid transparent;scroll-margin:20px}.finding:last-child{border-bottom:0}.finding.is-active{border-left-color:var(--severity);background:color-mix(in srgb,var(--severity) 7%,var(--surface))}.finding-focus{width:100%;display:grid;grid-template-columns:24px minmax(0,1fr) 18px;align-items:start;gap:9px;padding:0;border:0;background:transparent;cursor:pointer;text-align:left}.finding-number{width:22px;height:22px;display:grid;place-items:center;border-radius:4px;background:var(--severity);color:#fff;font-size:11px;font-weight:800}.finding-title{display:block;line-height:1.35}.finding-tags{display:flex;align-items:center;gap:7px;margin-top:4px}.finding-tags b{color:var(--severity);font-size:10px;text-transform:uppercase}.finding-tags code{padding:1px 4px;border-radius:3px;background:var(--muted);color:var(--subtle);font-size:10px}.locate{color:var(--subtle);font-size:17px}.message{margin:10px 0 8px 33px;line-height:1.55}.selector{margin-left:33px;color:var(--subtle);overflow-wrap:anywhere}.selector>code{padding:2px 4px;border-radius:3px;background:var(--muted);color:var(--text)}.related{display:block;margin-top:5px;font-size:11px}.details{margin:10px 0 0 33px;color:var(--subtle);font-size:11px}.details summary{cursor:pointer;font-weight:650}.details dl{margin:7px 0 0}.detail-row{display:grid;grid-template-columns:minmax(70px,.45fr) minmax(0,1fr);gap:8px;padding:3px 0}.detail-row dt,.detail-row dd{overflow-wrap:anywhere}.detail-row dd{margin:0;color:var(--text)}.help{margin:11px 0 0 33px;padding:8px 9px;border-radius:5px;background:var(--muted);color:var(--subtle);font-size:11px}.help strong{color:var(--text)}.clean{min-height:320px;display:grid;place-content:center;text-align:center}.clean strong{font-size:16px}.clean span{color:var(--subtle)}.suppression-audit{margin-top:18px;border:1px solid var(--border);border-radius:8px;background:var(--surface);overflow:hidden}.suppression-title{display:flex;align-items:end;justify-content:space-between;gap:18px;padding:15px 18px;background:var(--muted);border-bottom:1px solid var(--border)}.suppression-title h2{margin:2px 0 0;font-size:16px}.suppression-title p{margin:0;color:var(--subtle);font-size:12px}.suppression-entry{padding:13px 18px;border-bottom:1px solid var(--border)}.suppression-entry:last-child{border-bottom:0}.suppression-head{display:flex;justify-content:space-between;gap:16px}.suppression-head span{min-width:0;overflow-wrap:anywhere}.suppression-head strong{flex:none;font-size:12px}.suppression-entry>p{margin:5px 0;color:var(--subtle)}.suppression-entry details{margin-top:7px;color:var(--subtle);font-size:11px}.suppression-entry summary{cursor:pointer}.suppression-entry ul{margin:7px 0 0;padding-left:20px}.suppression-entry li{margin:3px 0;overflow-wrap:anywhere}.unused-suppression{font-style:italic}.report-footer{display:flex;justify-content:space-between;gap:18px;margin-top:28px;padding-top:18px;border-top:1px solid var(--border);color:var(--subtle);font-size:11px} @media(max-width:1180px){.workbench{grid-template-columns:1fr}.visual{border-right:0;border-bottom:1px solid var(--border)}.finding-list{max-height:none}} @media(max-width:820px){.topbar{align-items:flex-start}.run{text-align:left}.target{max-width:55vw}.layout{grid-template-columns:1fr;padding-top:18px}.sidebar{position:static;grid-template-columns:minmax(150px,.45fr) minmax(0,1fr)}.filters{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 15px}.filters h2{grid-column:1/-1}.filter-group{border-top:1px solid var(--border)}} -@media(max-width:560px){.topbar{display:block}.brand{flex-wrap:wrap}.run{margin-top:10px}.target{max-width:100%;white-space:normal;overflow-wrap:anywhere}.sidebar,.filters{grid-template-columns:1fr}.summary{grid-template-columns:repeat(2,minmax(0,1fr))}.results-head,.suppression-title,.suppression-head{display:block}.page-head{align-items:flex-start}.page-id a{max-width:48vw}.metrics span{flex:1 1 42%}.panel-head>span{display:none}.shot-scroll{min-height:240px}.message,.selector,.details,.help{margin-left:0}.suppression-title p,.suppression-head strong{display:block;margin-top:5px}.report-footer{display:block}} +@media(max-width:560px){.topbar{display:block}.brand{flex-wrap:wrap}.run{margin-top:10px}.target{max-width:100%;white-space:normal;overflow-wrap:anywhere}.sidebar,.filters{grid-template-columns:1fr}.summary{grid-template-columns:repeat(2,minmax(0,1fr))}.comparison{display:block}.comparison dl{width:100%;min-width:0;margin-top:13px}.comparison dl>div:first-child{border-left:0;padding-left:0}.results-head,.suppression-title,.suppression-head{display:block}.page-head{align-items:flex-start}.page-id a{max-width:48vw}.metrics span{flex:1 1 42%}.panel-head>span{display:none}.shot-scroll{min-height:240px}.message,.selector,.details,.help{margin-left:0}.suppression-title p,.suppression-head strong{display:block;margin-top:5px}.report-footer{display:block}} @media print{:root{color-scheme:light}body{background:#fff}.sidebar,.summary,.results-head p{display:none!important}.layout{display:block;width:100%;padding:16px}.page{break-inside:avoid;box-shadow:none}.workbench{display:block}.visual{border:0}.shot-scroll,.finding-list{max-height:none;overflow:visible}} `; @@ -634,6 +634,43 @@ function renderSummary(report: ScanReport): string { ).join(""); } +function renderComparison(report: ScanReport): string { + const comparison = report.comparison; + if (!comparison) return ""; + + const baselineLabel = comparison.baseline.source + ? '' + + escapeHtml(shorten(comparison.baseline.source, 80)) + + "" + : "run " + escapeHtml(comparison.baseline.runId) + ""; + const headline = comparison.counts.new + ? formatNumber(comparison.counts.new) + + (comparison.counts.new === 1 ? " new finding" : " new findings") + : "No new findings"; + + return [ + '

', + 'Baseline comparison

', + headline, + "

Compared with ", + baselineLabel, + " from ", + escapeHtml(formatTimestamp(comparison.baseline.startedAt)), + ".

", + '
New
', + formatNumber(comparison.counts.new), + "
", + '
Existing
', + formatNumber(comparison.counts.existing), + "
", + '
Resolved
', + formatNumber(comparison.counts.resolved), + "
", + ].join(""); +} + export function createHtmlReport( report: ScanReport, options: HtmlReportOptions = {}, @@ -790,7 +827,8 @@ export function createHtmlReport( '', '
' + renderSummary(report) + - "
", + "" + + renderComparison(report), '

Inspection results

' + formatNumber(findings.length) + ' findings across ' + diff --git a/src/sarif.ts b/src/sarif.ts index 60f7898..9761803 100644 --- a/src/sarif.ts +++ b/src/sarif.ts @@ -2,7 +2,13 @@ import { mkdir, writeFile } from "node:fs/promises"; import { dirname } from "node:path"; import { RULES } from "./rules.js"; -import type { Finding, RuleId, ScanReport, Severity } from "./types.js"; +import type { + Finding, + ReportComparison, + RuleId, + ScanReport, + Severity, +} from "./types.js"; export type SarifLevel = "error" | "warning" | "note" | "none"; @@ -37,6 +43,7 @@ export interface SarifRun { score: number; pages: number; viewports: number; + comparison?: Pick; suppressed?: number; suppressionAudit?: Array<{ ruleId: RuleId; @@ -255,6 +262,14 @@ export function createSarifLog(report: ScanReport): SarifLog { score: report.summary.score, pages: report.summary.pages, viewports: report.summary.viewports, + ...(report.comparison + ? { + comparison: { + baseline: report.comparison.baseline, + counts: report.comparison.counts, + }, + } + : {}), ...(report.suppressions ? { suppressed: report.suppressions.total, diff --git a/src/scanner.ts b/src/scanner.ts index d65fa7b..dfec8a5 100644 --- a/src/scanner.ts +++ b/src/scanner.ts @@ -392,9 +392,9 @@ async function toolVersion(): Promise { }; return typeof packageJson.version === "string" ? packageJson.version - : "0.3.0"; + : "0.4.0"; } catch { - return "0.3.0"; + return "0.4.0"; } } diff --git a/src/types.ts b/src/types.ts index 7a08249..6db99e0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -124,6 +124,26 @@ export interface SummaryCounts { suppressed?: number; } +export interface FindingComparisonSummary { + new: number; + existing: number; + resolved: number; +} + +export interface ReportComparison { + baseline: { + source?: string; + schemaVersion: string; + toolVersion: string; + runId: string; + startedAt: string; + }; + counts: FindingComparisonSummary; + new: Finding[]; + existing: Finding[]; + resolved: Finding[]; +} + export interface ScanReport { schemaVersion: "1.0"; tool: { @@ -137,6 +157,7 @@ export interface ScanReport { pages: PageResult[]; summary: SummaryCounts; suppressions?: SuppressionAudit; + comparison?: ReportComparison; options: { viewports: ViewportSpec[]; paths: string[]; diff --git a/test/cli-compare.test.ts b/test/cli-compare.test.ts new file mode 100644 index 0000000..66da894 --- /dev/null +++ b/test/cli-compare.test.ts @@ -0,0 +1,251 @@ +import { spawn } from "node:child_process"; +import { access, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import { afterAll, beforeAll, describe, expect, it } from "vitest"; + +import type { Finding, ScanReport, Severity } from "../src/types.js"; + +interface CliResult { + exitCode: number | null; + stderr: string; + stdout: string; +} + +const repositoryRoot = path.resolve(fileURLToPath(new URL("..", import.meta.url))); +const cliPath = path.join(repositoryRoot, "src", "cli.ts"); +const fixturePath = path.join( + repositoryRoot, + "src", + "__tests__", + "scanner-fixture.html", +); +const tsxCliPath = fileURLToPath(import.meta.resolve("tsx/cli")); +const browserCandidates = [ + process.env.LAYOUTSCOPE_TEST_EXECUTABLE, + "C:/Program Files/Google/Chrome/Application/chrome.exe", + "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe", + "/usr/bin/google-chrome", + "/usr/bin/chromium", + "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", +].filter((candidate): candidate is string => Boolean(candidate)); + +let temporaryDirectory: string; +let baselinePath: string; +let baselineReport: ScanReport; +let executablePath: string | undefined; + +async function findInstalledBrowser(): Promise { + for (const candidate of browserCandidates) { + if (await access(candidate).then(() => true).catch(() => false)) { + return candidate; + } + } + return undefined; +} + +async function runCli(args: string[]): Promise { + return new Promise((resolve, reject) => { + const child = spawn(process.execPath, [tsxCliPath, cliPath, ...args], { + cwd: repositoryRoot, + env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" }, + stdio: ["ignore", "pipe", "pipe"], + }); + let stdout = ""; + let stderr = ""; + child.stdout.setEncoding("utf8"); + child.stderr.setEncoding("utf8"); + child.stdout.on("data", (chunk: string) => { + stdout += chunk; + }); + child.stderr.on("data", (chunk: string) => { + stderr += chunk; + }); + child.once("error", reject); + child.once("close", (exitCode) => resolve({ exitCode, stderr, stdout })); + }); +} + +function scanArguments(outputDirectory: string): string[] { + return [ + fixturePath, + "--output", + outputDirectory, + "--viewport", + "640x800:fixture", + "--wait", + "0", + "--max-findings", + "20", + "--no-auto-config", + "--no-open", + ...(executablePath ? ["--executable-path", executablePath] : []), + ]; +} + +function parseJsonReport(result: CliResult): ScanReport { + return JSON.parse(result.stdout) as ScanReport; +} + +function withoutFinding(report: ScanReport, removed: Finding): ScanReport { + const copy = structuredClone(report); + for (const page of copy.pages) { + page.findings = page.findings.filter( + (finding) => finding.id !== removed.id, + ); + } + + const findings = copy.pages.flatMap((page) => page.findings); + const counts: Record = { + critical: 0, + error: 0, + warning: 0, + info: 0, + }; + for (const finding of findings) counts[finding.severity] += 1; + copy.summary = { + ...counts, + total: findings.length, + pages: copy.pages.length, + viewports: copy.options.viewports.length, + score: Math.max( + 0, + 100 - + counts.critical * 25 - + counts.error * 10 - + counts.warning * 3, + ), + }; + return copy; +} + +beforeAll(async () => { + temporaryDirectory = await mkdtemp( + path.join(os.tmpdir(), "layoutscope-cli-compare-"), + ); + executablePath = await findInstalledBrowser(); + const baselineDirectory = path.join(temporaryDirectory, "baseline"); + const result = await runCli([ + ...scanArguments(baselineDirectory), + "--format", + "json", + "--fail-on", + "never", + ]); + if (result.exitCode !== 0) { + throw new Error( + `Unable to create CLI comparison baseline (exit ${result.exitCode}).\n${result.stderr}`, + ); + } + baselinePath = path.join(baselineDirectory, "report.json"); + baselineReport = parseJsonReport(result); +}, 60_000); + +afterAll(async () => { + if (temporaryDirectory) { + await rm(temporaryDirectory, { recursive: true, force: true }); + } +}); + +describe("CLI baseline comparison", () => { + it("rejects an invalid baseline before creating scan artifacts", async () => { + const invalidBaselinePath = path.join( + temporaryDirectory, + "invalid-baseline.json", + ); + const outputDirectory = path.join(temporaryDirectory, "invalid-output"); + await writeFile( + invalidBaselinePath, + JSON.stringify({ schemaVersion: "0.0" }), + "utf8", + ); + + const result = await runCli([ + path.join(temporaryDirectory, "missing-target.html"), + "--compare", + invalidBaselinePath, + "--output", + outputDirectory, + "--no-auto-config", + "--no-open", + ]); + + expect(result.exitCode).toBe(2); + expect(result.stderr).toMatch(/Baseline report .*schemaVersion/i); + expect(result.stderr).not.toMatch(/Target does not exist/i); + await expect(access(outputDirectory)).rejects.toThrow(); + }); + + it("passes a self-compare with existing errors and keeps JSON output in sync", async () => { + expect(baselineReport.summary.error).toBeGreaterThan(0); + const outputDirectory = path.join(temporaryDirectory, "self-compare"); + const result = await runCli([ + ...scanArguments(outputDirectory), + "--compare", + baselinePath, + "--format", + "json", + "--fail-on", + "error", + ]); + + expect(result.exitCode).toBe(0); + const stdoutReport = parseJsonReport(result); + expect(stdoutReport.summary.error).toBeGreaterThan(0); + expect(stdoutReport.comparison).toMatchObject({ + counts: { + new: 0, + existing: baselineReport.summary.total, + resolved: 0, + }, + }); + expect( + stdoutReport.comparison?.existing.some( + (finding) => finding.severity === "error", + ), + ).toBe(true); + + const artifactReport = JSON.parse( + await readFile(path.join(outputDirectory, "report.json"), "utf8"), + ) as ScanReport; + expect(artifactReport.comparison).toEqual(stdoutReport.comparison); + }, 60_000); + + it("fails when the current scan introduces a new error", async () => { + const removedError = baselineReport.pages + .flatMap((page) => page.findings) + .find((finding) => finding.ruleId === "LS001"); + expect(removedError).toMatchObject({ severity: "error" }); + + const derivedBaselinePath = path.join( + temporaryDirectory, + "baseline-without-error.json", + ); + await writeFile( + derivedBaselinePath, + JSON.stringify(withoutFinding(baselineReport, removedError!)), + "utf8", + ); + const result = await runCli([ + ...scanArguments(path.join(temporaryDirectory, "new-error")), + "--compare", + derivedBaselinePath, + "--format", + "json", + "--fail-on", + "error", + ]); + + expect(result.exitCode).toBe(1); + const report = parseJsonReport(result); + expect(report.comparison?.new).toContainEqual( + expect.objectContaining({ + fingerprint: removedError!.fingerprint, + ruleId: removedError!.ruleId, + severity: "error", + }), + ); + }, 60_000); +}); diff --git a/test/compare.test.ts b/test/compare.test.ts new file mode 100644 index 0000000..9a55be0 --- /dev/null +++ b/test/compare.test.ts @@ -0,0 +1,239 @@ +import { mkdtemp, writeFile } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; + +import { describe, expect, it } from "vitest"; + +import { + compareReports, + findingIdentity, + loadBaselineReport, + validateBaselineReport, +} from "../src/compare.js"; +import type { Finding, ScanReport, ViewportSpec } from "../src/types.js"; + +const viewport: ViewportSpec = { + name: "mobile", + width: 390, + height: 844, + isMobile: true, + hasTouch: true, +}; + +function finding( + fingerprint: string, + overrides: Partial = {}, +): Finding { + return { + id: `LS003-${fingerprint}`, + ruleId: "LS003", + severity: "error", + title: "Clipped content", + message: "Content is clipped.", + help: "Allow the content to wrap.", + pageUrl: "https://example.com/pricing", + pagePath: "/pricing", + viewport: { ...viewport }, + evidence: { + selector: "#price", + tag: "div", + rect: { + x: 0, + y: 0, + width: 80, + height: 20, + top: 0, + right: 80, + bottom: 20, + left: 0, + }, + }, + fingerprint, + ...overrides, + }; +} + +function report(findings: Finding[], overrides: Partial = {}): ScanReport { + return { + schemaVersion: "1.0", + tool: { name: "layoutscope", version: "0.3.0" }, + runId: "run-1", + startedAt: "2026-08-13T00:00:00.000Z", + durationMs: 100, + target: "https://example.com", + pages: [ + { + pageUrl: "https://example.com/pricing", + pagePath: "/pricing", + title: "Pricing", + viewport: { ...viewport }, + findings, + metrics: { + documentWidth: 390, + documentHeight: 844, + viewportWidth: 390, + viewportHeight: 844, + elementsInspected: 10, + loadTimeMs: 25, + }, + screenshotPath: "screenshots/pricing.png", + annotatedScreenshotPath: "screenshots/pricing.annotated.png", + }, + ], + summary: { + critical: 0, + error: findings.length, + warning: 0, + info: 0, + total: findings.length, + pages: 1, + viewports: 1, + score: 90, + }, + options: { + viewports: [{ ...viewport }], + paths: ["/pricing"], + waitMs: 0, + }, + ...overrides, + }; +} + +describe("compareReports", () => { + it("classifies new, existing, and resolved active findings", () => { + const shared = finding("shared", { message: "Current wording." }); + const baseline = report([ + finding("resolved"), + finding("shared", { message: "Old wording." }), + ]); + const current = report([shared, finding("new")], { + runId: "run-2", + tool: { name: "layoutscope", version: "0.4.0" }, + }); + + expect( + compareReports(current, baseline, { baselineSource: "baseline.json" }), + ).toEqual({ + baseline: { + source: "baseline.json", + schemaVersion: "1.0", + toolVersion: "0.3.0", + runId: "run-1", + startedAt: "2026-08-13T00:00:00.000Z", + }, + counts: { new: 1, existing: 1, resolved: 1 }, + new: [current.pages[0]!.findings[1]], + existing: [shared], + resolved: [baseline.pages[0]!.findings[0]], + }); + }); + + it("includes route, viewport, rule, and fingerprint in the identity", () => { + const original = finding("same"); + const identities = [ + finding("same", { pagePath: "/account" }), + finding("same", { + viewport: { ...viewport, name: "desktop", width: 1440, height: 900 }, + }), + finding("same", { ruleId: "LS002" }), + finding("different"), + ].map(findingIdentity); + + expect(new Set([findingIdentity(original), ...identities]).size).toBe(5); + for (const changed of identities) { + expect(changed).not.toBe(findingIdentity(original)); + } + }); + + it("matches duplicate identities as a multiset and ignores ordering", () => { + const duplicate = finding("duplicate"); + const baseline = report([duplicate, finding("other"), { ...duplicate }]); + const current = report([finding("other"), { ...duplicate }]); + + const comparison = compareReports(current, baseline); + + expect(comparison.counts).toEqual({ new: 0, existing: 2, resolved: 1 }); + expect(comparison.existing.map((item) => item.fingerprint)).toEqual([ + "other", + "duplicate", + ]); + expect(comparison.resolved).toEqual([baseline.pages[0]!.findings[2]]); + }); + + it("compares only active page findings, not suppression audit samples", () => { + const suppressed = finding("suppressed"); + const baseline = report([], { + suppressions: { + active: [ + { + ruleId: "LS003", + fingerprint: "suppressed", + reason: "Accepted legacy behavior.", + matchCount: 1, + shadowedMatchCount: 0, + }, + ], + findings: [ + { + ...suppressed, + suppression: { + index: 0, + reason: "Accepted legacy behavior.", + shadowedIndexes: [], + }, + }, + ], + total: 1, + sampled: 1, + omitted: 0, + rawTotal: 1, + rawScore: 90, + }, + }); + + const comparison = compareReports(report([suppressed]), baseline); + + expect(comparison.counts).toEqual({ new: 1, existing: 0, resolved: 0 }); + expect(comparison.new).toEqual([suppressed]); + }); +}); + +describe("baseline validation", () => { + it("reports the exact invalid finding property", () => { + const invalid = report([finding("broken")]) as unknown as { + pages: Array<{ findings: Array<{ fingerprint?: string }> }>; + }; + delete invalid.pages[0]!.findings[0]!.fingerprint; + + expect(() => validateBaselineReport(invalid)).toThrow( + "Baseline report.pages[0].findings[0].fingerprint must be a non-empty string.", + ); + }); + + it("rejects unsupported schemas and non-LayoutScope JSON", () => { + expect(() => + validateBaselineReport({ schemaVersion: "2.0" }), + ).toThrow(/schemaVersion must be the supported value "1\.0"/); + expect(() => validateBaselineReport([])).toThrow( + "Baseline report.root must be an object.", + ); + }); + + it("loads valid reports and gives actionable file and JSON errors", async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), "layoutscope-compare-")); + const validPath = path.join(directory, "valid.json"); + const invalidPath = path.join(directory, "invalid.json"); + const missingPath = path.join(directory, "missing.json"); + const baseline = report([finding("baseline")]); + await writeFile(validPath, JSON.stringify(baseline), "utf8"); + await writeFile(invalidPath, "{not-json", "utf8"); + + await expect(loadBaselineReport(validPath)).resolves.toEqual(baseline); + await expect(loadBaselineReport(invalidPath)).rejects.toThrow( + /contains invalid JSON/, + ); + await expect(loadBaselineReport(missingPath)).rejects.toThrow( + /Unable to read baseline report/, + ); + }); +}); diff --git a/test/report.test.ts b/test/report.test.ts index f1921ba..89cd129 100644 --- a/test/report.test.ts +++ b/test/report.test.ts @@ -8,7 +8,7 @@ import type { ScanReport } from "../src/types.js"; const report: ScanReport = { schemaVersion: "1.0", - tool: { name: "layoutscope", version: "0.3.0" }, + tool: { name: "layoutscope", version: "0.4.0" }, runId: "run-1", startedAt: "2026-08-12T00:00:00.000Z", durationMs: 1200, @@ -192,4 +192,34 @@ describe("reports", () => { sarif.runs[0]?.results[0]?.partialFingerprints["layoutscope/v1"], ).toBe("fingerprint"); }); + + it("renders and exports baseline comparison metadata", () => { + const comparedReport: ScanReport = { + ...report, + comparison: { + baseline: { + source: ".layoutscope-main/report.json", + schemaVersion: "1.0", + toolVersion: "0.3.0", + runId: "baseline-run", + startedAt: "2026-08-11T23:45:00.000Z", + }, + counts: { new: 1, existing: 2, resolved: 3 }, + new: report.pages[0]!.findings, + existing: [], + resolved: [], + }, + }; + + const html = createHtmlReport(comparedReport); + expect(html).toContain("Baseline comparison"); + expect(html).toContain("1 new finding"); + expect(html).toContain(".layoutscope-main/report.json"); + expect(html).toContain('

Resolved
3
'); + + expect(createSarifLog(comparedReport).runs[0]?.properties.comparison).toEqual({ + baseline: comparedReport.comparison!.baseline, + counts: comparedReport.comparison!.counts, + }); + }); });