<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Viacheslav Bogdanov</title>
    <description>The latest articles on DEV Community by Viacheslav Bogdanov (@vvbogdanov).</description>
    <link>https://dev.to/vvbogdanov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2024241%2F51104694-e5e1-44f6-9e41-c386c638ed8c.jpg</url>
      <title>DEV Community: Viacheslav Bogdanov</title>
      <link>https://dev.to/vvbogdanov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vvbogdanov"/>
    <language>en</language>
    <item>
      <title>Add a 50x+ faster duplicate-code gate to GitHub Actions with jscpd-rs</title>
      <dc:creator>Viacheslav Bogdanov</dc:creator>
      <pubDate>Thu, 04 Jun 2026 06:46:24 +0000</pubDate>
      <link>https://dev.to/vvbogdanov/add-a-50x-faster-duplicate-code-gate-to-github-actions-with-jscpd-rs-kml</link>
      <guid>https://dev.to/vvbogdanov/add-a-50x-faster-duplicate-code-gate-to-github-actions-with-jscpd-rs-kml</guid>
      <description>&lt;p&gt;Duplicate-code checks are useful, but they often become one more slow quality gate that teams run less often than they should.&lt;/p&gt;

&lt;p&gt;That trade-off is getting worse. Large teams already create repeated code through parallel feature work. AI coding agents make code generation even cheaper, which also makes accidental copy-paste cheaper to create. Reviewers still need deterministic checks that catch repetition before it settles into the codebase.&lt;/p&gt;

&lt;p&gt;This post shows how to add a fast duplicate-code gate to GitHub Actions with &lt;a href="https://github.com/vv-bogdanov/jscpd-rs" rel="noopener noreferrer"&gt;&lt;code&gt;jscpd-rs&lt;/code&gt;&lt;/a&gt;, a native Rust implementation of the common &lt;a href="https://github.com/kucherenko/jscpd" rel="noopener noreferrer"&gt;&lt;code&gt;jscpd&lt;/code&gt;&lt;/a&gt; workflow.&lt;/p&gt;

&lt;p&gt;If you only want the CI snippet, jump to the GitHub Actions workflow below and adjust the threshold and ignore list for your repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is jscpd?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;jscpd&lt;/code&gt; is a copy-paste detector for source code. It scans a project, finds duplicated fragments across files, writes reports for humans and CI systems, and can fail a build when the duplicated-line percentage crosses a configured threshold.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jscpd-rs&lt;/code&gt; keeps the familiar workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scan source trees from the CLI;&lt;/li&gt;
&lt;li&gt;load &lt;code&gt;.jscpd.json&lt;/code&gt; or &lt;code&gt;package.json#jscpd&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;generate console, JSON, SARIF, HTML, XML, CSV, Markdown, badge, and Xcode reports;&lt;/li&gt;
&lt;li&gt;fail CI on a threshold;&lt;/li&gt;
&lt;li&gt;expose the &lt;code&gt;jscpd&lt;/code&gt;, &lt;code&gt;jscpd-rs&lt;/code&gt;, and &lt;code&gt;jscpd-server&lt;/code&gt; command names.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference is the hot path: file discovery, tokenization, matching, and reporting run natively in Rust. The npm package uses prebuilt platform binaries for Linux, macOS, and Windows. On those platforms, npm users do not need a Rust toolchain just to run the check. Unsupported platforms can install the CLI through Cargo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick local check
&lt;/h2&gt;

&lt;p&gt;Try it locally before putting it in CI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;--yes&lt;/span&gt; jscpd-rs &lt;span class="nt"&gt;--threshold&lt;/span&gt; 5 &lt;span class="nt"&gt;--exitCode&lt;/span&gt; 1 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That command scans the current project and exits with code &lt;code&gt;1&lt;/code&gt; if duplication is above 5%.&lt;/p&gt;

&lt;p&gt;The examples use &lt;code&gt;npx --yes&lt;/code&gt; so CI does not stop on an interactive package install prompt.&lt;/p&gt;

&lt;p&gt;For a more useful first run, write machine-readable reports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;--yes&lt;/span&gt; jscpd-rs &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--threshold&lt;/span&gt; 5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--exitCode&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--reporters&lt;/span&gt; console,json,sarif,html &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; report &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ignore&lt;/span&gt; &lt;span class="s2"&gt;"node_modules/**"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ignore&lt;/span&gt; &lt;span class="s2"&gt;"dist/**"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ignore&lt;/span&gt; &lt;span class="s2"&gt;"coverage/**"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--ignore&lt;/span&gt; &lt;span class="s2"&gt;"target/**"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important outputs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;terminal summary from &lt;code&gt;console&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;report/jscpd-report.json&lt;/code&gt; for scripts;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;report/jscpd-sarif.json&lt;/code&gt; for GitHub Code Scanning;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;report/html/&lt;/code&gt; for a browsable local report.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Add it to GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;.github/workflows/duplicate-code.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;duplicate-code&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jscpd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
      &lt;span class="na"&gt;security-events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v5&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;22&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run duplicate-code check&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;npx --yes jscpd-rs \&lt;/span&gt;
            &lt;span class="s"&gt;--threshold 5 \&lt;/span&gt;
            &lt;span class="s"&gt;--exitCode 1 \&lt;/span&gt;
            &lt;span class="s"&gt;--reporters console,json,sarif \&lt;/span&gt;
            &lt;span class="s"&gt;--output report \&lt;/span&gt;
            &lt;span class="s"&gt;--ignore "node_modules/**" \&lt;/span&gt;
            &lt;span class="s"&gt;--ignore "dist/**" \&lt;/span&gt;
            &lt;span class="s"&gt;--ignore "coverage/**" \&lt;/span&gt;
            &lt;span class="s"&gt;--ignore "target/**" \&lt;/span&gt;
            &lt;span class="s"&gt;.&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload SARIF&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github/codeql-action/upload-sarif@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;sarif_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;report/jscpd-sarif.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you do not use GitHub Code Scanning, remove the &lt;code&gt;security-events: write&lt;/code&gt; permission and the &lt;code&gt;Upload SARIF&lt;/code&gt; step.&lt;/p&gt;

&lt;p&gt;The duplicate-code step is still the gate. The SARIF upload only makes findings visible in the GitHub Security tab and code-scanning UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use a config file for real projects
&lt;/h2&gt;

&lt;p&gt;For a real repository, I prefer moving the policy into &lt;code&gt;.jscpd.json&lt;/code&gt; and keeping the CI command short:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"minLines"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"minTokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reporters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"console"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sarif"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"report"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ignore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"node_modules/**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"dist/**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"coverage/**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"target/**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;".next/**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"generated/**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"**/*.snap"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"gitignore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"noTips"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the workflow step becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run duplicate-code check&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx --yes jscpd-rs .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is easier to maintain because the threshold, ignored paths, and reporters live with the code-quality policy instead of being hidden inside YAML.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing a threshold
&lt;/h2&gt;

&lt;p&gt;Start with a threshold that does not block the whole team on day one.&lt;/p&gt;

&lt;p&gt;For existing codebases, I usually recommend:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the tool without failing CI and inspect the report.&lt;/li&gt;
&lt;li&gt;Ignore generated files, build output, snapshots, and vendored code.&lt;/li&gt;
&lt;li&gt;Set the threshold slightly above the current duplicated percentage.&lt;/li&gt;
&lt;li&gt;Ratchet it down over time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a new project, a stricter threshold is reasonable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;--yes&lt;/span&gt; jscpd-rs &lt;span class="nt"&gt;--threshold&lt;/span&gt; 3 &lt;span class="nt"&gt;--exitCode&lt;/span&gt; 1 src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The point is not to delete every repeated line immediately. The point is to stop new accidental duplication from entering silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why speed matters
&lt;/h2&gt;

&lt;p&gt;Slow checks are the first checks teams disable, move to nightly jobs, or run only before releases. That is exactly the wrong place for duplicate-code detection: copy-paste is cheapest to fix when the pull request is still fresh.&lt;/p&gt;

&lt;p&gt;The current public benchmark suite for &lt;code&gt;jscpd-rs&lt;/code&gt; uses pinned React, Next.js, and Prometheus revisions and compares against upstream &lt;code&gt;jscpd&lt;/code&gt; with the same high-level inputs and options:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Case&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;jscpd-rs avg&lt;/th&gt;
&lt;th&gt;upstream jscpd avg&lt;/th&gt;
&lt;th&gt;Speedup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;React &lt;code&gt;f0dfee3&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;0.197325s&lt;/td&gt;
&lt;td&gt;10.413453s&lt;/td&gt;
&lt;td&gt;52.77x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Next.js &lt;code&gt;2bbb67b9&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;0.270786s&lt;/td&gt;
&lt;td&gt;14.983243s&lt;/td&gt;
&lt;td&gt;55.33x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prometheus &lt;code&gt;a0524ee&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;0.083162s&lt;/td&gt;
&lt;td&gt;4.842499s&lt;/td&gt;
&lt;td&gt;58.23x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Those numbers are not a guarantee that every repository will see the same ratio. They are a public baseline for the current release gate: large enough to be useful, pinned enough to be reproducible, and focused on the kind of check you would actually run in CI.&lt;/p&gt;

&lt;p&gt;The benchmark table is also published in the &lt;a href="https://github.com/vv-bogdanov/jscpd-rs#performance" rel="noopener noreferrer"&gt;README performance section&lt;/a&gt;, along with the release-candidate command used to rerun the public suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compatibility model
&lt;/h2&gt;

&lt;p&gt;The goal is practical compatibility with upstream &lt;code&gt;jscpd&lt;/code&gt;, not a new tool with similar-looking output.&lt;/p&gt;

&lt;p&gt;For the current 0.x releases, the compatibility gate is coverage-first: on the same inputs and options, &lt;code&gt;jscpd-rs&lt;/code&gt; must not miss duplicated source lines reported by upstream &lt;code&gt;jscpd&lt;/code&gt;. Extra Rust findings are visible in compatibility reports and treated as follow-up work when they are noisy.&lt;/p&gt;

&lt;p&gt;That model is useful for CI adoption because missing real duplicated ranges is the dangerous failure mode. Exact clone-pair identity can differ, especially for multi-way clones, while still covering the same duplicated source ranges.&lt;/p&gt;

&lt;p&gt;There are also intentional first-release limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dynamic npm reporters, stores, listeners, and plugins are not loaded;&lt;/li&gt;
&lt;li&gt;HTML output is practical and self-contained, not pixel-perfect;&lt;/li&gt;
&lt;li&gt;exact token totals may differ from upstream;&lt;/li&gt;
&lt;li&gt;this is a native CLI and Rust library, not a JavaScript package API clone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  npm or Cargo?
&lt;/h2&gt;

&lt;p&gt;Use npm when Node is already part of your workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; jscpd-rs
jscpd &lt;span class="nt"&gt;--threshold&lt;/span&gt; 5 &lt;span class="nt"&gt;--exitCode&lt;/span&gt; 1 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or run it without a global install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;--yes&lt;/span&gt; jscpd-rs &lt;span class="nt"&gt;--threshold&lt;/span&gt; 5 &lt;span class="nt"&gt;--exitCode&lt;/span&gt; 1 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use Cargo when Rust is the natural toolchain for the project or when npm prebuilt binaries are not available for your platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo &lt;span class="nb"&gt;install &lt;/span&gt;jscpd-rs &lt;span class="nt"&gt;--locked&lt;/span&gt;
jscpd &lt;span class="nt"&gt;--threshold&lt;/span&gt; 5 &lt;span class="nt"&gt;--exitCode&lt;/span&gt; 1 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where to go next
&lt;/h2&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository: &lt;a href="https://github.com/vv-bogdanov/jscpd-rs" rel="noopener noreferrer"&gt;https://github.com/vv-bogdanov/jscpd-rs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;npm package: &lt;a href="https://www.npmjs.com/package/jscpd-rs" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/jscpd-rs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;crates.io: &lt;a href="https://crates.io/crates/jscpd-rs" rel="noopener noreferrer"&gt;https://crates.io/crates/jscpd-rs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;docs.rs: &lt;a href="https://docs.rs/jscpd-rs" rel="noopener noreferrer"&gt;https://docs.rs/jscpd-rs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;User guide: &lt;a href="https://github.com/vv-bogdanov/jscpd-rs/blob/main/docs/user-guide.md" rel="noopener noreferrer"&gt;https://github.com/vv-bogdanov/jscpd-rs/blob/main/docs/user-guide.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Migration notes: &lt;a href="https://github.com/vv-bogdanov/jscpd-rs/blob/main/docs/migrating-from-jscpd.md" rel="noopener noreferrer"&gt;https://github.com/vv-bogdanov/jscpd-rs/blob/main/docs/migrating-from-jscpd.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Longer launch note: &lt;a href="https://vv-bogdanov.github.io/posts/fast-duplicate-code-detection-for-agents/" rel="noopener noreferrer"&gt;https://vv-bogdanov.github.io/posts/fast-duplicate-code-detection-for-agents/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would especially like feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repositories where &lt;code&gt;jscpd-rs&lt;/code&gt; misses duplicates found by upstream &lt;code&gt;jscpd&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;report compatibility issues in JSON, SARIF, HTML, XML, CSV, or Markdown;&lt;/li&gt;
&lt;li&gt;npm install friction on Linux, macOS, or Windows;&lt;/li&gt;
&lt;li&gt;public benchmark cases that represent real monorepos;&lt;/li&gt;
&lt;li&gt;formats where generic tokenization is too noisy or not sensitive enough.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If duplicate-code checks are currently too slow to keep in every pull request, try running this once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;--yes&lt;/span&gt; jscpd-rs &lt;span class="nt"&gt;--threshold&lt;/span&gt; 5 &lt;span class="nt"&gt;--exitCode&lt;/span&gt; 1 &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should be enough to see whether the check is cheap enough for your normal CI loop.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>performance</category>
      <category>devops</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
