cpd 5.0.1 → 5.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +234 -0
- package/package.json +7 -7
package/README.md
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# cpd — Rust Copy/Paste Detector
|
|
2
|
+
|
|
3
|
+
Fast copy/paste detector for programming source code. Rust rewrite of [jscpd](https://github.com/kucherenko/jscpd) with 10–30× faster detection, git blame, and 225+ language formats.
|
|
4
|
+
|
|
5
|
+
## Performance
|
|
6
|
+
|
|
7
|
+
| Codebase | Files | jscpd v4 (Node.js) | cpd v5 (Rust) | Speedup |
|
|
8
|
+
|----------|-------|--------------------|----------------|---------|
|
|
9
|
+
| Multi-format fixtures | 353 | 1.59 s | 0.45 s | 3.5× |
|
|
10
|
+
| Rust sources (homogeneous) | 46 | 0.87 s | 0.03 s | 29× |
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
### npm (recommended)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g cpd
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Prebuilt binaries for 6 platforms — no Node.js runtime required:
|
|
21
|
+
|
|
22
|
+
| Package | OS | Arch | libc |
|
|
23
|
+
|---------|----|------|------|
|
|
24
|
+
| `cpd-darwin-arm64` | macOS | arm64 | — |
|
|
25
|
+
| `cpd-darwin-x64` | macOS | x64 | — |
|
|
26
|
+
| `cpd-linux-arm64-gnu` | Linux | arm64 | glibc |
|
|
27
|
+
| `cpd-linux-x64-gnu` | Linux | x64 | glibc |
|
|
28
|
+
| `cpd-linux-x64-musl` | Linux | x64 | musl |
|
|
29
|
+
| `cpd-windows-x64-msvc` | Windows | x64 | — |
|
|
30
|
+
|
|
31
|
+
### crates.io
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cargo install jscpd
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### From source
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/kucherenko/jscpd.git
|
|
41
|
+
cd jscpd/rust
|
|
42
|
+
cargo build --release
|
|
43
|
+
# binary at target/release/cpd
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Scan current directory (defaults: min-tokens 50, min-lines 5)
|
|
50
|
+
cpd .
|
|
51
|
+
|
|
52
|
+
# Scan specific paths
|
|
53
|
+
cpd ./src ./lib
|
|
54
|
+
|
|
55
|
+
# Git blame with side-by-side author comparison
|
|
56
|
+
cpd . --blame --reporters console-full
|
|
57
|
+
|
|
58
|
+
# Output to JSON + HTML
|
|
59
|
+
cpd . --reporters json,html
|
|
60
|
+
|
|
61
|
+
# Fail CI if duplication exceeds threshold
|
|
62
|
+
cpd . --threshold 10 --exit-code
|
|
63
|
+
|
|
64
|
+
# List all 225+ supported formats
|
|
65
|
+
cpd --list
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Options
|
|
69
|
+
|
|
70
|
+
| Flag | Short | Default | Description |
|
|
71
|
+
|------|-------|---------|-------------|
|
|
72
|
+
| `--min-tokens` | `-k` | 50 | Minimum tokens to consider a duplicate |
|
|
73
|
+
| `--min-lines` | `-l` | 5 | Minimum lines to consider a duplicate |
|
|
74
|
+
| `--max-lines` | `-x` | — | Maximum lines per duplicate block |
|
|
75
|
+
| `--mode` | `-m` | mild | Detection mode: `mild`, `weak`, `strict` |
|
|
76
|
+
| `--skip-comments` | — | — | Alias for `--mode weak` |
|
|
77
|
+
| `--format` | `-f` | all | Comma-separated formats to check |
|
|
78
|
+
| `--ignore-pattern` | `-i` | — | Glob patterns to ignore |
|
|
79
|
+
| `--reporters` | `-r` | console | comma-separated reporters |
|
|
80
|
+
| `--output` | `-o` | report | Output directory for file reporters |
|
|
81
|
+
| `--config` | `-c` | — | Path to config file (`.jscpd.json`) |
|
|
82
|
+
| `--exit-code` | — | — | Exit non-zero if duplicates found |
|
|
83
|
+
| `--threshold` | `-t` | — | Max duplication % before exit 1 |
|
|
84
|
+
| `--blame` | `-b` | — | Enrich clones with git blame data |
|
|
85
|
+
| `--no-gitignore` | — | — | Ignore `.gitignore` files |
|
|
86
|
+
| `--follow-symlinks` | — | — | Follow symbolic links |
|
|
87
|
+
| `--max-size` | `-z` | 512 KB | Skip files larger than N bytes |
|
|
88
|
+
| `--workers` | — | auto | Number of worker threads |
|
|
89
|
+
| `--no-colors` | — | — | Disable ANSI color output |
|
|
90
|
+
| `--skip-local` | — | — | Skip clones within the same directory |
|
|
91
|
+
| `--silent` | `-s` | — | Suppress console output |
|
|
92
|
+
| `--no-tips` | — | — | Suppress tips and promotional messages |
|
|
93
|
+
| `--list` | — | — | List all supported formats and exit |
|
|
94
|
+
|
|
95
|
+
## Reporters
|
|
96
|
+
|
|
97
|
+
13 built-in reporters:
|
|
98
|
+
|
|
99
|
+
| Reporter | Output |
|
|
100
|
+
|----------|--------|
|
|
101
|
+
| `console` | Clone list + statistics table (default) |
|
|
102
|
+
| `console-full` | Source snippets + optional blame comparison |
|
|
103
|
+
| `json` | `report/cpd.json` |
|
|
104
|
+
| `xml` | `report/cpd.xml` |
|
|
105
|
+
| `csv` | `report/cpd.csv` |
|
|
106
|
+
| `html` | `report/cpd.html` |
|
|
107
|
+
| `markdown` | `report/cpd.md` |
|
|
108
|
+
| `badge` | `report/cpd-badge.svg` |
|
|
109
|
+
| `sarif` | `report/cpd.sarif.json` (GitHub Code Scanning) |
|
|
110
|
+
| `ai` | Token-efficient output for LLM pipelines |
|
|
111
|
+
| `xcode` | Xcode-compatible warnings |
|
|
112
|
+
| `threshold` | Exit 1 if duplication % exceeds `--threshold` |
|
|
113
|
+
| `silent` | No console output |
|
|
114
|
+
|
|
115
|
+
Combine reporters: `--reporters console,json,html`
|
|
116
|
+
|
|
117
|
+
## Git Blame
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
cpd . --blame --reporters console-full
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Produces a side-by-side author comparison:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
176 │ Andrii Kucherenko │ <= │ 196 │ Josh Soref │ ## TODO
|
|
127
|
+
177 │ Andrii Kucherenko │ <= │ 197 │ Josh Soref │
|
|
128
|
+
180 │ Andrii Kucherenko │ == │ 200 │ Andrii Kucherenko │ ## License
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`==` = same author (original). `<=` = different author (potential copy).
|
|
132
|
+
|
|
133
|
+
## Config File
|
|
134
|
+
|
|
135
|
+
Create `.jscpd.json` in your project root:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"minTokens": 30,
|
|
140
|
+
"minLines": 3,
|
|
141
|
+
"format": ["javascript", "typescript", "python"],
|
|
142
|
+
"ignorePattern": ["node_modules", "dist", "*.min.js"],
|
|
143
|
+
"reporters": ["console", "json"],
|
|
144
|
+
"output": "report",
|
|
145
|
+
"threshold": 5,
|
|
146
|
+
"blame": false,
|
|
147
|
+
"noGitignore": false,
|
|
148
|
+
"noColors": false,
|
|
149
|
+
"silent": false
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Cross-Format Detection
|
|
154
|
+
|
|
155
|
+
Vue SFC (`.vue`), Svelte (`.svelte`), Astro (`.astro`), and Markdown files are tokenized per-block, enabling duplicate detection across file types:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
Clone found (javascript)
|
|
159
|
+
- app.vue:javascript [10:1 - 35:2] (25 lines, 180 tokens)
|
|
160
|
+
utils.js [40:1 - 65:2]
|
|
161
|
+
|
|
162
|
+
Clone found (yaml)
|
|
163
|
+
- docker-compose.yml:yaml [7:1 - 25:33] (18 lines, 36 tokens)
|
|
164
|
+
config.yml:yaml [7:1 - 25:37]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Programmatic Usage (Rust)
|
|
168
|
+
|
|
169
|
+
```rust
|
|
170
|
+
use cpd_finder::orchestrate::{RunConfig, run};
|
|
171
|
+
|
|
172
|
+
let config = RunConfig {
|
|
173
|
+
paths: vec!["./src".into()],
|
|
174
|
+
min_tokens: 50,
|
|
175
|
+
..Default::default()
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
let result = run(&config).unwrap();
|
|
179
|
+
println!("Found {} clones", result.clones.len());
|
|
180
|
+
println!("Analyzed {} files", result.statistics.total.sources);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Architecture
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
jscpd (binary)
|
|
187
|
+
├── cpd-core — Detection algorithm (Rabin-Karp rolling hash)
|
|
188
|
+
├── cpd-tokenizer — Language tokenization (225+ formats)
|
|
189
|
+
├── cpd-finder — File walking, orchestration, git blame
|
|
190
|
+
└── cpd-reporter — Output formatting (13 reporters)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
| Crate | crates.io | Purpose |
|
|
194
|
+
|-------|-----------|---------|
|
|
195
|
+
| `cpd-core` | [0.1.1](https://crates.io/crates/cpd-core) | Detection algorithm, rolling hash, models |
|
|
196
|
+
| `cpd-tokenizer` | [0.1.1](https://crates.io/crates/cpd-tokenizer) | Language tokenization (225+ formats) |
|
|
197
|
+
| `cpd-finder` | [0.1.2](https://crates.io/crates/cpd-finder) | File walking, orchestration, git blame |
|
|
198
|
+
| `cpd-reporter` | [0.1.2](https://crates.io/crates/cpd-reporter) | Output formatting (13 reporters) |
|
|
199
|
+
| `jscpd` | [5.0.2](https://crates.io/crates/jscpd) | CLI binary and entry point |
|
|
200
|
+
|
|
201
|
+
## Known Differences from jscpd v4
|
|
202
|
+
|
|
203
|
+
| Feature | jscpd v4 (Node.js) | cpd v5 (Rust) |
|
|
204
|
+
|---------|--------------------|-----------------|
|
|
205
|
+
| `--blame` in `console-full` | Per-line side-by-side author comparison | Same — `==` / `<=` markers |
|
|
206
|
+
| `--store` (LevelDB) | Persistent store for large repos | Not supported. Use jscpd v4.x |
|
|
207
|
+
| `--formatsExts` | Custom format-to-extension mapping | Not supported. Use `--format` |
|
|
208
|
+
| Programming API | `jscpd()` Promise API, `detectClones()` | Rust crate API; no Node.js API |
|
|
209
|
+
| Config file | `.jscpd.json` with camelCase keys | Same |
|
|
210
|
+
| Cross-format detection | Vue, Svelte, Astro, Markdown | Same — per-block tokenization |
|
|
211
|
+
| Token counts | May differ slightly | May differ by 1–2%; clone detection matches |
|
|
212
|
+
| `--reporters` | All v4 reporters | All v4 reporters except `full` (use `console-full`) |
|
|
213
|
+
|
|
214
|
+
## Building
|
|
215
|
+
|
|
216
|
+
### Prerequisites
|
|
217
|
+
|
|
218
|
+
- Rust 1.87+ (see `rust-toolchain.toml`)
|
|
219
|
+
|
|
220
|
+
### Build
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
cargo build --release
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Run Tests
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
cargo test
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## License
|
|
233
|
+
|
|
234
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cpd",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.3",
|
|
4
4
|
"description": "Copy/paste detector — fast Rust-based CLI for code duplication detection",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cpd": "./run-cpd.js"
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
"platform-map.js"
|
|
11
11
|
],
|
|
12
12
|
"optionalDependencies": {
|
|
13
|
-
"cpd-linux-x64-gnu": "5.0.
|
|
14
|
-
"cpd-linux-arm64-gnu": "5.0.
|
|
15
|
-
"cpd-linux-x64-musl": "5.0.
|
|
16
|
-
"cpd-darwin-arm64": "5.0.
|
|
17
|
-
"cpd-darwin-x64": "5.0.
|
|
18
|
-
"cpd-windows-x64-msvc": "5.0.
|
|
13
|
+
"cpd-linux-x64-gnu": "5.0.3",
|
|
14
|
+
"cpd-linux-arm64-gnu": "5.0.3",
|
|
15
|
+
"cpd-linux-x64-musl": "5.0.3",
|
|
16
|
+
"cpd-darwin-arm64": "5.0.3",
|
|
17
|
+
"cpd-darwin-x64": "5.0.3",
|
|
18
|
+
"cpd-windows-x64-msvc": "5.0.3"
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|