Skip to content

Extend jscpd coverage to scripts/ and remove all duplication - #1713

Merged
stefan-burke merged 3 commits into
mainfrom
claude/jscpd-scripts-coverage-xuhh07
Jul 10, 2026
Merged

Extend jscpd coverage to scripts/ and remove all duplication#1713
stefan-burke merged 3 commits into
mainfrom
claude/jscpd-scripts-coverage-xuhh07

Conversation

@stefan-burke

@stefan-burke stefan-burke commented Jul 10, 2026

Copy link
Copy Markdown
Member

What

Adds scripts to the path list in .jscpd.json so the project's non‑negotiable 0% duplication policy now covers the tooling scripts alongside src and e2e-payments. Turning it on surfaced 35 clones; this PR removes every one of them so deno task cpd passes green on both configs.

How

Most clones collapsed into small, intent‑revealing shared helpers:

New module Replaces
scripts/stream-lines.ts readStream / readLines / readText stream readers
scripts/walk-files.ts duplicated recursive file walkers (line‑counts, unit‑tests‑report, test‑quality‑audit)
scripts/line-column.ts duplicated offset → line/column helpers
scripts/run-build-edge.ts inline deno task build:edge spawns in build-site / deploy-edge
scripts/not-found.ts repeated Deno.errors.NotFound re‑throw guards
scripts/precommit/git.ts runGit / commandValue / work‑tree check shared by push + merge-warning
scripts/mutation/child-process.ts duplicated deno subprocess spawns and SIGINT/SIGTERM registration

Plus in‑place fixes where a whole module wasn't warranted:

  • project-root.ts gains a shared toDisplayPath; test-harness.ts gains runSuiteWithHarness (used by run-tests and find-slow-tests).
  • mutation/generate.ts: a MutantFn function‑type alias collapses repeated (node, content, exhaustive) => Mutant[] signatures; a literalValueOfType helper and a hoisted clippedText remove the rest.
  • deploy-edge-lib.ts: a ScriptCodeFn type alias de‑duplicates the upload/deploy signatures (call sites stay positional, so tests are untouched).
  • safe-upgrade.ts: the identical npm:/jsr: parse branches merge into one.
  • find-unused-src.ts and profile-cold-boot.ts: local helpers (splitAliasedNames, readSource, importersOf, isNeverImported, profileCaching, recordTiming, timeLoop) fold the repeated blocks together.
  • mutation/isolation.ts: killRuns/cleanRuns now delegate to a withSelectedRuns wrapper with named body helpers.

Verification

  • deno task cpd0 clones on both .jscpd.json and .jscpd.test.json
  • deno task typecheck and deno task lint pass
  • test/scripts/ (59 files) and test/lib/stripe-mock/ pass; refactored standalone scripts (find-unused-src, line-counts, unit-tests-report, test:quality-audit) run cleanly

Behaviour is unchanged throughout — this is duplication removal, not a functional change.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YPmXvHk8ynjRJn6TQrjyMJ


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added shared utilities for file discovery, streaming output, path display, and precise source location mapping.
    • Introduced reusable helpers for edge builds, Git command execution/checks, and consistent child-process + signal handling.
  • Improvements
    • Streamlined site deployment/build flows, mutation workflow execution, and test-suite running (including coverage/JUnit handling).
    • Improved precommit checks and reporting by consolidating common Git/process/stream helpers.
  • Tests
    • Added coverage for the shared stream-reading behavior.

Add `scripts` to the main .jscpd.json path so the 0% duplication policy now
applies to the tooling scripts too, then eliminate every clone it surfaced by
extracting shared helpers:

- stream-lines.ts: unify readStream/readLines/readText
- walk-files.ts: shared recursive file walker
- line-column.ts: shared offset -> line/column
- run-build-edge.ts: shared `deno task build:edge` runner
- not-found.ts: shared Deno NotFound guard
- precommit/git.ts: shared runGit/commandValue/isInsideWorkTree
- mutation/child-process.ts: shared denoExitCode + termination-signal helpers
- project-root.ts: shared toDisplayPath
- test-harness.ts: shared runSuiteWithHarness

Remaining clones are removed in place via small local helpers, function-type
aliases, branch merges, and higher-order wrappers. Behaviour is unchanged;
typecheck, lint, cpd (both configs), and the scripts/stripe-mock tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YPmXvHk8ynjRJn6TQrjyMJ
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@stefan-burke, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 9 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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

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

How do review limits work?

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

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d6a4d5fb-d069-49ab-9a66-feba942b2cb5

📥 Commits

Reviewing files that changed from the base of the PR and between 286ca6b and 236763d.

📒 Files selected for processing (4)
  • deno.json
  • scripts/project-root.ts
  • test/scripts/project-root.test.ts
  • test/scripts/stream-lines.test.ts
📝 Walkthrough

Walkthrough

This change centralizes reusable script helpers for process execution, signals, streams, paths, filesystem traversal, testing, Git operations, deployment, mutation tooling, and source analysis. Existing scripts are refactored to consume these helpers, with benchmark and scan configuration updates.

Changes

Script consolidation

Layer / File(s) Summary
Shared filesystem, path, stream, and process utilities
scripts/walk-files.ts, scripts/line-column.ts, scripts/stream-lines.ts, scripts/project-root.ts, scripts/not-found.ts, scripts/run-build-edge.ts, scripts/line-counts-lib.ts, scripts/unit-tests-report.ts
Adds reusable traversal, position, stream, path, missing-file, edge-build, and process helpers.
Mutation process helpers and orchestration
scripts/mutation/*
Centralizes Deno process exit handling, termination signals, run selection, error handling, and mutant-generator typing and formatting.
Precommit Git command abstraction
scripts/precommit/*, scripts/precommit-mutation.ts, test/scripts/precommit.test.ts, test/scripts/mutation-step.test.ts
Adds shared Git command types and helpers, then updates precommit flows and tests to use them.
Test harness and reporting flow
scripts/test-harness.ts, scripts/run-tests.ts, scripts/find-slow-tests.ts, scripts/test-durations.ts, scripts/compact-test-reporter.ts, scripts/test-quality-audit.ts, scripts/stream-lines.ts, test/scripts/stream-lines.test.ts
Centralizes suite execution, JUnit handling, path display, stream consumption, file traversal, and coverage annotation formatting.
Deployment, benchmark, and lock helpers
scripts/build-site.ts, scripts/deploy-edge.ts, scripts/run-build-edge.ts, scripts/deploy-edge-lib.ts, scripts/bench/*, scripts/profile-cold-boot.ts, scripts/stripe-mock*, scripts/safe-upgrade.ts
Extracts edge building, standardizes script-code typing, reuses benchmark timing helpers, and consolidates Stripe mock directory and registry parsing logic.
Source usage analysis and scan configuration
scripts/find-unused-src.ts, .jscpd.json, deno.json
Refactors source/import analysis helpers, adds scripts to duplicate-code scanning, and expands typecheck coverage.
Path utility validation
scripts/project-root.ts, test/scripts/project-root.test.ts
Adds and tests shared display-path normalization behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: expanding jscpd coverage to scripts/ and eliminating duplicated helper logic across the scripts.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/jscpd-scripts-coverage-xuhh07

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bd7f5996c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// the finally below still restores.
}
}
onTerminationSignals(onSignal);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove the stale signals cleanup reference

When any mutation run leaves mutate() (success, survivor, baseline failure, or interrupt), the finally block still executes for (const signal of signals), but this change removed that local signals binding in favor of onTerminationSignals. In deno task mutation ... that throws ReferenceError: signals is not defined and masks the actual mutation result, so callers can no longer rely on the mutation gate; unregister through the shared helper or keep the local signal list.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 286ca6b. The finally now calls the shared offTerminationSignals(onSignal), symmetric with the onTerminationSignals(onSignal) registration — the stale signals loop is gone.

Added a regression guard for the root cause too: runner.ts had no importing test, so deno task typecheck never type-checked it (that's how the identical bug in isolation.ts was caught — via its test). The typecheck task now also checks scripts/mutation/** and scripts/precommit/**, which fails with TS2552: Cannot find name 'signals' before the fix and passes after. Verified end-to-end by running the mutation entry point.


Generated by Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

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

Inline comments:
In `@scripts/find-unused-src.ts`:
- Around line 158-164: Refactor extractBraceExports to use functional
composition instead of mutating names in an imperative loop: obtain all regex
matches, map each match through splitAliasedNames using the existing `#fp`
utilities, and flatten the results with flatMap. Preserve the current regex and
returned export-name behavior.

In `@scripts/mutation/runner.ts`:
- Line 577: Update the cleanup logic in the mutation runner to call
offTerminationSignals(onSignal) from a finally block, replacing the manual local
SIGINT/SIGTERM listener-removal loop. Keep onTerminationSignals(onSignal) for
registration and ensure cleanup runs on every exit path.

In `@scripts/precommit/merge-warning.ts`:
- Around line 10-15: Eliminate the duplicated empty-command validation between
splitCommand and runStep. Export splitCommand, add a context-label parameter for
its error message, and update runStep to call this shared helper instead of
destructuring and checking command inline; adjust all existing callers
accordingly.
- Line 8: Move the generic command runner exports and implementations out of
merge-warning.ts into a dedicated command.ts or git.ts module, including
runCommand, runInteractiveCommand, CommandResult, and RunCommand. Update
runner.ts and other consumers to import these symbols directly from the new
module, and remove the re-export from merge-warning.ts so it contains only
merge-warning logic.

In `@scripts/test-harness.ts`:
- Around line 181-186: In runSuiteWithHarness, narrow the
Deno.remove(JUNIT_PATH) error handling to ignore only Deno errors with name
"NotFound"; rethrow all other removal failures so stale JUnit files cannot be
silently reused.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 387c4be1-a5c5-479b-b3aa-b7b64c2246a5

📥 Commits

Reviewing files that changed from the base of the PR and between 00fccf9 and bd7f599.

📒 Files selected for processing (33)
  • .jscpd.json
  • scripts/bench/bunny-crypto-smoke.ts
  • scripts/build-site.ts
  • scripts/compact-test-reporter.ts
  • scripts/deploy-edge-lib.ts
  • scripts/deploy-edge.ts
  • scripts/find-slow-tests.ts
  • scripts/find-unused-src.ts
  • scripts/line-column.ts
  • scripts/line-counts-lib.ts
  • scripts/mutation/child-process.ts
  • scripts/mutation/generate.ts
  • scripts/mutation/isolation-state.ts
  • scripts/mutation/isolation.ts
  • scripts/mutation/runner.ts
  • scripts/not-found.ts
  • scripts/precommit/git.ts
  • scripts/precommit/merge-warning.ts
  • scripts/precommit/push.ts
  • scripts/precommit/runner.ts
  • scripts/profile-cold-boot.ts
  • scripts/project-root.ts
  • scripts/run-build-edge.ts
  • scripts/run-tests.ts
  • scripts/safe-upgrade.ts
  • scripts/stream-lines.ts
  • scripts/stripe-mock.ts
  • scripts/stripe-mock/install.ts
  • scripts/test-durations.ts
  • scripts/test-harness.ts
  • scripts/test-quality-audit.ts
  • scripts/unit-tests-report.ts
  • scripts/walk-files.ts

Comment thread scripts/find-unused-src.ts Outdated
Comment thread scripts/mutation/runner.ts
Comment thread scripts/precommit/merge-warning.ts Outdated
Comment thread scripts/precommit/merge-warning.ts Outdated
Comment thread scripts/test-harness.ts
Address CI (100% coverage on scripts/) and PR review feedback:

- mutation/runner.ts: the mutate() teardown still referenced the removed
  local `signals` array, throwing ReferenceError on every real run. Use the
  shared offTerminationSignals(onSignal) helper. Guard the class of bug by
  type-checking scripts/mutation and scripts/precommit in the typecheck task
  (runner.ts had no importing test, so it was never type-checked) — this fails
  before the fix (TS2552) and passes after.
- stream-lines.ts + project-root.ts: add direct unit tests; the extracted
  readStream/toDisplayPath moved out of the coverage-excluded reporter, so they
  now need their own coverage. Drop the unreachable `?? ""` on a split result.
- test-harness.ts: narrow the JUnit-remove catch to NotFound via
  rethrowUnlessNotFound so a real removal failure surfaces.
- precommit/git.ts: move runCommand/runInteractiveCommand and the shared
  splitCommand here (with a context label reused by runStep) and drop the
  re-export shim from merge-warning.ts; update all importers.
- find-unused-src.ts: extractBraceExports uses #fp flatMap instead of an
  imperative push loop.

All gates pass: lint, typecheck, cpd (0 clones), and 100% line/branch coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YPmXvHk8ynjRJn6TQrjyMJ

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@deno.json`:
- Line 18: Update the root-level typecheck command to explicitly include
scripts/mutation.ts and scripts/precommit.ts alongside their existing recursive
directory globs, ensuring the executed mutation and precommit entrypoints are
typechecked.

In `@test/scripts/project-root.test.ts`:
- Around line 14-16: Add a regression test in the existing project-root path
display tests for `/base/..cache.ts`, expecting `..cache.ts`. Update
`toDisplayPath` in `scripts/project-root.ts` so escape detection matches only
the exact `..` segment or paths beginning with `../`, not any relative string
starting with `..`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: cbb9e3cf-a437-4a3d-ad03-0e9fae1f695b

📥 Commits

Reviewing files that changed from the base of the PR and between bd7f599 and 286ca6b.

📒 Files selected for processing (14)
  • deno.json
  • scripts/find-unused-src.ts
  • scripts/mutation/runner.ts
  • scripts/precommit-mutation.ts
  • scripts/precommit/git.ts
  • scripts/precommit/merge-warning.ts
  • scripts/precommit/mutation-step.ts
  • scripts/precommit/runner.ts
  • scripts/stream-lines.ts
  • scripts/test-harness.ts
  • test/scripts/mutation-step.test.ts
  • test/scripts/precommit.test.ts
  • test/scripts/project-root.test.ts
  • test/scripts/stream-lines.test.ts
💤 Files with no reviewable changes (1)
  • scripts/precommit/merge-warning.ts

Comment thread deno.json Outdated
Comment thread test/scripts/project-root.test.ts
…am test

- deno.json: also type-check the `scripts/mutation.ts` and `scripts/precommit.ts`
  entrypoints (the recursive globs covered only the subdirectories, so the
  top-level scripts the tasks actually run were still unchecked).
- project-root.ts: `toDisplayPath` now treats only an exact `..` or a
  `..<sep>`-prefixed relative path as escaping the base, so a file whose name
  merely starts with `..` (e.g. `..cache.ts`) renders correctly; add tests for
  both new branches.
- stream-lines test: build the fixture stream with `ReadableStream.from` so it
  closes deterministically (removes a manually-controlled stream that could
  leave a pending read at suite shutdown).

Full suite green locally: lint, typecheck, cpd (0 clones), 100% coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YPmXvHk8ynjRJn6TQrjyMJ
@stefan-burke
stefan-burke added this pull request to the merge queue Jul 10, 2026
Merged via the queue into main with commit 83c6afa Jul 10, 2026
2 checks passed
@stefan-burke
stefan-burke deleted the claude/jscpd-scripts-coverage-xuhh07 branch July 10, 2026 23:19
stefan-burke pushed a commit that referenced this pull request Jul 10, 2026
Main now runs jscpd over scripts/ (#1713) and ships a profiler whose
timing helper shares this benchmark child's token shape. The child's two
db proxies fold their shared scaffolding into a proxyMembers helper, and
record() becomes a curried two-stage function (start captured in the
outer stage), which both reads better and no longer collides. Verified
by re-running the benchmark: identical output (~2.0 round trips cold).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDJfd1kwQ72hjGvATnEJJ7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants