| name | fix-jscpd |
| description | Decision framework for fixing jscpd (copy-paste detector) errors. Use when asked to fix jscpd issues, copy-paste errors, clones or COPYPASTE lint failures. |
| user-invocable | false |
Fixing jscpd / Copy-Paste Issues
When jscpd reports a clone, decide between factorization and ignore comments based on these criteria.
Decision Criteria
Factorize when
- The duplicate logic is semantically identical and would not diverge (same intent, same data shape).
- Extracting it produces a clean, named helper with a clear single responsibility.
- The helper is small (under ~15 lines) and self-contained.
- The duplication is within the same file or a closely related module.
Examples in this project: buildPersonaCols(n) in profiles-extract.ts, formatLimitLine(limit) in limits.ts.
Ignore with /* jscpd:ignore-start */ / /* jscpd:ignore-end */ when
- The clones are in separate, unrelated command files (each command is a standalone unit).
- The structure is the same but the data shapes or intent diverge (e.g., different result fields in different audit commands).
- The duplication is unavoidable boilerplate (standard flags:
agent, debug, websocket, skipauth).
- Extracting would add indirection with no real benefit (e.g.,
buildInitialMarkdownLines in different DocBuilder subclasses).
Ignore Comment Placement
Place /* jscpd:ignore-start */ on the line before the first duplicate line, and /* jscpd:ignore-end */ on the line after the last duplicate line. Keep the comments on their own lines, indented to match the surrounding code.
for (const catcher of catchers) {
const results = await catchMatches(catcher, file, fileText, this);
this.matchResults.push(...results);
}
Factorization Pattern
Add a private (or private static) helper method to the enclosing class, or a module-level function if the logic is pure and stateless.
private static formatLimitLine(limit: any): string {
return `• ${limit.name}: *${limit.percentUsed}%* used (${limit.used}/${limit.max})`;
}
Then replace the duplicate .map(...) blocks with .map(MyClass.formatLimitLine).
Standard Flag Boilerplate
The agent, debug, websocket, and skipauth flags appear in every command. These are always intentional duplicates - wrap them with jscpd:ignore rather than abstracting.