New Features
-
A language server:
jscpd --lsp. An editor starts jscpd for a workspace, and the files you edit get what jscpd finds as diagnostics that follow the text in the editor, saved or not. After 300 ms without typing, the server tokenizes the file again from the buffer and searches its detection pool again from the tokens it keeps for the rest of the project.- The server runs five analyses: clones (exact, renamed and near-miss copies), similar functions (
--similarity), semantic clones (--semantic), dead code (--dead-code) and complexity, with a limit of 15 per function and the complex-file bar of the health score per file. Only clones are on unless you turn the others on, with--lsp-analyses, with thelspsection of.jscpd.json, or from the editor's settings, and each place wins over the one before it. - The code of each diagnostic is the id of its rule, the one the SARIF reporters write for clones and dead code. A clone is a warning, as in SARIF, and
lsp.clones.warningTokenslowers the smaller ones to information. Dead code is a hint that editors fade. - Each
.jscpd.jsonin the workspace makes its folder a project of its own, and clones are found within a project. A workspace with no config is one project across all its folders. - A clone comes with "Go to the other copy" and "Ignore this clone", which wraps the fragment in
jscpd:ignore-startandjscpd:ignore-endcomments. Dead code and semantic clones run in the background after a save, and the progress of each run ends with what it found, such as94 files, 13 clones. - Editor clients can ask for the whole project's clones, semantic pairs, dead code, complexity and statistics with custom requests.
- docs/editors.md has the setup for Neovim, Helix, Sublime Text, Emacs and JetBrains IDEs, and
fixtures/lsp-demois a project that shows each analysis. (#1120, #1121, #1122)
- The server runs five analyses: clones (exact, renamed and near-miss copies), similar functions (
-
Comparing two codebases, experimental:
--compare.jscpd --compare source targetpairs the functions of two folders with the--semanticmodel and reports which functions of each side have a counterpart in the other. During a port to another language or platform, that is what is still to port; for two implementations of one app, it is what only one of them has.- A function pairs with its counterpart when the model finds them each other's closest match. A short function the model cannot place pairs by name when the names match once case and underscores are ignored and the code is similar enough. Every pair has its similarity and a level,
high,mediumorlow, and the report lists the pairs under other names on their own. - Tests and code are measured apart, and a test pairs only with a test. jscpd tells a test by the conventions of its language, such as
*_test.go,test_*.py,*.test.tsor Rust's#[cfg(test)], and JavaScript test cases take part under their titles. - The console, JSON and Markdown reporters print the totals per side and per file, the functions with no counterpart and the pairs.
-r htmlwrites a migration map: both sides as dependency graphs with the pairs bridging them, a table of the same pairs, and the functions ready to port, whose callees all have a counterpart already. The JSON report lists those asreadyToPort. - On the Java and Python versions of nayuki/QR-Code-generator, it paired 30 of 41 Java functions with no wrong pair.
fixtures/compare-demois a runnable example. (#1115, #1118, #1119)
- A function pairs with its counterpart when the model finds them each other's closest match. A short function the model cannot place pairs by name when the names match once case and underscores are ignored and the code is similar enough. Every pair has its similarity and a level,
-
Agent skills for ports.
compare-codebasesexplains how--comparepairs functions and how to check a comparison.code-migrationports a codebase tests first, binds tests to code by coverage, and takes the next function to port from--compare. Install them withnpx skills add kucherenko/jscpd --skill <name>. (#1115, #1117)
Changes
- Pairs from
--similarityhave a SARIF rule of their own,jscpd/similar-function. Thesimilarkind comes from two mechanisms that find different things, and SARIF filed both underjscpd/similar-code. That rule now keeps the copies merged across a gap (--max-gap-lines), and Code Climate'scheck_namefollows. GitHub code scanning matches alerts by rule, so the first upload of--similarityresults after the update closes the old alerts and opens the same findings under the new rule. (#1121)
Other
- A failed
cargo publishnow fails the release job instead of passing it. (#1116)
Published Packages
basta@0.3.0on crates.iocpd-core@0.1.20on crates.iocpd-finder@0.1.20on crates.iocpd-reporter@0.1.21on crates.iocpd-semantic@0.1.1on crates.iocpd-tokenizer@0.1.19on crates.iojscpd@5.4.0on crates.iocpd@5.4.0on npmjscpd@5.4.0on npmjscpd-darwin-arm64@5.4.0on npmjscpd-darwin-x64@5.4.0on npmjscpd-linux-x64-gnu@5.4.0on npmjscpd-linux-arm64-gnu@5.4.0on npmjscpd-linux-x64-musl@5.4.0on npmjscpd-linux-arm64-musl@5.4.0on npmjscpd-windows-x64-msvc@5.4.0on npmjscpd-windows-arm64-msvc@5.4.0on npmjscpd==5.4.0on PyPI
Verify
Archives are signed with Sigstore (keyless, <asset>.sigstore.json)
and carry SLSA build provenance. Replace jscpd-linux-x64-gnu.tar.gz with your asset:
cosign verify-blob \
--bundle jscpd-linux-x64-gnu.tar.gz.sigstore.json \
--certificate-identity-regexp '^https://github\.com/kucherenko/jscpd/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
jscpd-linux-x64-gnu.tar.gz
gh attestation verify jscpd-linux-x64-gnu.tar.gz --repo kucherenko/jscpd
sha256sum --check --ignore-missing checksums.txt