cpd 5.1.0 → 5.1.2
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 +53 -49
- package/package.json +11 -9
- package/platform-map.js +29 -1
- package/run-cpd.js +14 -2
package/README.md
CHANGED
|
@@ -1,37 +1,29 @@
|
|
|
1
|
-
#
|
|
1
|
+
# jscpd — Rust engine
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Copy/paste detector for programming source code. A self-contained binary that finds duplicated blocks across 224 language formats, writes reports in 15 formats and can fail CI when duplication grows.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Performance
|
|
8
|
-
|
|
9
|
-
| Codebase | Files | Size | jscpd v4 (Node.js) | cpd v5 (Rust) | Speedup |
|
|
10
|
-
|----------|-------|------|--------------------|----------------|---------|
|
|
11
|
-
| Multi-format fixtures | 548 | 1.5 MB | 1.03 s | 0.03 s | 34.3× |
|
|
12
|
-
| Svelte source | 9K | 38 MB | 15.80 s | 0.43 s | 36.9× |
|
|
13
|
-
| CopilotKit | 17K | 159 MB | 82.89 s | 3.44 s | 24.1× |
|
|
14
|
-
|
|
15
|
-
See [performance-comparison.md](../docs/performance-comparison.md) for full methodology and raw data.
|
|
5
|
+
Published as [`jscpd`](https://www.npmjs.com/package/jscpd) on npm (installs the `jscpd` command), [`cpd`](https://www.npmjs.com/package/cpd) on npm (installs the `cpd` command), and [`jscpd`](https://crates.io/crates/jscpd) on crates.io (installs both). Full documentation: [jscpd.dev](https://jscpd.dev) and [docs/rust.md](../docs/rust.md).
|
|
16
6
|
|
|
17
7
|
## Install
|
|
18
8
|
|
|
19
|
-
### npm
|
|
9
|
+
### npm
|
|
20
10
|
|
|
21
11
|
```bash
|
|
22
|
-
#
|
|
12
|
+
# installs the jscpd command
|
|
23
13
|
npm install -g jscpd
|
|
24
14
|
|
|
25
|
-
#
|
|
15
|
+
# installs only the cpd command
|
|
26
16
|
npm install -g cpd
|
|
27
17
|
```
|
|
28
18
|
|
|
29
|
-
Prebuilt binaries for
|
|
19
|
+
Prebuilt binaries for 8 platforms (macOS arm64/x64, Linux arm64/x64 with glibc or musl, Windows arm64/x64) — no Node.js runtime required.
|
|
30
20
|
|
|
31
21
|
### crates.io
|
|
32
22
|
|
|
33
23
|
```bash
|
|
34
24
|
cargo install jscpd
|
|
25
|
+
# or, without compiling (prebuilt release binaries via cargo-binstall):
|
|
26
|
+
cargo binstall jscpd
|
|
35
27
|
```
|
|
36
28
|
|
|
37
29
|
Installs both `jscpd` and `cpd` binaries.
|
|
@@ -64,12 +56,14 @@ cargo build --release
|
|
|
64
56
|
## Quick Start
|
|
65
57
|
|
|
66
58
|
```bash
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
59
|
+
jscpd .
|
|
60
|
+
jscpd ./src ./lib
|
|
61
|
+
jscpd . --blame --reporters console-full
|
|
62
|
+
jscpd . --reporters json,html
|
|
63
|
+
jscpd . --threshold 10
|
|
64
|
+
jscpd --baseline-from-ref origin/main --fail-on-new-clones .
|
|
65
|
+
jscpd --mcp .
|
|
66
|
+
jscpd --list
|
|
73
67
|
```
|
|
74
68
|
|
|
75
69
|
## Architecture
|
|
@@ -77,18 +71,20 @@ cpd --list
|
|
|
77
71
|
```
|
|
78
72
|
jscpd/cpd (CLI binary)
|
|
79
73
|
├── cpd-core — Detection algorithm (Rabin-Karp rolling hash)
|
|
80
|
-
├── cpd-tokenizer — Language tokenization (
|
|
81
|
-
├── cpd-finder — File walking, orchestration, git blame
|
|
82
|
-
└── cpd-reporter — Output formatting (
|
|
74
|
+
├── cpd-tokenizer — Language tokenization (224 formats)
|
|
75
|
+
├── cpd-finder — File walking, orchestration, baseline, git blame
|
|
76
|
+
└── cpd-reporter — Output formatting (15 reporters)
|
|
83
77
|
```
|
|
84
78
|
|
|
85
|
-
| Crate |
|
|
86
|
-
|
|
87
|
-
| `
|
|
88
|
-
| `cpd-
|
|
89
|
-
| `cpd-
|
|
90
|
-
| `cpd-
|
|
91
|
-
| `
|
|
79
|
+
| Crate | Purpose |
|
|
80
|
+
|-------|---------|
|
|
81
|
+
| [`jscpd`](https://crates.io/crates/jscpd) | CLI binary and entry point (`crates/cpd`) |
|
|
82
|
+
| [`cpd-core`](https://crates.io/crates/cpd-core) | Detection algorithm, rolling hash, models |
|
|
83
|
+
| [`cpd-tokenizer`](https://crates.io/crates/cpd-tokenizer) | Language tokenization (224 formats); pure, no I/O |
|
|
84
|
+
| [`cpd-finder`](https://crates.io/crates/cpd-finder) | File walking, orchestration, git blame |
|
|
85
|
+
| [`cpd-reporter`](https://crates.io/crates/cpd-reporter) | Output formatting (15 reporters) |
|
|
86
|
+
|
|
87
|
+
Current versions are in each crate's `Cargo.toml`; `scripts/sync-version.mjs` keeps them and the npm packages in step. The workspace layout, npm launcher packages and platform packages are described in [docs/packages.md](../docs/packages.md).
|
|
92
88
|
|
|
93
89
|
## Programmatic Usage (Rust)
|
|
94
90
|
|
|
@@ -106,33 +102,41 @@ println!("Found {} clones", result.clones.len());
|
|
|
106
102
|
println!("Analyzed {} files", result.statistics.total.sources);
|
|
107
103
|
```
|
|
108
104
|
|
|
109
|
-
|
|
105
|
+
See [docs/api.md](../docs/api.md) and [examples/rust-cpd-finder](../examples/rust-cpd-finder).
|
|
106
|
+
|
|
107
|
+
## Building and testing
|
|
110
108
|
|
|
111
|
-
Requires Rust 1.
|
|
109
|
+
Requires Rust 1.96+ (the MSRV declared in `Cargo.toml`, enforced by the `msrv`
|
|
110
|
+
job in CI). Development uses the exact toolchain pinned in `rust-toolchain.toml`.
|
|
112
111
|
|
|
113
112
|
```bash
|
|
114
113
|
cargo build --release
|
|
115
|
-
cargo test
|
|
114
|
+
cargo nextest run --workspace # or: cargo test --workspace
|
|
115
|
+
cargo clippy --workspace --all-targets -- -D warnings
|
|
116
|
+
cargo fmt --all --check
|
|
117
|
+
|
|
118
|
+
# End-to-end run over the multi-format corpus (what CI's smoke job does)
|
|
119
|
+
./target/release/jscpd ../fixtures --reporters console,json --output ../smoke-report --min-tokens 50
|
|
116
120
|
```
|
|
117
121
|
|
|
118
|
-
|
|
122
|
+
After changing the format table in `crates/cpd-tokenizer/src/formats.rs`, regenerate the root [FORMATS.md](../FORMATS.md) with `node scripts/gen-formats-md.mjs`.
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
- **[docs/typescript.md](../docs/typescript.md)** — TypeScript/Node.js engine (v4.x) documentation
|
|
122
|
-
- **[docs/ai-ready.md](../docs/ai-ready.md)** — AI reporter, agent skills, MCP server
|
|
123
|
-
- **[docs/api.md](../docs/api.md)** — Programming APIs (TypeScript and Rust)
|
|
124
|
+
## Benchmarks
|
|
124
125
|
|
|
125
|
-
|
|
126
|
+
Compared against other copy/paste detectors (jscpd-rs, Duplo, Fallow, Simian, PMD CPD) on the repository's `fixtures/` corpus — timing, detection counts, cross-format detection and AI-token efficiency — in [benchmark/BENCHMARK.md](../benchmark/BENCHMARK.md). Re-run with [`benchmark/benchmark.sh`](../benchmark/benchmark.sh).
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
## Documentation
|
|
129
|
+
|
|
130
|
+
- **[docs/rust.md](../docs/rust.md)** — Full CLI reference, all options, reporters, baseline, summary, config file
|
|
131
|
+
- **[docs/ai-ready.md](../docs/ai-ready.md)** — AI reporter, agent skills, MCP server
|
|
132
|
+
- **[docs/api.md](../docs/api.md)** — Rust API
|
|
133
|
+
- **[docs/ci-and-hooks.md](../docs/ci-and-hooks.md)** — GitHub Action, Docker, pre-commit hooks
|
|
134
|
+
- **[CHANGELOG.md](CHANGELOG.md)** — Release notes
|
|
132
135
|
|
|
133
|
-
|
|
136
|
+
## Coming from jscpd v4?
|
|
134
137
|
|
|
138
|
+
The CLI flags, `.jscpd.json` config and reporters are the same; see the [migration table](../docs/rust.md#migrating-from-jscpd-v4) for the few differences. jscpd v4 (TypeScript engine, Node.js API, LevelDB/Redis stores) is maintained on the [`master-v4`](https://github.com/kucherenko/jscpd/tree/master-v4) branch and published as `jscpd@4`.
|
|
135
139
|
|
|
136
140
|
## License
|
|
137
141
|
|
|
138
|
-
MIT
|
|
142
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cpd",
|
|
3
|
-
"version": "5.1.
|
|
4
|
-
"description": "Copy/paste detector —
|
|
3
|
+
"version": "5.1.2",
|
|
4
|
+
"description": "Copy/paste detector for programming source code — Rust engine, self-contained binary, installs the cpd command",
|
|
5
5
|
"homepage": "https://jscpd.dev",
|
|
6
|
+
"funding": "https://opencollective.com/jscpd",
|
|
6
7
|
"bin": {
|
|
7
8
|
"cpd": "./run-cpd.js"
|
|
8
9
|
},
|
|
@@ -11,13 +12,14 @@
|
|
|
11
12
|
"platform-map.js"
|
|
12
13
|
],
|
|
13
14
|
"optionalDependencies": {
|
|
14
|
-
"jscpd-linux-x64-gnu": "5.1.
|
|
15
|
-
"jscpd-linux-arm64-gnu": "5.1.
|
|
16
|
-
"jscpd-linux-x64-musl": "5.1.
|
|
17
|
-
"jscpd-
|
|
18
|
-
"jscpd-darwin-
|
|
19
|
-
"jscpd-
|
|
20
|
-
"jscpd-windows-
|
|
15
|
+
"jscpd-linux-x64-gnu": "5.1.2",
|
|
16
|
+
"jscpd-linux-arm64-gnu": "5.1.2",
|
|
17
|
+
"jscpd-linux-x64-musl": "5.1.2",
|
|
18
|
+
"jscpd-linux-arm64-musl": "5.1.2",
|
|
19
|
+
"jscpd-darwin-arm64": "5.1.2",
|
|
20
|
+
"jscpd-darwin-x64": "5.1.2",
|
|
21
|
+
"jscpd-windows-x64-msvc": "5.1.2",
|
|
22
|
+
"jscpd-windows-arm64-msvc": "5.1.2"
|
|
21
23
|
},
|
|
22
24
|
"repository": {
|
|
23
25
|
"type": "git",
|
package/platform-map.js
CHANGED
|
@@ -27,6 +27,14 @@ const PLATFORM_MAP = {
|
|
|
27
27
|
rustTarget: "x86_64-unknown-linux-musl",
|
|
28
28
|
runner: "ubuntu-latest",
|
|
29
29
|
},
|
|
30
|
+
"linux-arm64-musl": {
|
|
31
|
+
packageName: "jscpd-linux-arm64-musl",
|
|
32
|
+
os: "linux",
|
|
33
|
+
cpu: "arm64",
|
|
34
|
+
libc: "musl",
|
|
35
|
+
rustTarget: "aarch64-unknown-linux-musl",
|
|
36
|
+
runner: "ubuntu-22.04-arm",
|
|
37
|
+
},
|
|
30
38
|
"darwin-arm64": {
|
|
31
39
|
packageName: "jscpd-darwin-arm64",
|
|
32
40
|
os: "darwin",
|
|
@@ -88,4 +96,24 @@ function getPlatformKey() {
|
|
|
88
96
|
return undefined;
|
|
89
97
|
}
|
|
90
98
|
|
|
91
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Human-readable description of the host, e.g. "linux/arm64 (musl)", for
|
|
101
|
+
* error messages.
|
|
102
|
+
*/
|
|
103
|
+
function describeHost() {
|
|
104
|
+
const libc = detectLinuxLibc();
|
|
105
|
+
return `${platform}/${arch}${libc ? ` (${libc})` : ""}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Supported platform keys, e.g. ["linux-x64-gnu", ...]. */
|
|
109
|
+
function supportedPlatforms() {
|
|
110
|
+
return Object.keys(PLATFORM_MAP);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
PLATFORM_MAP,
|
|
115
|
+
getPlatformKey,
|
|
116
|
+
detectLinuxLibc,
|
|
117
|
+
describeHost,
|
|
118
|
+
supportedPlatforms,
|
|
119
|
+
};
|
package/run-cpd.js
CHANGED
|
@@ -3,12 +3,24 @@
|
|
|
3
3
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const { spawnSync } = require("child_process");
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
getPlatformKey,
|
|
8
|
+
PLATFORM_MAP,
|
|
9
|
+
describeHost,
|
|
10
|
+
supportedPlatforms,
|
|
11
|
+
} = require("./platform-map");
|
|
7
12
|
|
|
8
13
|
const key = getPlatformKey();
|
|
9
14
|
if (!key) {
|
|
10
15
|
console.error(
|
|
11
|
-
`cpd:
|
|
16
|
+
`cpd: no prebuilt binary for this platform: ${describeHost()}`
|
|
17
|
+
);
|
|
18
|
+
console.error(
|
|
19
|
+
`cpd: supported platforms: ${supportedPlatforms().join(", ")}`
|
|
20
|
+
);
|
|
21
|
+
console.error(
|
|
22
|
+
"cpd: build from source instead with `cargo install jscpd` " +
|
|
23
|
+
"(https://github.com/kucherenko/jscpd/tree/master/rust)"
|
|
12
24
|
);
|
|
13
25
|
process.exit(1);
|
|
14
26
|
}
|