dry-refactoring
Guided workflow to eliminate copy-paste duplication in source code. Use after running jscpd to detect clones.
Prerequisites
First, run jscpd to identify duplications:
npx jscpd --reporters ai <path>
In codebases that mix related formats (e.g. JavaScript and TypeScript), add --cross-formats so clones spanning both are detected too:
npx jscpd --reporters ai --cross-formats "js-ts" <path>
See the jscpd skill for full option reference, including cross-format group syntax.
Workflow
- Run jscpd with
--reporters aion the target path - Parse each clone line to identify the two duplicated locations (file + line range)
- Read both code fragments from the source files
- Understand what the duplicated code does
- Design a refactoring: extract a shared function, class, module, or constant
- Apply the refactoring — update both locations and all other usages
- Re-run jscpd to confirm the clone is eliminated
- Repeat for remaining clones, highest-impact first
Refactoring Strategies
Extract function — when the duplicate is a block of logic:
// Before: same block in two places
// After: shared function called from both places
Extract module/utility — when the duplicate spans multiple files in different domains:
// Move shared logic to a shared utility file and import it
Extract constant or config — when the duplicate is repeated data or configuration.
Template/base class — when the duplicate is structural (e.g., repeated class shape).
Always ensure:
- All call sites are updated, not just the two reported by jscpd
- Tests still pass after refactoring
- The extracted abstraction has a clear, descriptive name
Tips
- Start with clones that have the highest line count — they have the most impact
- A clone between test files may indicate a missing test helper
- Clones across unrelated modules may signal a missing shared utility
- A cross-format clone (same logic in a
.jsand a.tsfile, found with--cross-formats) often means code was ported without deleting the original — consolidate into one implementation (usually the TypeScript one) and update imports, rather than extracting a third shared copy - Use
--min-lines 10to filter noise and focus on meaningful duplications











