[{"data":1,"prerenderedAt":3590},["ShallowReactive",2],{"navigation_docs":3,"-project-changelog":239,"-project-changelog-surround":3585},[4,29,94,114,184],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"Start",false,"\u002Fstart","1.start",[10,14,19,24],{"title":11,"path":7,"stem":12,"icon":13},"What jscpd finds","1.start\u002Findex","i-lucide-house",{"title":15,"path":16,"stem":17,"icon":18},"Installation","\u002Fstart\u002Finstallation","1.start\u002F2.installation","i-lucide-download",{"title":20,"path":21,"stem":22,"icon":23},"Quickstart","\u002Fstart\u002Fquickstart","1.start\u002F3.quickstart","i-lucide-rocket",{"title":25,"path":26,"stem":27,"icon":28},"Configuration basics","\u002Fstart\u002Fconfiguration","1.start\u002F4.configuration","i-lucide-settings-2",{"title":30,"icon":6,"path":31,"stem":32,"children":33,"page":6},"Guides","\u002Fguides","2.guides",[34,39,44,49,54,59,64,69,74,79,84,89],{"title":35,"path":36,"stem":37,"icon":38},"Use jscpd in CI","\u002Fguides\u002Fci","2.guides\u002F01.ci","i-lucide-github",{"title":40,"path":41,"stem":42,"icon":43},"Pre-commit hooks","\u002Fguides\u002Fpre-commit","2.guides\u002F02.pre-commit","i-lucide-git-commit",{"title":45,"path":46,"stem":47,"icon":48},"Fail only on new duplication","\u002Fguides\u002Fbaseline","2.guides\u002F03.baseline","i-lucide-git-compare",{"title":50,"path":51,"stem":52,"icon":53},"Monorepos","\u002Fguides\u002Fmonorepos","2.guides\u002F04.monorepos","i-lucide-folder-tree",{"title":55,"path":56,"stem":57,"icon":58},"Cross-format detection","\u002Fguides\u002Fcross-format","2.guides\u002F05.cross-format","i-lucide-layers",{"title":60,"path":61,"stem":62,"icon":63},"Agents","\u002Fguides\u002Fagents","2.guides\u002F06.agents","i-lucide-cpu",{"title":65,"path":66,"stem":67,"icon":68},"Editors","\u002Fguides\u002Feditors","2.guides\u002F07.editors","i-lucide-code",{"title":70,"path":71,"stem":72,"icon":73},"Duplication over git history","\u002Fguides\u002Fhistory","2.guides\u002F08.history","i-lucide-chart-no-axes-combined",{"title":75,"path":76,"stem":77,"icon":78},"Dashboard and health score","\u002Fguides\u002Fdashboard","2.guides\u002F09.dashboard","i-lucide-layout-dashboard",{"title":80,"path":81,"stem":82,"icon":83},"Dead code","\u002Fguides\u002Fdead-code","2.guides\u002F10.dead-code","i-lucide-ghost",{"title":85,"path":86,"stem":87,"icon":88},"Comparing two codebases","\u002Fguides\u002Fcompare","2.guides\u002F11.compare","i-lucide-git-compare-arrows",{"title":90,"path":91,"stem":92,"icon":93},"Semantic clones","\u002Fguides\u002Fsemantic-clones","2.guides\u002F12.semantic-clones","i-lucide-brain-circuit",{"title":95,"icon":6,"path":96,"stem":97,"children":98,"page":6},"Concepts","\u002Fconcepts","3.concepts",[99,104,109],{"title":100,"path":101,"stem":102,"icon":103},"Types of code clones","\u002Fconcepts\u002Fclone-types","3.concepts\u002F1.clone-types","i-lucide-copy",{"title":105,"path":106,"stem":107,"icon":108},"How detection works","\u002Fconcepts\u002Fhow-detection-works","3.concepts\u002F2.how-detection-works","i-lucide-scan-search",{"title":110,"path":111,"stem":112,"icon":113},"The health score","\u002Fconcepts\u002Fhealth-score","3.concepts\u002F3.health-score","i-lucide-heart-pulse",{"title":115,"icon":6,"path":116,"stem":117,"children":118,"page":6},"Reference","\u002Freference","4.reference",[119,124,129,134,171,176,180],{"title":120,"path":121,"stem":122,"icon":123},"CLI options","\u002Freference\u002Fcli","4.reference\u002F1.cli","i-lucide-terminal",{"title":125,"path":126,"stem":127,"icon":128},"The config file","\u002Freference\u002Fconfig-file","4.reference\u002F2.config-file","i-lucide-settings",{"title":130,"path":131,"stem":132,"icon":133},"Exit codes","\u002Freference\u002Fexit-codes","4.reference\u002F3.exit-codes","i-lucide-log-out",{"title":135,"icon":6,"path":136,"stem":137,"children":138},"Reporters","\u002Freference\u002Freporters","4.reference\u002F4.reporters\u002Findex",[139,141,146,151,156,161,166],{"title":135,"path":136,"stem":137,"icon":140},"i-lucide-file-chart-column",{"title":142,"path":143,"stem":144,"icon":145},"HTML reporter","\u002Freference\u002Freporters\u002Fhtml","4.reference\u002F4.reporters\u002F2.html","i-lucide-file-code",{"title":147,"path":148,"stem":149,"icon":150},"JSON reporter","\u002Freference\u002Freporters\u002Fjson","4.reference\u002F4.reporters\u002F3.json","i-lucide-braces",{"title":152,"path":153,"stem":154,"icon":155},"Badge reporter","\u002Freference\u002Freporters\u002Fbadge","4.reference\u002F4.reporters\u002F4.badge","i-lucide-award",{"title":157,"path":158,"stem":159,"icon":160},"SARIF reporter","\u002Freference\u002Freporters\u002Fsarif","4.reference\u002F4.reporters\u002F5.sarif","i-lucide-shield-check",{"title":162,"path":163,"stem":164,"icon":165},"CodeClimate reporter","\u002Freference\u002Freporters\u002Fcodeclimate","4.reference\u002F4.reporters\u002F6.codeclimate","i-lucide-flag-triangle-right",{"title":167,"path":168,"stem":169,"icon":170},"OpenMetrics reporter","\u002Freference\u002Freporters\u002Fopenmetrics","4.reference\u002F4.reporters\u002F7.openmetrics","i-lucide-activity",{"title":172,"path":173,"stem":174,"icon":175},"Supported formats","\u002Freference\u002Fsupported-formats","4.reference\u002F5.supported-formats","i-lucide-languages",{"title":177,"path":178,"stem":179,"icon":38},"GitHub Action","\u002Freference\u002Fgithub-action","4.reference\u002F6.github-action",{"title":181,"path":182,"stem":183,"icon":68},"Rust crates","\u002Freference\u002Frust-crates","4.reference\u002F7.rust-crates",{"title":185,"icon":6,"path":186,"stem":187,"children":188,"page":6},"Project","\u002Fproject","5.project",[189,194,199,204,229,234],{"title":190,"path":191,"stem":192,"icon":193},"Changelog","\u002Fproject\u002Fchangelog","5.project\u002F1.changelog","i-lucide-scroll-text",{"title":195,"path":196,"stem":197,"icon":198},"Migrating from v4 to v5","\u002Fproject\u002Fmigration","5.project\u002F2.migration","i-lucide-arrow-right-left",{"title":200,"path":201,"stem":202,"icon":203},"jscpd v4 (TypeScript)","\u002Fproject\u002Fv4","5.project\u002F3.v4","i-simple-icons-typescript",{"title":205,"icon":6,"path":206,"stem":207,"children":208},"Benchmarks","\u002Fproject\u002Fbenchmarks","5.project\u002F4.benchmarks\u002Findex",[209,211,216,220,225],{"title":205,"path":206,"stem":207,"icon":210},"i-lucide-gauge",{"title":212,"path":213,"stem":214,"icon":215},"Detection Speed","\u002Fproject\u002Fbenchmarks\u002Fdetection-speed","5.project\u002F4.benchmarks\u002F2.detection-speed","i-lucide-zap",{"title":217,"path":218,"stem":219,"icon":58},"Multi-Format Detection","\u002Fproject\u002Fbenchmarks\u002Fcross-format","5.project\u002F4.benchmarks\u002F3.cross-format",{"title":221,"path":222,"stem":223,"icon":224},"AI Token Efficiency","\u002Fproject\u002Fbenchmarks\u002Fai-token-efficiency","5.project\u002F4.benchmarks\u002F4.ai-token-efficiency","i-lucide-sparkles",{"title":226,"path":227,"stem":228,"icon":93},"Embedding Models","\u002Fproject\u002Fbenchmarks\u002Fembedding-models","5.project\u002F4.benchmarks\u002F5.embedding-models",{"title":230,"path":231,"stem":232,"icon":233},"Research","\u002Fproject\u002Fresearch","5.project\u002F5.research","i-lucide-graduation-cap",{"title":235,"path":236,"stem":237,"icon":238},"Articles","\u002Fproject\u002Farticles","5.project\u002F6.articles","i-lucide-newspaper",{"id":240,"title":190,"body":241,"description":3577,"extension":3578,"links":3579,"meta":3580,"navigation":3581,"path":191,"seo":3582,"stem":192,"__hash__":3584},"docs\u002F5.project\u002F1.changelog.md",{"type":242,"value":243,"toc":3487},"minimark",[244,266,271,277,282,393,397,429,433,438,441,560,564,616,620,666,670,675,678,735,738,793,796,819,823,828,831,933,936,943,1052,1055,1072,1076,1081,1084,1252,1255,1336,1340,1355,1359,1364,1367,1467,1470,1534,1537,1600,1603,1618,1622,1627,1630,1835,1838,1909,1912,1939,1942,1988,1992,1997,2000,2063,2066,2147,2150,2228,2232,2237,2240,2282,2285,2300,2304,2307,2437,2440,2479,2482,2556,2560,2563,2650,2654,2668,2671,2688,2692,2695,2764,2767,2808,2811,2837,2841,2844,2892,2895,2911,2915,2991,3004,3008,3012,3019,3026,3029,3107,3111,3166,3170,3187,3191,3205,3209,3220,3224,3232,3236,3241,3245,3256,3260,3268,3272,3279,3283,3286,3368,3371,3418,3422,3427,3431,3473,3477],[245,246,247,248,255,256,265],"p",{},"For the full, up-to-date changelog, see the ",[249,250,254],"a",{"href":251,"rel":252},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fblob\u002Fmaster\u002Frust\u002FCHANGELOG.md",[253],"nofollow","v5 (Rust) changelog"," in the jscpd GitHub repository. The v4 (TypeScript) history lives on the ",[249,257,260,264],{"href":258,"rel":259},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fblob\u002Fmaster-v4\u002Fapps\u002Fjscpd\u002FCHANGELOG.md",[253],[261,262,263],"code",{},"master-v4"," branch",".",[267,268,270],"h2",{"id":269},"v540-latest","v5.4.0 (Latest)",[245,272,273],{},[274,275,276],"em",{},"Released 2026-09-30",[278,279,281],"h3",{"id":280},"new-features","New Features",[283,284,285,326,366],"ul",{},[286,287,288,295,296,299,300,303,304,307,308,313,314,319,320,325],"li",{},[289,290,291,292,265],"strong",{},"A language server: ",[261,293,294],{},"jscpd --lsp"," An editor starts jscpd for a workspace, and the files you edit get its findings as diagnostics that follow the text in the editor, saved or not. The server runs clones, similar functions, semantic clones, dead code and complexity. Only clones are on by default; ",[261,297,298],{},"--lsp-analyses",", the ",[261,301,302],{},"lsp"," section of ",[261,305,306],{},".jscpd.json"," or the editor's settings turn on the rest. A clone comes with \"Go to the other copy\" and \"Ignore this clone\". The ",[249,309,312],{"href":310,"rel":311},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fblob\u002Fmaster\u002Fdocs\u002Feditors.md",[253],"editors guide"," has the setup for Neovim, Helix, Sublime Text, Emacs and JetBrains IDEs. (",[249,315,318],{"href":316,"rel":317},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1121",[253],"#1121",", ",[249,321,324],{"href":322,"rel":323},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1122",[253],"#1122",")",[286,327,328,334,335,338,339,342,343,346,347,350,351,319,356,319,361,325],{},[289,329,330,331,265],{},"Comparing two codebases, experimental: ",[261,332,333],{},"--compare"," ",[261,336,337],{},"jscpd --compare source target"," pairs the functions of two folders with the ",[261,340,341],{},"--semantic"," model and reports which functions of each side have a counterpart in the other. During a port that is what is still to port, and for two implementations of one app it is what only one of them has. Tests and code are measured apart, and ",[261,344,345],{},"-r html"," draws a migration map with the functions ready to port. See ",[249,348,349],{"href":86},"Comparing Two Codebases",". (",[249,352,355],{"href":353,"rel":354},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1115",[253],"#1115",[249,357,360],{"href":358,"rel":359},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1118",[253],"#1118",[249,362,365],{"href":363,"rel":364},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1119",[253],"#1119",[286,367,368,334,371,374,375,378,379,381,382,350,385,319,388,325],{},[289,369,370],{},"Agent skills for ports.",[261,372,373],{},"compare-codebases"," shows how to compare two folders and check the result, and ",[261,376,377],{},"code-migration"," ports a codebase tests first, with ",[261,380,333],{}," as the progress measure. Install one with ",[261,383,384],{},"npx skills add kucherenko\u002Fjscpd --skill \u003Cname>",[249,386,355],{"href":353,"rel":387},[253],[249,389,392],{"href":390,"rel":391},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1117",[253],"#1117",[278,394,396],{"id":395},"changes","Changes",[283,398,399],{},[286,400,401,334,415,418,419,422,423,425,426,325],{},[289,402,403,404,407,408,411,412,265],{},"Pairs from ",[261,405,406],{},"--similarity"," have a ",[249,409,410],{"href":158},"SARIF"," rule of their own, ",[261,413,414],{},"jscpd\u002Fsimilar-function",[261,416,417],{},"jscpd\u002Fsimilar-code"," keeps the copies merged across a gap (",[261,420,421],{},"--max-gap-lines","). GitHub code scanning matches alerts by rule, so the first upload of ",[261,424,406],{}," results after the update closes the old alerts and opens the same findings under the new rule. (",[249,427,318],{"href":316,"rel":428},[253],[267,430,432],{"id":431},"v533","v5.3.3",[245,434,435],{},[274,436,437],{},"Released 2026-09-28",[278,439,281],{"id":440},"new-features-1",[283,442,443,482,513,540],{},[286,444,445,450,451,453,454,457,458,461,462,465,466,471,472,350,477,325],{},[289,446,447,448,265],{},"Semantic clones, experimental: ",[261,449,341],{}," Functions that do the same job with different code share no token run, so the other passes cannot match them. Examples are a rule that a Rust backend enforces and a Svelte frontend repeats, or two helpers that two people wrote for the same task. ",[261,452,341],{}," embeds every function with a code embedding model and reports two functions as a clone of kind ",[261,455,456],{},"semantic"," when each is the other's closest match. It reads JavaScript, TypeScript, JSX, TSX, Vue, Svelte, Astro, Python, Rust, Go, Java, Kotlin, C#, C, C++, PHP, Ruby, Scala and Swift, and finds pairs within one language (",[261,459,460],{},"--semantic-scope same",") and across languages (",[261,463,464],{},"--semantic-scope cross","). See the ",[249,467,470],{"href":468,"rel":469},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fblob\u002Fmaster\u002Ffixtures\u002Fsemantic-demo\u002FREADME.md",[253],"semantic demo"," and the ",[249,473,476],{"href":474,"rel":475},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fblob\u002Fmaster\u002Fdocs\u002Frust.md#semantic-clones-with---semantic-experimental",[253],"docs",[249,478,481],{"href":479,"rel":480},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1101",[253],"#1101",[286,483,484,487,488,491,492,495,496,499,500,350,503,319,508,325],{},[289,485,486],{},"The model runs inside jscpd."," The default model, CodeRankEmbed (MIT), runs on the CPU once ",[261,489,490],{},"jscpd --semantic-download"," has fetched it (548 MB, pinned by revision and SHA-256), so a scan makes no network call. ",[261,493,494],{},"jscpd --semantic-download jina-embeddings-v2-base-code"," fetches the second local model. ",[261,497,498],{},"--semantic-url"," sends the functions to an OpenAI-compatible embeddings API instead, and jscpd reads the API key only from ",[261,501,502],{},"JSCPD_SEMANTIC_API_KEY",[249,504,507],{"href":505,"rel":506},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1108",[253],"#1108",[249,509,512],{"href":510,"rel":511},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1110",[253],"#1110",[286,514,515,334,518,521,522,525,526,529,530,533,534,536,537,325],{},[289,516,517],{},"Thresholds for nine models.",[261,519,520],{},"jscpd --semantic-models"," lists the models jscpd has calibrated, with their thresholds and licenses. ",[261,523,524],{},"--semantic-model"," picks one, and the thresholds follow it; ",[261,527,528],{},"--semantic-threshold"," and ",[261,531,532],{},"--semantic-same-threshold"," set them by hand. ",[249,535,226],{"href":227}," compares the nine models. (",[249,538,507],{"href":505,"rel":539},[253],[286,541,542,545,546,549,550,319,555,325],{},[289,543,544],{},"A vector cache for each set of scanned paths."," A repeat run embeds only the functions whose code changed. jscpd drops stale vectors once they make up more than a quarter of a cache file, and ",[261,547,548],{},"--semantic-rebuild-cache"," embeds everything again. (",[249,551,554],{"href":552,"rel":553},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1103",[253],"#1103",[249,556,559],{"href":557,"rel":558},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1105",[253],"#1105",[278,561,563],{"id":562},"bug-fixes","Bug Fixes",[283,565,566,585,603],{},[286,567,568,571,572,575,576,579,580,325],{},[289,569,570],{},"A scan path inside another scanned its files twice."," With ",[261,573,574],{},"jscpd . src",", jscpd walked every file under ",[261,577,578],{},"src"," once for each path and reported each of those files as a clone of itself. It reads them once now. (",[249,581,584],{"href":582,"rel":583},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1106",[253],"#1106",[286,586,587,593,594,597,598,325],{},[289,588,589,590,265],{},"Svelte components lost two kinds of use to ",[261,591,592],{},"--dead-code"," A store read as ",[261,595,596],{},"$name",", and a name used only inside a template literal in the markup, were reported as unused. Both count as uses now. (",[249,599,602],{"href":600,"rel":601},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1102",[253],"#1102",[286,604,605,608,609,612,613,325],{},[289,606,607],{},"Positions in files with Windows line endings drifted."," The generic tokenizer lost a byte on every CRLF line, so the positions in the JSON report were off and ",[261,610,611],{},"--ignore-pattern"," removed the wrong tokens. Files with CRLF endings report true byte offsets now. (",[249,614,481],{"href":479,"rel":615},[253],[278,617,619],{"id":618},"other","Other",[283,621,622,644],{},[286,623,624,630,631,634,635,638,639,325],{},[289,625,626,629],{},[261,627,628],{},"--min-duplicated-lines"," never did anything, and now says so."," It prints a warning and will be removed in a later release. Use ",[261,632,633],{},"--threshold"," to fail on too much duplication, or ",[261,636,637],{},"--min-lines"," to set the smallest clone. (",[249,640,643],{"href":641,"rel":642},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1100",[253],"#1100",[286,645,646,652,653,656,657,660,661,325],{},[289,647,648,651],{},[261,649,650],{},"paste"," is gone from the build."," jscpd replaces the unmaintained crate (RUSTSEC-2024-0436) with its successor ",[261,654,655],{},"pastey",", so ",[261,658,659],{},"cargo audit"," passes without ignoring the advisory. (",[249,662,665],{"href":663,"rel":664},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1109",[253],"#1109",[267,667,669],{"id":668},"v532","v5.3.2",[245,671,672],{},[274,673,674],{},"Released 2026-09-23",[278,676,281],{"id":677},"new-features-2",[283,679,680,722],{},[286,681,682,687,688,691,692,695,696,699,700,529,703,706,707,710,711,529,714,350,717,325],{},[289,683,684,686],{},[261,685,592],{}," reads Rust dead code from the compiler."," jscpd does not parse Rust and does not need to: every ",[261,689,690],{},"cargo check"," already prints lines like ",[261,693,694],{},"function `reprint` is never used",", with real name resolution, trait dispatch and macro expansion behind them. Pipe that output in — ",[261,697,698],{},"cargo check --all-targets --message-format=json | jscpd . --dead-code --rust-diagnostics -"," — and the findings appear next to every other language, at 100% confidence. The same flag works for ",[261,701,702],{},"--dashboard",[261,704,705],{},"--health",", so a Rust project gets its health badge from the check it already runs, and the config file takes the file as ",[261,708,709],{},"rustDiagnostics",". See ",[249,712,713],{"href":111},"Project Health Score",[249,715,716],{"href":76},"Project Dashboard",[249,718,721],{"href":719,"rel":720},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1089",[253],"#1089",[286,723,724,727,728,731,732,325],{},[289,725,726],{},"Findings from a Rust test target are treated as test code",", reported only with ",[261,729,730],{},"--include-tests"," and then at 85%, the same way a test file is handled in any other language. Neither jscpd nor basta runs cargo itself, because that would execute the project's build scripts and procedural macros. (",[249,733,721],{"href":719,"rel":734},[253],[278,736,563],{"id":737},"bug-fixes-1",[283,739,740,776],{},[286,741,742,745,746,749,750,753,754,757,758,761,762,350,765,770,771,325],{},[289,743,744],{},"Text around an embedded code block was counted as code."," A ",[261,747,748],{},"ts"," block in Markdown or a ",[261,751,752],{},"\u003Cscript>"," in a Vue, Svelte or Astro component keeps the line numbers of the file it lives in, and the statistics read those numbers as if the block ran the whole way — so prose and templates landed in the embedded language's line counts, in the total and in the duplicated lines both. On a repository with about 3600 Markdown files the ",[261,755,756],{},"typescript"," row said 51.30% of lines were duplicated where the same code, scanned with ",[261,759,760],{},"-f typescript",", said 3.37%. An embedded source now counts the lines its blocks occupy, and a clone counts the block lines it covers. To tell whether an older report was affected, compare the two percentage columns: they measure the same duplication, so a line column sitting far below the token column was counting text that holds no code. See ",[249,763,764],{"href":106},"Embedded languages",[249,766,769],{"href":767,"rel":768},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1091",[253],"#1091",", closes ",[249,772,775],{"href":773,"rel":774},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F1090",[253],"#1090",[286,777,778,781,782,785,786,789,790,325],{},[289,779,780],{},"Every clone was one line short."," Duplicated lines came from ",[261,783,784],{},"end - start",", so a clone covering lines 10 through 19 counted nine — while the console printed ",[261,787,788],{},"10 lines"," for it. Line counts are inclusive now and both come from one place, so duplicated-line totals rise by about one line per clone, and percentages with them. (",[249,791,769],{"href":767,"rel":792},[253],[278,794,619],{"id":795},"other-1",[283,797,798],{},[286,799,800,801,319,809,529,814,265],{},"The dead-code engine in this release is basta 0.3.0, which is also published on its own: ",[249,802,805,808],{"href":803,"rel":804},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fbasta",[253],[261,806,807],{},"basta"," on npm",[249,810,813],{"href":811,"rel":812},"https:\u002F\u002Fcrates.io\u002Fcrates\u002Fbasta",[253],"crates.io",[249,815,818],{"href":816,"rel":817},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fbasta\u002Freleases\u002Ftag\u002Fv0.3.0",[253],"GitHub",[267,820,822],{"id":821},"v531","v5.3.1",[245,824,825],{},[274,826,827],{},"Released 2026-09-21",[278,829,281],{"id":830},"new-features-3",[283,832,833,856,877,918],{},[286,834,835,840,841,844,845,847,848,350,851,325],{},[289,836,837,839],{},[261,838,592],{}," now detects which frameworks a project uses."," A framework runs files that nothing imports: a router's pages, a runtime's plugin directories. basta, the dead-code engine, used to know three such cases. It now reads a built-in list of 56 frameworks (Next.js, Nuxt, WXT, Remix, SvelteKit, Astro, Angular, NestJS, Storybook, Vitest, Django and more) and keeps the files they load out of the report. A framework is detected from its config file, from the ",[261,842,843],{},"package.json"," dependencies, or from its section in ",[261,846,843],{},", separately for each package of a monorepo. The console report names what it found, for example ",[261,849,850],{},"Frameworks: next (apps\u002Fweb), vitest",[249,852,855],{"href":853,"rel":854},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1087",[253],"#1087",[286,857,858,861,862,865,866,869,870,873,874,325],{},[289,859,860],{},"Names a framework reads are never reported."," Next calls a page's ",[261,863,864],{},"getServerSideProps",", Remix a route's ",[261,867,868],{},"loader",", Angular a component's ",[261,871,872],{},"ngOnInit",". A framework definition can list such names, limited to the files the framework reads them from. A declaration with one of these names counts as used, and so does everything it calls. (",[249,875,855],{"href":853,"rel":876},[253],[286,878,879,884,885,888,889,892,893,895,896,319,899,319,902,319,905,908,909,911,912,350,915,325],{},[289,880,881,883],{},[261,882,306],{}," can hold dead-code settings in a section of their own."," The ",[261,886,887],{},"deadCode"," key (also ",[261,890,891],{},"dead-code"," or ",[261,894,807],{},") can now be an object: ",[261,897,898],{},"minConfidence",[261,900,901],{},"entry",[261,903,904],{},"ignore",[261,906,907],{},"threshold",", your own framework definitions and more. It only supplies settings, so clone settings and dead-code settings can share one file. A flag still wins over the section. The standalone ",[261,910,807],{}," binary reads the same section. See ",[249,913,914],{"href":126},"Configuration",[249,916,855],{"href":853,"rel":917},[253],[286,919,920,925,926,350,928,325],{},[289,921,922,924],{},[261,923,702],{}," lists the largest code files",", by lines, next to the largest formats. Only code is ranked, so a lockfile or a long HTML page does not top the list. See ",[249,927,716],{"href":76},[249,929,932],{"href":930,"rel":931},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1086",[253],"#1086",[278,934,563],{"id":935},"bug-fixes-2",[245,937,938,939,942],{},"We ran basta next to knip and fallow on 55 repositories (the GitHub trending lists for JavaScript, TypeScript, Vue, Svelte and Astro, plus the source code of Nuxt, Next.js, Svelte, Gatsby and Astro) and fixed what the run found (",[249,940,855],{"href":853,"rel":941},[253],"):",[283,944,945,953,963,977,986,992,998,1004,1033],{},[286,946,947,952],{},[289,948,949,951],{},[261,950,592],{}," was very slow on projects with many path aliases."," A monorepo with 150 packages took 198 s and Next.js took 83 s. They now take 3.3 s and 4.4 s, with identical findings.",[286,954,955,962],{},[289,956,957,958,961],{},"A catch-all alias such as ",[261,959,960],{},"\"*\": [\".\u002F*\"]"," made every package import slow."," LibreChat went from 4.0 s to 0.86 s.",[286,964,965,972,973,976],{},[289,966,967,968,971],{},"Vite's ",[261,969,970],{},"'@': '\u002Fsrc'"," alias was read as the root of the file system",", so every ",[261,974,975],{},"@\u002F"," import was lost and live components were reported as unused.",[286,978,979,985],{},[289,980,981,984],{},[261,982,983],{},"require(`.\u002Fx`)"," with backticks was ignored."," Gatsby writes every string that way.",[286,987,988,991],{},[289,989,990],{},"An arrow function in a Svelte or Astro attribute broke parsing",", and everything the component imports was reported as unused.",[286,993,994,997],{},[289,995,996],{},"Django migrations and management commands were reported as unused files."," Django, Alembic and Scrapy are now in the framework list.",[286,999,1000,1003],{},[289,1001,1002],{},"A file named only by a path string without an extension",", the way a framework registers a file it loads itself, is no longer reported at full confidence. It gets a new reason, \"its path appears in a string literal\", which puts it under the default threshold.",[286,1005,1006,1015,1016,1019,1020,1023,1024,1027,1028,325],{},[289,1007,1008,1009,1014],{},"A ",[249,1010,1013],{"href":1011,"rel":1012},"https:\u002F\u002Fwxt.dev",[253],"WXT"," browser extension was read as almost entirely dead",", because its ",[261,1017,1018],{},"entrypoints\u002F"," directory and its generated ",[261,1021,1022],{},"@","\u002F",[261,1025,1026],{},"~"," aliases were not recognized. (",[249,1029,1032],{"href":1030,"rel":1031},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F1082",[253],"#1082",[286,1034,1035,1038,1039,1042,1043,1046,1047,325],{},[289,1036,1037],{},"Markup, stylesheet and template files no longer get a complexity score."," Words like ",[261,1040,1041],{},"if"," or a media query's ",[261,1044,1045],{},"and"," were counted as branches, so an HTML page could top the \"Most complex files\" list. (",[249,1048,1051],{"href":1049,"rel":1050},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1081",[253],"#1081",[278,1053,619],{"id":1054},"other-2",[283,1056,1057],{},[286,1058,1059,1060,319,1065,529,1068,265],{},"The dead-code engine in this release is basta 0.2.0, which is also published on its own: ",[249,1061,1063,808],{"href":803,"rel":1062},[253],[261,1064,807],{},[249,1066,813],{"href":811,"rel":1067},[253],[249,1069,818],{"href":1070,"rel":1071},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fbasta\u002Freleases\u002Ftag\u002Fv0.2.0",[253],[267,1073,1075],{"id":1074},"v530","v5.3.0",[245,1077,1078],{},[274,1079,1080],{},"Released 2026-09-18",[278,1082,281],{"id":1083},"new-features-4",[283,1085,1086,1108,1121,1135,1172,1197,1217],{},[286,1087,1088,1093,1094,1097,1098,710,1101,350,1103,325],{},[289,1089,1090,1092],{},[261,1091,705],{},": one score for the project"," — duplication, dead code and complexity, folded into a single 0-100 score with an A-E grade. It adjusts for project size, so a small project isn't sunk by one finding, and a dimension jscpd can't measure (say, no JavaScript\u002FTypeScript\u002FPython to check for dead code) is left out and labeled ",[261,1095,1096],{},"n\u002Fa"," rather than scored as if it were clean. Bring in your own metrics — coverage, security scans, anything you track — with ",[261,1099,1100],{},"--health-input",[249,1102,713],{"href":111},[249,1104,1107],{"href":1105,"rel":1106},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1064",[253],"#1064",[286,1109,1110,1115,1116,350,1118,325],{},[289,1111,1112,1114],{},[261,1113,702],{},": the whole picture on one screen"," — project size, duplication by clone kind and format, the most complex files, and dead code, all from a single run, with the health score on top. See ",[249,1117,716],{"href":76},[249,1119,1107],{"href":1105,"rel":1120},[253],[286,1122,1123,1129,1130,350,1132,325],{},[289,1124,1125,1128],{},[261,1126,1127],{},"--complexity",": the complexity summary without a clone scan"," — for when all you want to know is which files are hardest to maintain. See ",[249,1131,914],{"href":126},[249,1133,1107],{"href":1105,"rel":1134},[253],[286,1136,1137,1143,1144,319,1147,892,1150,1153,1154,1156,1157,1160,1161,1164,1165,350,1169,325],{},[289,1138,1139,1142],{},[261,1140,1141],{},"--kind",": filter clones by how they were found"," — keep only ",[261,1145,1146],{},"exact",[261,1148,1149],{},"renamed",[261,1151,1152],{},"similar"," matches, or narrow ",[261,1155,1152],{}," further to a near-miss merge (",[261,1158,1159],{},"gap",") or a structural match (",[261,1162,1163],{},"ast","). An unknown kind is an error instead of quietly returning a clean report. See ",[249,1166,1168],{"href":1167},"\u002Fconcepts\u002Fclone-types#reporting-one-kind","Types of Code Clones",[249,1170,1107],{"href":1105,"rel":1171},[253],[286,1173,1174,1179,1180,1182,1183,1185,1186,1188,1189,350,1194,325],{},[289,1175,1176,1178],{},[261,1177,592],{},": find code nothing runs"," — a new engine, ",[289,1181,807],{},", builds a project's import graph from its real entry points and reports unused files, exports and imports across JavaScript, TypeScript, Vue, Svelte, Astro and Python, including monorepo package names, path aliases and framework routing conventions. Every finding carries a confidence score. It's built into jscpd as ",[261,1184,592],{}," and also ships as its own standalone ",[261,1187,807],{}," command. A dedicated guide is coming; for now see the ",[249,1190,1193],{"href":1191,"rel":1192},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fblob\u002Fmaster\u002Frust\u002FCHANGELOG.md#530",[253],"full write-up in the changelog",[249,1195,1107],{"href":1105,"rel":1196},[253],[286,1198,1199,1206,1207,319,1210,529,1213,1216],{},[289,1200,1201,1202,529,1204],{},"Markdown and HTML reports for ",[261,1203,702],{},[261,1205,705],{}," — alongside the existing ",[261,1208,1209],{},"console",[261,1211,1212],{},"json",[261,1214,1215],{},"badge"," output, so either one can be posted as a PR comment or published as a static page.",[286,1218,1219,1222,1223,1226,1227,1230,1231,1234,1235,1238,1239,319,1242,1245,1246,1251],{},[289,1220,1221],{},"More accurate complexity counting"," — ",[261,1224,1225],{},"--summary --summary-by complexity"," now counts branches the way each language actually spells them (Rust ",[261,1228,1229],{},"match"," arms, Swift ",[261,1232,1233],{},"guard",", Go ",[261,1236,1237],{},"select",", and so on), counts one path per function instead of per file, and reads short-circuit operators (",[261,1240,1241],{},"&&",[261,1243,1244],{},"||",") correctly in every language, not only JavaScript. Checked against ",[249,1247,1250],{"href":1248,"rel":1249},"https:\u002F\u002Fgithub.com\u002Fterryyin\u002Flizard",[253],"lizard"," across nine languages, agreement on file ranking rose from 0.83 to 0.92.",[278,1253,563],{"id":1254},"bug-fixes-3",[283,1256,1257,1268,1279,1293,1302,1313,1319,1325],{},[286,1258,1259,1222,1262,1264,1265,1267],{},[289,1260,1261],{},"A single mistyped config field no longer discards the whole config",[261,1263,306],{}," fields are now checked one at a time, so one wrong type (say, a string where ",[261,1266,901],{}," wants an array) drops just that field instead of the entire file.",[286,1269,1270,1278],{},[289,1271,1272,1273,1023,1275,1277],{},"Hardened ",[261,1274,702],{},[261,1276,705],{}," output against crafted input"," — a hostile file path, format name or metric ID could break a Markdown table, inject content into the HTML report, or forge extra rows in the console output; every such value is now escaped before it's rendered.",[286,1280,1281,1292],{},[289,1282,1283,1023,1285,1287,1288,1291],{},[261,1284,702],{},[261,1286,705],{}," no longer fail outright when ",[261,1289,1290],{},"--format"," rules out every dead-code-capable language"," — they drop just that section, the way a project with none of those files already does.",[286,1294,1295,1301],{},[289,1296,1297,1300],{},[261,1298,1299],{},"--complexity --fail-on-empty"," now writes its reports before failing",", matching every other mode.",[286,1303,1304,1310,1311,265],{},[289,1305,1306,1309],{},[261,1307,1308],{},"--min-confidence"," above 100 is clamped everywhere it's read",", not only in standalone ",[261,1312,592],{},[286,1314,1315,1318],{},[289,1316,1317],{},"Fixed a health-score bug"," where excluding duplicated markup (HTML, CSS, templates, …) from scoring barely moved the number on a real project — it's now excluded properly on both sides of the calculation.",[286,1320,1321,1324],{},[289,1322,1323],{},"Windows report paths now use forward slashes",", matching every other platform.",[286,1326,1327],{},[289,1328,1329,1331,1332,1335],{},[261,1330,807],{},"'s ",[261,1333,1334],{},"oxc"," parser crates bumped to 0.150.",[278,1337,1339],{"id":1338},"thank-you-️","Thank You ❤️",[283,1341,1342],{},[286,1343,1344,1349,1350,325],{},[249,1345,1348],{"href":1346,"rel":1347},"https:\u002F\u002Fgithub.com\u002FDev-next-gen",[253],"@Dev-next-gen"," for fixing how plain text, log and CSV files handle comments (",[249,1351,1354],{"href":1352,"rel":1353},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1065",[253],"#1065",[267,1356,1358],{"id":1357},"v521","v5.2.1",[245,1360,1361],{},[274,1362,1363],{},"Released 2026-09-15",[278,1365,281],{"id":1366},"new-features-5",[283,1368,1369,1414,1441],{},[286,1370,1371,1222,1377,1380,1381,1383,1384,319,1387,529,1390,1393,1394,1397,1398,1400,1401,350,1404,319,1409,325],{},[289,1372,1373,1376],{},[261,1374,1375],{},"--history",": duplication trend over git history",[261,1378,1379],{},"jscpd src --history v5.0.0..HEAD"," scans every commit in the range and prints a bar chart, a per-commit table with the change between points, the overall trend and how far ",[261,1382,633],{}," could be tightened. ",[261,1385,1386],{},"--history-since",[261,1388,1389],{},"--history-every",[261,1391,1392],{},"--history-limit"," narrow the range, the JSON report carries a ",[261,1395,1396],{},"history"," key, and the Action takes a ",[261,1399,1396],{}," input. See ",[249,1402,1403],{"href":71},"History",[249,1405,1408],{"href":1406,"rel":1407},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F1002",[253],"#1002",[249,1410,1413],{"href":1411,"rel":1412},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1050",[253],"#1050",[286,1415,1416,1422,1423,1425,1426,1428,1429,350,1431,319,1436,325],{},[289,1417,1418,1419],{},"Exit codes you can gate on, and ",[261,1420,1421],{},"--fail-on-empty"," — an unknown ",[261,1424,1290],{},", a scan path that does not exist and a reporter that cannot write its file now exit 1 instead of passing with an empty report. ",[261,1427,1421],{}," fails a scan that analyzed no files, so a mistyped path or an over-broad ignore cannot look like a clean run. See ",[249,1430,914],{"href":126},[249,1432,1435],{"href":1433,"rel":1434},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F1047",[253],"#1047",[249,1437,1440],{"href":1438,"rel":1439},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1049",[253],"#1049",[286,1442,1443,1448,1449,529,1451,1454,1455,350,1457,319,1462,325],{},[289,1444,1445],{},[261,1446,1447],{},"pip install jscpd"," — eight platform wheels built from the same prebuilt binaries as the npm packages, so ",[261,1450,1447],{},[261,1452,1453],{},"uvx jscpd"," get the Rust engine with no Python code and no Node.js runtime involved. The repository-hosted pre-commit hook now installs from PyPI. See ",[249,1456,15],{"href":16},[249,1458,1461],{"href":1459,"rel":1460},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F1037",[253],"#1037",[249,1463,1466],{"href":1464,"rel":1465},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1039",[253],"#1039",[278,1468,563],{"id":1469},"bug-fixes-4",[283,1471,1472,1488,1511],{},[286,1473,1474,1477,1478,319,1483,325],{},[289,1475,1476],{},"An open clone could be stretched past the file it started in"," — a third file sharing the same text but continuing differently could extend a fragment beyond its own file, so the clone was dropped or reported with mismatched ends. Growth now follows the clone's own anchor, and N-way copies no longer lose pairs. (",[249,1479,1482],{"href":1480,"rel":1481},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F1033",[253],"#1033",[249,1484,1487],{"href":1485,"rel":1486},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1034",[253],"#1034",[286,1489,1490,1493,1494,1497,1498,1500,1501,319,1506,325],{},[289,1491,1492],{},"The XML report could be rejected by every parser"," — bytes XML 1.0 cannot represent were written verbatim, ",[261,1495,1496],{},"]]>"," inside a fragment closed the CDATA section early and attributes were escaped twice. Such characters become U+FFFD, ",[261,1499,1496],{}," is split across two CDATA sections, and paths are escaped once. (",[249,1502,1505],{"href":1503,"rel":1504},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F375",[253],"#375",[249,1507,1510],{"href":1508,"rel":1509},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1055",[253],"#1055",[286,1512,1513,1519,1520,1523,1524,319,1529,325],{},[289,1514,1515,1518],{},[261,1516,1517],{},"--follow-symlinks"," renamed and double-counted linked files"," — a file reached through a link was reported by its resolved real path, so the report and ",[261,1521,1522],{},"--ignore"," disagreed about its name, a file reachable through two paths counted twice, and a file symlink next to its target was a clone of itself. Files now keep the path they were found at and each real file is scanned once. (",[249,1525,1528],{"href":1526,"rel":1527},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F1059",[253],"#1059",[249,1530,1533],{"href":1531,"rel":1532},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1060",[253],"#1060",[278,1535,619],{"id":1536},"other-3",[283,1538,1539,1551,1567,1580],{},[286,1540,1541,1546,1547,1550],{},[289,1542,1543,1544],{},"Symbolic links are skipped unless ",[261,1545,1517],{}," — v4 followed them by default unless ",[261,1548,1549],{},"--noSymlinks"," was set. True in every 5.x release but undocumented, and it silently drops a corpus mounted through a symlink.",[286,1552,1553,1559,1560,350,1562,325],{},[289,1554,1555,1558],{},[261,1556,1557],{},"CITATION.cff"," and a Citation section"," — GitHub's \"Cite this repository\" button and a BibTeX entry for papers that use jscpd as their detector. See ",[249,1561,230],{"href":231},[249,1563,1566],{"href":1564,"rel":1565},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1051",[253],"#1051",[286,1568,1569,1572,1573,350,1575,325],{},[289,1570,1571],{},"Docs: jscpd is language-aware"," — detection runs on language tokens, with per-format comment and string syntax and the oxc parser for JavaScript and TypeScript, not on raw text. See ",[249,1574,105],{"href":106},[249,1576,1579],{"href":1577,"rel":1578},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1048",[253],"#1048",[286,1581,1582,1585,1586,1589,1590,319,1595,325],{},[289,1583,1584],{},"Agent skills know about clone kinds, the summary and their noise"," — the bundled skills document ",[261,1587,1588],{},"--summary"," and the Type-2 and Type-3 flags, and warn that normalized passes surface look-alike code, with conservative defaults and a triage step. (",[249,1591,1594],{"href":1592,"rel":1593},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1056",[253],"#1056",[249,1596,1599],{"href":1597,"rel":1598},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1057",[253],"#1057",[278,1601,1339],{"id":1602},"thank-you-️-1",[283,1604,1605],{},[286,1606,1607,1612,1613,325],{},[249,1608,1611],{"href":1609,"rel":1610},"https:\u002F\u002Fgithub.com\u002Fmnahkies",[253],"@mnahkies"," for correcting the ignore examples in the README (",[249,1614,1617],{"href":1615,"rel":1616},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1038",[253],"#1038",[267,1619,1621],{"id":1620},"v520","v5.2.0",[245,1623,1624],{},[274,1625,1626],{},"Released 2026-09-08",[278,1628,281],{"id":1629},"new-features-6",[283,1631,1632,1679,1718,1757,1794,1822],{},[286,1633,1634,1222,1637,319,1640,529,1643,1646,1647,319,1650,319,1653,1656,1657,319,1660,892,1662,1664,1665,1668,1669,319,1674,325],{},[289,1635,1636],{},"Type-2 clone detection",[261,1638,1639],{},"--ignore-identifiers",[261,1641,1642],{},"--ignore-literals",[261,1644,1645],{},"--ignore-annotations"," (config keys ",[261,1648,1649],{},"ignoreIdentifiers",[261,1651,1652],{},"ignoreLiterals",[261,1654,1655],{},"ignoreAnnotations",", Action inputs of the same names) find blocks that differ only in names, literal values or annotations. Every clone now carries a ",[261,1658,1659],{},"kind",[261,1661,1146],{},[261,1663,1149],{},"; a run without the flags is unchanged apart from the additive ",[261,1666,1667],{},"\"kind\": \"exact\""," JSON field. (",[249,1670,1673],{"href":1671,"rel":1672},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F998",[253],"#998",[249,1675,1678],{"href":1676,"rel":1677},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1019",[253],"#1019",[286,1680,1681,1687,1688,1691,1692,1694,1695,1698,1699,1702,1703,319,1708,319,1713,325],{},[289,1682,1683,1684],{},"Near-miss clone merging with ",[261,1685,1686],{},"--max-gap-lines N"," — clones of one file pair separated by at most ",[261,1689,1690],{},"N"," unmatched lines in both files are merged into one clone of kind ",[261,1693,1152],{}," with a ",[261,1696,1697],{},"similarity"," score, so a copy with a line inserted in the middle is reported once instead of as two halves. Default ",[261,1700,1701],{},"0"," keeps the old behaviour. (",[249,1704,1707],{"href":1705,"rel":1706},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F999",[253],"#999",[249,1709,1712],{"href":1710,"rel":1711},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1020",[253],"#1020",[249,1714,1717],{"href":1715,"rel":1716},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1030",[253],"#1030",[286,1719,1720,1726,1727,1729,1730,1733,1734,1737,1738,1741,1742,1745,1746,350,1749,319,1752,325],{},[289,1721,1722,1723],{},"Function-level similarity for JavaScript and TypeScript with ",[261,1724,1725],{},"--similarity RATIO"," — compares whole functions by syntax-tree structure and reports pairs at or above the ratio as ",[261,1728,1152],{}," clones; names and literals do not take part, so a renamed copy scores ",[261,1731,1732],{},"1.0"," and a couple of inserted statements about ",[261,1735,1736],{},"0.75",". The default ",[261,1739,1740],{},"1"," means exact matches only. The MCP ",[261,1743,1744],{},"check_duplication"," tool takes the same argument. See ",[249,1747,1748],{"href":61},"MCP Server",[249,1750,1707],{"href":1705,"rel":1751},[253],[249,1753,1756],{"href":1754,"rel":1755},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1021",[253],"#1021",[286,1758,1759,1762,1763,1766,1767,1769,1770,529,1773,1775,1776,1779,1780,892,1782,1784,1785,319,1788,319,1791,325],{},[289,1760,1761],{},"Clone kinds in every reporter"," — console, ",[261,1764,1765],{},"ai",", JSON, XML, HTML, Xcode, ",[249,1768,410],{"href":158}," (rules ",[261,1771,1772],{},"jscpd\u002Frenamed-code",[261,1774,417],{},") and ",[249,1777,1778],{"href":163},"CodeClimate"," all show whether a clone is exact, renamed or similar, and how a similar one was found (",[261,1781,1159],{},[261,1783,1163],{},"). (",[249,1786,1678],{"href":1676,"rel":1787},[253],[249,1789,1756],{"href":1754,"rel":1790},[253],[249,1792,1717],{"href":1715,"rel":1793},[253],[286,1795,1796,1799,1800,1803,1804,1807,1808,1811,1812,319,1817,325],{},[289,1797,1798],{},"Tips are skipped when stdout is not a terminal"," — pipes, files, CI logs and agent hooks no longer receive the tips and sponsor lines; ",[261,1801,1802],{},"JSCPD_NO_TIPS"," joins ",[261,1805,1806],{},"CI"," as an environment switch and ",[261,1809,1810],{},"--no-tips"," stays. (",[249,1813,1816],{"href":1814,"rel":1815},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F1008",[253],"#1008",[249,1818,1821],{"href":1819,"rel":1820},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1029",[253],"#1029",[286,1823,1824,1827,1828,350,1830,325],{},[289,1825,1826],{},"MCP: fully described tool definitions"," — titles, read-only annotations, parameter examples and descriptions that say when to use each tool; names and schemas are unchanged. See ",[249,1829,1748],{"href":61},[249,1831,1834],{"href":1832,"rel":1833},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1028",[253],"#1028",[278,1836,563],{"id":1837},"bug-fixes-5",[283,1839,1840,1864,1880,1898],{},[286,1841,1842,1856,1857,350,1859,325],{},[289,1843,1844,1845,1848,1849,892,1852,1855],{},"Config-file ",[261,1846,1847],{},"ignorePattern"," entries without ",[261,1850,1851],{},"*",[261,1853,1854],{},"?"," silently did nothing"," — they were treated as relative paths; they are now applied verbatim, and an invalid regex prints a warning. See ",[249,1858,914],{"href":126},[249,1860,1863],{"href":1861,"rel":1862},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F997",[253],"#997",[286,1865,1866,1869,1870,319,1875,325],{},[289,1867,1868],{},"JavaScript\u002FTypeScript files with a recoverable parse error could not match clean files"," — any parser diagnostic sent the file to the fallback tokenizer; tokens now come from the lexer whenever the parser did not fail outright. (",[249,1871,1874],{"href":1872,"rel":1873},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F1023",[253],"#1023",[249,1876,1879],{"href":1877,"rel":1878},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1024",[253],"#1024",[286,1881,1882,1885,1886,892,1889,1892,1893,325],{},[289,1883,1884],{},"Markdown inherited the C comment style"," — a ",[261,1887,1888],{},"\u002F*",[261,1890,1891],{},"\u002F\u002F"," in prose swallowed the rest of the file; Markdown now has no comment syntax. (",[249,1894,1897],{"href":1895,"rel":1896},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1026",[253],"#1026",[286,1899,1900,1903,1904,325],{},[289,1901,1902],{},"Vue template clones were reported with wrong ranges"," — the html token stream is now in source order and the wrapper tags are left out of it, so a template clone gets the template's own line range. (",[249,1905,1908],{"href":1906,"rel":1907},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F1031",[253],"#1031",[278,1910,619],{"id":1911},"other-4",[283,1913,1914,1923],{},[286,1915,1916,1922],{},[289,1917,1918,1919],{},"Runnable demos under ",[261,1920,1921],{},"fixtures\u002F"," — every feature and fix above ships a demo directory with a README listing each command and its expected output.",[286,1924,1925,1928,1929,319,1934,325],{},[289,1926,1927],{},"Docs: ignore patterns and inline markers"," are documented in the v5 reference. (",[249,1930,1933],{"href":1931,"rel":1932},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F993",[253],"#993",[249,1935,1938],{"href":1936,"rel":1937},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F996",[253],"#996",[278,1940,1339],{"id":1941},"thank-you-️-2",[283,1943,1944,1955,1966,1977],{},[286,1945,1946,1951,1952,325],{},[249,1947,1950],{"href":1948,"rel":1949},"https:\u002F\u002Fgithub.com\u002F7487",[253],"@7487"," for skipping the tips on a non-terminal stdout (",[249,1953,1821],{"href":1819,"rel":1954},[253],[286,1956,1957,1962,1963,325],{},[249,1958,1961],{"href":1959,"rel":1960},"https:\u002F\u002Fgithub.com\u002Fzero-stroke",[253],"@zero-stroke"," for the Vue template clone ranges (",[249,1964,1908],{"href":1906,"rel":1965},[253],[286,1967,1968,1973,1974,325],{},[249,1969,1972],{"href":1970,"rel":1971},"https:\u002F\u002Fgithub.com\u002Fkwesolowski",[253],"@kwesolowski"," for the Markdown comment-style fix (",[249,1975,1897],{"href":1895,"rel":1976},[253],[286,1978,1979,1984,1985,325],{},[249,1980,1983],{"href":1981,"rel":1982},"https:\u002F\u002Fgithub.com\u002Fw3lld1",[253],"@w3lld1"," for documenting ignore patterns and inline markers (",[249,1986,1938],{"href":1936,"rel":1987},[253],[267,1989,1991],{"id":1990},"v512","v5.1.2",[245,1993,1994],{},[274,1995,1996],{},"Released 2026-09-03",[278,1998,281],{"id":1999},"new-features-7",[283,2001,2002,2021,2047],{},[286,2003,2004,2007,2008,2011,2012,350,2016,325],{},[289,2005,2006],{},"Linux ARM64 musl prebuilt binaries"," — npm installs on Alpine and other musl-based ARM64 Linux systems now get a native binary from the new ",[261,2009,2010],{},"jscpd-linux-arm64-musl"," package, bringing the prebuilt platform count to 8. See ",[249,2013,2015],{"href":2014},"\u002Fstart\u002Finstallation#platform-binaries","Platform Binaries",[249,2017,2020],{"href":2018,"rel":2019},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F988",[253],"#988",[286,2022,2023,2029,2030,319,2033,319,2036,2039,2040,350,2044,325],{},[289,2024,2025,2026],{},"Docker image ",[261,2027,2028],{},"ghcr.io\u002Fkucherenko\u002Fjscpd"," — a multi-arch (amd64\u002Farm64) distroless image built from the release binaries ships with every release, tagged ",[261,2031,2032],{},"latest",[261,2034,2035],{},"5",[261,2037,2038],{},"5.1"," and the exact version, with SLSA provenance and an SBOM. See ",[249,2041,2043],{"href":2042},"\u002Fstart\u002Finstallation#using-docker","Using Docker",[249,2045,2020],{"href":2018,"rel":2046},[253],[286,2048,2049,2055,2056,2059,2060,325],{},[289,2050,2051,2054],{},[261,2052,2053],{},"cargo-binstall"," metadata"," — the crate now points ",[261,2057,2058],{},"cargo binstall jscpd"," at the release tarballs. The 5.1.2 metadata still makes binstall fall back to compiling from source because the crate ships two binaries from one archive file; a follow-up release fixes the layout. (",[249,2061,2020],{"href":2018,"rel":2062},[253],[278,2064,563],{"id":2065},"bug-fixes-6",[283,2067,2068,2096,2113,2131],{},[286,2069,2070,2082,2083,656,2086,2088,2089,2092,2093,325],{},[289,2071,2072,529,2075,2078,2079],{},[261,2073,2074],{},"jscpd --version",[261,2076,2077],{},"--help"," now say ",[261,2080,2081],{},"jscpd"," — the command name was the literal ",[261,2084,2085],{},"cpd",[261,2087,2074],{}," printed ",[261,2090,2091],{},"cpd 5.1.1",". The name now follows the invoked executable. (",[249,2094,2020],{"href":2018,"rel":2095},[253],[286,2097,2098,2105,2106,2109,2110,325],{},[289,2099,2100,2101,2104],{},"Windows: drive-anchored ",[261,2102,2103],{},"--pattern"," values are treated as absolute"," — patterns like ",[261,2107,2108],{},"C:\\src\\**\\*.ts"," were never recognized as absolute because of an impossible character check. (",[249,2111,2020],{"href":2018,"rel":2112},[253],[286,2114,2115,2118,2119,2122,2123,350,2126,325],{},[289,2116,2117],{},"pre-commit hook passed v4-only flags"," — the hook definition still used ",[261,2120,2121],{},"--gitignore --exitCode",", which the v5 CLI rejects; it now passes ",[261,2124,2125],{},"--exit-code 1",[249,2127,2130],{"href":2128,"rel":2129},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F989",[253],"#989",[286,2132,2133,2136,2137,2140,2141,350,2144,325],{},[289,2134,2135],{},"Unsupported-platform error is actionable"," — the npm launchers now name the host (",[261,2138,2139],{},"os\u002Farch (libc)","), list the supported platforms and point to ",[261,2142,2143],{},"cargo install jscpd",[249,2145,2020],{"href":2018,"rel":2146},[253],[278,2148,619],{"id":2149},"other-5",[283,2151,2152,2184,2200,2213],{},[286,2153,2154,2161,2162,2168,2169,2172,2173,350,2176,319,2179,325],{},[289,2155,2156,2157,2160],{},"Repository split: ",[261,2158,2159],{},"master"," is v5-only"," — the TypeScript v4 engine moved to the ",[249,2163,2166],{"href":2164,"rel":2165},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Ftree\u002Fmaster-v4",[253],[261,2167,263],{}," branch and releases from there under the ",[261,2170,2171],{},"latest-4"," npm dist-tag. See ",[249,2174,2175],{"href":201},"jscpd v4",[249,2177,2130],{"href":2128,"rel":2178},[253],[249,2180,2183],{"href":2181,"rel":2182},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F990",[253],"#990",[286,2185,2186,1222,2193,2196,2197,325],{},[289,2187,2188,2189,2192],{},"Floating ",[261,2190,2191],{},"v5"," tag for the GitHub Action",[261,2194,2195],{},"uses: kucherenko\u002Fjscpd@v5"," follows the latest 5.x release. (",[249,2198,2020],{"href":2018,"rel":2199},[253],[286,2201,2202,2205,2206,2209,2210,325],{},[289,2203,2204],{},"Signed release assets"," — every release archive carries a Sigstore keyless signature (",[261,2207,2208],{},"\u003Casset>.sigstore.json",") in addition to SLSA provenance. (",[249,2211,2020],{"href":2018,"rel":2212},[253],[286,2214,2215,2218,2219,2221,2222,350,2225,325],{},[289,2216,2217],{},"crates.io metadata and CI"," — all crates declare repository, docs, keywords and categories; Windows joined the PR build matrix; a smoke test runs the release binary against the fixtures corpus; nightly ",[261,2220,659],{}," \u002F ",[261,2223,2224],{},"cargo deny",[249,2226,2020],{"href":2018,"rel":2227},[253],[267,2229,2231],{"id":2230},"v511","v5.1.1",[245,2233,2234],{},[274,2235,2236],{},"Released 2026-08-31",[278,2238,563],{"id":2239},"bug-fixes-7",[283,2241,2242],{},[286,2243,2244,2249,2250,2252,2253,2256,2257,2260,2261,2264,2265,2267,2268,2271,2272,2274,2275,2278,2279,2281],{},[289,2245,2246,2248],{},[261,2247,2081],{}," on npm installed the 5.0.16 engine instead of 5.1.0"," — the ",[261,2251,2081],{}," wrapper package published its ",[261,2254,2255],{},"optionalDependencies"," pinned to the ",[261,2258,2259],{},"5.0.16"," platform binaries, so ",[261,2262,2263],{},"npm i jscpd@5.1.0"," resolved a native binary one release behind and ",[261,2266,2074],{}," reported ",[261,2269,2270],{},"cpd 5.0.16","; everything 5.1.0 fixed was therefore absent for ",[261,2273,2081],{}," users, including the Windows ",[261,2276,2277],{},"--baseline-from-ref"," fix. The ",[261,2280,2085],{}," package and the platform packages were unaffected. The release script now updates the wrapper's version and its platform pins independently and fails the release if any pin disagrees with the release version.",[278,2283,619],{"id":2284},"other-6",[283,2286,2287],{},[286,2288,2289,2292,2293,2296,2297,2299],{},[289,2290,2291],{},"Declared MSRV corrected to 1.96"," — the workspace advertised ",[261,2294,2295],{},"rust-version = \"1.87\""," on crates.io, a floor the crate could not build on (the ",[261,2298,1334],{}," parser crates require 1.96). CI now builds at exactly the declared MSRV so it cannot drift again.",[267,2301,2303],{"id":2302},"v510","v5.1.0",[278,2305,281],{"id":2306},"new-features-8",[283,2308,2309,2336,2347,2367,2395,2410],{},[286,2310,2311,2323,2324,2327,2328,350,2331,325],{},[289,2312,2313,2314,319,2317,319,2320,325],{},"Clone baseline (",[261,2315,2316],{},"--baseline",[261,2318,2319],{},"--update-baseline",[261,2321,2322],{},"--fail-on-new-clones"," — gate CI on ",[274,2325,2326],{},"new"," duplication only: a committed baseline file records fingerprints of accepted clones, and only clones absent from it fail the build, so legacy duplication is tolerated while regressions are caught. See ",[249,2329,2330],{"href":46},"Gate on New Duplication",[249,2332,2335],{"href":2333,"rel":2334},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F944",[253],"#944",[286,2337,2338,2343,2344,325],{},[289,2339,2340,2341,325],{},"Ephemeral baseline from a git ref (",[261,2342,2277],{}," — stateless PR gating without a committed file: scans the base ref in a temporary worktree and reports clones that don't exist there. (",[249,2345,2335],{"href":2333,"rel":2346},[253],[286,2348,2349,2355,2356,710,2359,350,2362,325],{},[289,2350,2351,2352,325],{},"OpenMetrics reporter (",[261,2353,2354],{},"--reporters openmetrics"," — duplication gauges in the OpenMetrics text format, ready for GitLab CI ",[261,2357,2358],{},"artifacts:reports:metrics",[249,2360,2361],{"href":168},"OpenMetrics Reporter",[249,2363,2366],{"href":2364,"rel":2365},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F422",[253],"#422",[286,2368,2369,1222,2379,2382,2383,2386,2387,350,2390,325],{},[289,2370,2371,2372,2375,2376,325],{},"CodeClimate \u002F GitLab Code Quality reporter (",[261,2373,2374],{},"--reporters codeclimate",", alias ",[261,2377,2378],{},"gitlab",[261,2380,2381],{},"gl-code-quality-report.json"," for GitLab's ",[261,2384,2385],{},"artifacts:reports:codequality",", so duplicates appear as code quality issues in merge requests. See ",[249,2388,2389],{"href":163},"CodeClimate Reporter",[249,2391,2394],{"href":2392,"rel":2393},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F958",[253],"#958",[286,2396,2397,2400,2401,2404,2405,325],{},[289,2398,2399],{},"Windows on ARM support"," — npm installs pick a native ",[261,2402,2403],{},"aarch64-pc-windows-msvc"," binary on Windows ARM64. (",[249,2406,2409],{"href":2407,"rel":2408},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F963",[253],"#963",[286,2411,2412,2418,2419,2422,2423,2428,2429,2431,2432,325],{},[289,2413,2414,2415],{},"Config discovery in ",[261,2416,2417],{},".config\u002F"," — jscpd also finds its config at ",[261,2420,2421],{},".config\u002Fjscpd.json"," per the ",[249,2424,2427],{"href":2425,"rel":2426},"https:\u002F\u002Fdot-config.github.io\u002F",[253],"dot-config convention","; a root ",[261,2430,306],{}," still wins. (",[249,2433,2436],{"href":2434,"rel":2435},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F979",[253],"#979",[278,2438,563],{"id":2439},"bug-fixes-8",[283,2441,2442,2459,2470],{},[286,2443,2444,1222,2450,2453,2454,325],{},[289,2445,2446,2447,2449],{},"Unknown ",[261,2448,1290],{}," values warn instead of silently scanning 0 files",[261,2451,2452],{},"--format cs"," (or any typo) no longer looks identical to a clean scan in CI. (",[249,2455,2458],{"href":2456,"rel":2457},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F964",[253],"#964",[286,2460,2461,2464,2465,325],{},[289,2462,2463],{},"Nix flake builds again"," — the Rust toolchain is pinned to an exact patch version, so the manifest hash can no longer drift. (",[249,2466,2469],{"href":2467,"rel":2468},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F976",[253],"#976",[286,2471,2472,2478],{},[289,2473,2474,2475,2477],{},"Windows: ",[261,2476,2277],{}," no longer reports every clone as new"," — Windows verbatim paths were truncated by the format-suffix stripper, silently breaking snippet reads behind the baseline fingerprints; fingerprints are also line-ending agnostic now.",[278,2480,1339],{"id":2481},"thank-you-️-3",[283,2483,2484,2495,2506,2517,2531,2545],{},[286,2485,2486,2491,2492,325],{},[249,2487,2490],{"href":2488,"rel":2489},"https:\u002F\u002Fgithub.com\u002Fluchsamapparat",[253],"@luchsamapparat"," for contributing Windows on ARM support (",[249,2493,2409],{"href":2407,"rel":2494},[253],[286,2496,2497,2502,2503,325],{},[249,2498,2501],{"href":2499,"rel":2500},"https:\u002F\u002Fgithub.com\u002Fdmromanov",[253],"@dmromanov"," for proposing the OpenMetrics reporter (",[249,2504,2366],{"href":2364,"rel":2505},[253],[286,2507,2508,2513,2514,325],{},[249,2509,2512],{"href":2510,"rel":2511},"https:\u002F\u002Fgithub.com\u002Fbeanaroo",[253],"@beanaroo"," for proposing the GitLab \u002F CodeClimate Code Quality report format (",[249,2515,2394],{"href":2392,"rel":2516},[253],[286,2518,2519,2524,2525,2527,2528,325],{},[249,2520,2523],{"href":2521,"rel":2522},"https:\u002F\u002Fgithub.com\u002FMRDGH2821",[253],"@MRDGH2821"," for proposing config discovery from the ",[261,2526,2417],{}," subfolder (",[249,2529,2436],{"href":2434,"rel":2530},[253],[286,2532,2533,2538,2539,2541,2542,325],{},[249,2534,2537],{"href":2535,"rel":2536},"https:\u002F\u002Fgithub.com\u002Fzbcoding",[253],"@zbcoding"," for reporting the silent unknown-",[261,2540,1290],{}," behavior (",[249,2543,2458],{"href":2456,"rel":2544},[253],[286,2546,2547,2552,2553,325],{},[249,2548,2551],{"href":2549,"rel":2550},"https:\u002F\u002Fgithub.com\u002Feaves-dropper",[253],"@eaves-dropper"," for reporting the Nix build failure (",[249,2554,2469],{"href":2467,"rel":2555},[253],[267,2557,2559],{"id":2558},"v5016","v5.0.16",[278,2561,281],{"id":2562},"new-features-9",[283,2564,2565,2595,2629],{},[286,2566,2567,1222,2573,2576,2577,319,2579,319,2582,319,2585,710,2588,350,2590,325],{},[289,2568,2569,2570,325],{},"MCP server over stdio (",[261,2571,2572],{},"--mcp",[261,2574,2575],{},"jscpd --mcp \u002Fpath\u002Fto\u002Fproject"," serves the Model Context Protocol on stdin\u002Fstdout, the transport MCP clients like Claude Desktop, Claude Code, and Cursor spawn and manage themselves — no port, no network policy. The project is scanned once at startup and kept in memory, so snippet checks answer in milliseconds. Tools: ",[261,2578,1744],{},[261,2580,2581],{},"get_file_clones",[261,2583,2584],{},"get_statistics",[261,2586,2587],{},"check_current_directory",[249,2589,1748],{"href":61},[249,2591,2594],{"href":2592,"rel":2593},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F891",[253],"#891",[286,2596,2597,2602,2603,2606,2607,2610,2611,1023,2613,2616,2617,2619,2620,2623,2624,325],{},[289,2598,2599,2600,325],{},"Codebase summary (",[261,2601,1588],{}," — opt-in refactoring-hotspot overview appended to the run output: top files and folders ranked by tokens, lines, size, or a token-based complexity estimate, with each file's duplication share. ",[261,2604,2605],{},"--summary-top \u003Cn>"," sets the list length, ",[261,2608,2609],{},"--summary-by tokens|lines|size|complexity"," picks the metric. Renders in ",[261,2612,1209],{},[261,2614,2615],{},"console-full",", compactly in the ",[261,2618,1765],{}," reporter, and as an additive ",[261,2621,2622],{},"summary"," key in the JSON report. (",[249,2625,2628],{"href":2626,"rel":2627},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F934",[253],"#934",[286,2630,2631,2637,2638,2641,2642,350,2645,325],{},[289,2632,2633,2634,325],{},"Isolated folder groups (",[261,2635,2636],{},"--skip-isolated"," — skip duplication between monorepo folders owned by different teams: ",[261,2639,2640],{},"--skip-isolated \"packages\u002Fteam-a|packages\u002Fteam-b\""," drops clones spanning two different folders of the same group, while duplication inside one folder or against shared code is still reported. Config file: ",[261,2643,2644],{},"\"skipIsolated\": [[\"packages\u002Fa\", \"packages\u002Fb\"]]",[249,2646,2649],{"href":2647,"rel":2648},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F628",[253],"#628",[278,2651,2653],{"id":2652},"security","Security",[283,2655,2656],{},[286,2657,2658,2661,2662,2665,2666,264],{},[289,2659,2660],{},"Supply-chain hardening (OpenSSF Scorecard)"," — GitHub Actions pinned to commit SHAs, least-privilege workflow tokens, ",[261,2663,2664],{},"SECURITY.md"," with private vulnerability reporting, protected ",[261,2667,2159],{},[278,2669,1339],{"id":2670},"thank-you-️-4",[283,2672,2673],{},[286,2674,2675,2680,2681,2684,2685,325],{},[249,2676,2679],{"href":2677,"rel":2678},"https:\u002F\u002Fgithub.com\u002Fhanzhangyu",[253],"@hanzhangyu"," for proposing isolated folder groups for monorepos and contributing the original ",[261,2682,2683],{},"skipIsolated"," implementation (",[249,2686,2649],{"href":2647,"rel":2687},[253],[267,2689,2691],{"id":2690},"v5015","v5.0.15",[278,2693,281],{"id":2694},"new-features-10",[283,2696,2697,2725,2744],{},[286,2698,2699,2702,2703,2706,2707,2710,2711,2714,2715,2717,2718,350,2720,325],{},[289,2700,2701],{},"SARIF: size-based severity"," — new ",[261,2704,2705],{},"--sarif-error-tokens \u003CN>"," flag: clones with at least N tokens are reported at level ",[261,2708,2709],{},"error"," while smaller ones stay ",[261,2712,2713],{},"warning","; when duplication exceeds ",[261,2716,633],{},", all results become ",[261,2719,2709],{},[249,2721,2724],{"href":2722,"rel":2723},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F908",[253],"#908",[286,2726,2727,2730,2731,2734,2735,2738,2739,325],{},[289,2728,2729],{},"SARIF: clone fingerprints"," — each result carries a ",[261,2732,2733],{},"partialFingerprints"," entry (",[261,2736,2737],{},"jscpdCloneHash\u002Fv1",") for cross-run result identity in GitHub code scanning. (",[249,2740,2743],{"href":2741,"rel":2742},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F909",[253],"#909",[286,2745,2746,2749,2750,2753,2754,319,2759,325],{},[289,2747,2748],{},"SARIF: related-location messages & richer rule metadata"," — counterpart locations get linked messages, and the ",[261,2751,2752],{},"jscpd\u002Fduplicate-code"," rule has full metadata for SARIF viewers. (",[249,2755,2758],{"href":2756,"rel":2757},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F911",[253],"#911",[249,2760,2763],{"href":2761,"rel":2762},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fpull\u002F914",[253],"#914",[278,2765,563],{"id":2766},"bug-fixes-9",[283,2768,2769,2785,2799],{},[286,2770,2771,2774,2775,319,2780,325],{},[289,2772,2773],{},"Scan-root-relative report paths"," — report paths are relative to the scanned directory again (as in 4.x); fixes empty snippets and unresolvable paths when scanning from outside the target directory. (",[249,2776,2779],{"href":2777,"rel":2778},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F872",[253],"#872",[249,2781,2784],{"href":2782,"rel":2783},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F892",[253],"#892",[286,2786,2787,2790,2791,350,2794,325],{},[289,2788,2789],{},"Report version stamping"," — SARIF and HTML report versions now match ",[261,2792,2793],{},"--version",[249,2795,2798],{"href":2796,"rel":2797},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F915",[253],"#915",[286,2800,2801,529,2804,2807],{},[289,2802,2803],{},"Multi-root blame attribution",[289,2805,2806],{},"git root discovery"," fixes",[278,2809,1339],{"id":2810},"thank-you-️-5",[283,2812,2813,2821,2829],{},[286,2814,2815,2820],{},[249,2816,2819],{"href":2817,"rel":2818},"https:\u002F\u002Fgithub.com\u002Fchrisc-onaorg",[253],"@chrisc-onaorg"," for the SARIF fingerprints, related-location messages, and rule metadata",[286,2822,2823,2828],{},[249,2824,2827],{"href":2825,"rel":2826},"https:\u002F\u002Fgithub.com\u002Fdarronz",[253],"@darronz"," for the scan-root-relative paths fix",[286,2830,2831,2836],{},[249,2832,2835],{"href":2833,"rel":2834},"https:\u002F\u002Fgithub.com\u002Fnvuillam",[253],"@nvuillam"," for proposing size-based SARIF severity",[267,2838,2840],{"id":2839},"v5014","v5.0.14",[278,2842,281],{"id":2843},"new-features-11",[283,2845,2846],{},[286,2847,2848,1222,2851,2854,2855,2858,2859,2862,2863,2866,2867,2870,2871,2874,2875,2878,2879,2221,2881,710,2883,350,2887,325],{},[289,2849,2850],{},"Cross-format clone detection",[261,2852,2853],{},"--cross-formats"," defines groups of related formats sharing one comparison pool, e.g. ",[261,2856,2857],{},"--cross-formats \"javascript,typescript\""," or the ",[261,2860,2861],{},"js-ts"," preset (",[261,2864,2865],{},"javascript,jsx,typescript,tsx","). When a group mixes TypeScript with JavaScript, TS files are compared with erasable type syntax stripped, so ",[261,2868,2869],{},"function f(a: number): void"," matches ",[261,2872,2873],{},"function f(a)",". Also configurable as ",[261,2876,2877],{},"crossFormats"," in ",[261,2880,306],{},[261,2882,843],{},[249,2884,2886],{"href":2885},"\u002Freference\u002Fconfig-file#cross-format-groups-cross-formats","Configuration → Cross-Format Groups",[249,2888,2891],{"href":2889,"rel":2890},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F810",[253],"#810",[278,2893,563],{"id":2894},"bug-fixes-10",[283,2896,2897],{},[286,2898,2899,1222,2902,2905,2906,325],{},[289,2900,2901],{},"Prose-only Markdown files are now analyzed",[261,2903,2904],{},".md"," files without fenced code blocks were silently skipped; duplicated prose is now detected as clones, while embedded code fences keep being detected under their own sub-format pools. (",[249,2907,2910],{"href":2908,"rel":2909},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fissues\u002F883",[253],"#883",[278,2912,2914],{"id":2913},"v506-v5013-highlights","v5.0.6 – v5.0.13 highlights",[283,2916,2917,2927,2937,2943,2952,2965,2985],{},[286,2918,2919,2922,2923,2926],{},[289,2920,2921],{},"v5.0.11"," — Razor (",[261,2924,2925],{},".razor",") tokenizer support",[286,2928,2929,2932,2933,2936],{},[289,2930,2931],{},"v5.0.10"," — scan-root-relative paths in all reporters; ",[261,2934,2935],{},"--skip-local"," now matches v4 semantics",[286,2938,2939,2942],{},[289,2940,2941],{},"v5.0.9"," — GitHub Action for jscpd v5; fixed platform binary resolution for nested installs",[286,2944,2945,2948,2949,2951],{},[289,2946,2947],{},"v5.0.8"," — fixed mmap exhaustion on very large repos; fixed ",[261,2950,2103],{}," matching with absolute scan roots",[286,2953,2954,2957,2958,2961,2962],{},[289,2955,2956],{},"v5.0.7"," — fixed stack overflow on deeply-nested JS\u002FTS; ",[261,2959,2960],{},"--max-size"," defaults to ",[261,2963,2964],{},"1mb",[286,2966,2967,2970,2971,319,2974,319,2977,319,2979,2981,2982,2984],{},[289,2968,2969],{},"v5.0.6"," — v4 config backward compatibility (",[261,2972,2973],{},"path",[261,2975,2976],{},"pattern",[261,2978,904],{},[261,2980,1847],{},"); ",[261,2983,2081],{}," npm wrapper package; memory-mapped I\u002FO and SIMD line counting",[286,2986,2987,2990],{},[289,2988,2989],{},"v5.0.12 \u002F v5.0.13"," — dependency updates and npm packaging fixes",[245,2992,2993,2994,2999,3000,265],{},"Full details for every release are on ",[249,2995,2998],{"href":2996,"rel":2997},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Freleases",[253],"GitHub Releases"," and in the ",[249,3001,3003],{"href":251,"rel":3002},[253],"Rust changelog",[267,3005,3007],{"id":3006},"v504","v5.0.4",[278,3009,3011],{"id":3010},"the-rust-rewrite","The Rust Rewrite",[245,3013,3014,3015,3018],{},"jscpd v5 is a ",[289,3016,3017],{},"complete Rust rewrite"," — a new Rust engine shipped as a self-contained native binary with zero Node.js dependency, bringing parallel detection, near-zero startup cost, and a large performance improvement over the TypeScript engine.",[245,3020,3021,3022,3025],{},"See the ",[249,3023,3024],{"href":196},"Migration Guide"," for what changed and how to upgrade.",[278,3027,281],{"id":3028},"new-features-12",[283,3030,3031,3043,3049,3055,3064,3087,3096],{},[286,3032,3033,3036,3037,319,3040,3042],{},[289,3034,3035],{},"Native binary"," — no Node.js runtime required. Install via ",[261,3038,3039],{},"npm install -g jscpd",[261,3041,2143],{},", or direct download.",[286,3044,3045,3048],{},[289,3046,3047],{},"13 reporters"," — console, console-full, json, xml, csv, html, markdown, sarif, ai, badge, xcode, threshold, silent.",[286,3050,3051,3054],{},[289,3052,3053],{},"OXC-based JS\u002FTS tokenization"," — JavaScript\u002FTypeScript\u002FJSX\u002FTSX tokenization now uses the OXC parser instead of PrismJS for better accuracy and speed.",[286,3056,3057,1222,3060,3063],{},[289,3058,3059],{},"Parallel detection",[261,3061,3062],{},"--workers N"," controls thread count. Detection runs in parallel across format groups.",[286,3065,3066,2702,3069,319,3072,319,3075,319,3078,3081,3082,3084,3085,265],{},[289,3067,3068],{},"CLI alignment",[261,3070,3071],{},"--absolute",[261,3073,3074],{},"--ignore-case",[261,3076,3077],{},"--formats-exts",[261,3079,3080],{},"--formats-names"," flags; fixed ",[261,3083,633],{},"; improved ",[261,3086,2960],{},[286,3088,3089,3092,3093,265],{},[289,3090,3091],{},"Side-by-side blame"," — console-full reporter shows side-by-side blame comparison with ",[261,3094,3095],{},"--blame",[286,3097,3098,1222,3101,529,3104,3106],{},[289,3099,3100],{},"Dual npm package",[261,3102,3103],{},"jscpd@5",[261,3105,2085],{}," both install the same Rust binary via platform-specific optional dependencies.",[278,3108,3110],{"id":3109},"breaking-changes-from-v4","Breaking Changes from v4",[283,3112,3113,3122,3131,3144,3154,3160],{},[286,3114,3115,1222,3118,3121],{},[289,3116,3117],{},"No Node.js API",[261,3119,3120],{},"import { jscpd } from 'jscpd'"," is not available in v5. Use the CLI (with JSON output) or the Rust crates instead.",[286,3123,3124,3130],{},[289,3125,3126,3127],{},"No ",[261,3128,3129],{},"--store leveldb"," — external store backends are not supported in v5 (detection is fast enough without caching).",[286,3132,3133,3136,3137,3140,3141,3143],{},[289,3134,3135],{},"Reporter name change"," — v4's ",[261,3138,3139],{},"full"," reporter is now ",[261,3142,2615],{}," in v5.",[286,3145,3146,3149,3150,3153],{},[289,3147,3148],{},"Output filenames"," — HTML reporter outputs ",[261,3151,3152],{},"jscpd-report.html"," at the output directory root.",[286,3155,3156,3159],{},[289,3157,3158],{},"Token counts"," — may differ by 1-2% due to the Rust tokenizer using OXC for JS\u002FTS.",[286,3161,3162,3165],{},[289,3163,3164],{},"Format count"," — 223 formats (vs. v4's 224).",[278,3167,3169],{"id":3168},"v503","v5.0.3",[283,3171,3172,3175,3178,3181,3184],{},[286,3173,3174],{},"Full Rust CLI feature parity with TypeScript jscpd",[286,3176,3177],{},"Cross-platform binary distribution via npm platform packages",[286,3179,3180],{},"CLI short-form aliases matching TypeScript jscpd conventions",[286,3182,3183],{},"Time reporter for execution timing",[286,3185,3186],{},"ReportContext struct for extensible reporter signatures",[278,3188,3190],{"id":3189},"v502","v5.0.2",[283,3192,3193,3196,3199,3202],{},[286,3194,3195],{},"Fixed Vue SFC tokenization (each block dispatched to its own sub-format)",[286,3197,3198],{},"Fixed entire-file duplicates silently dropped by RabinKarp store flush logic",[286,3200,3201],{},"Fixed ReDoS hang on Lisp\u002FElisp files",[286,3203,3204],{},"Fixed crash on malformed package.json when reading config",[278,3206,3208],{"id":3207},"v501","v5.0.1",[283,3210,3211,3214,3217],{},[286,3212,3213],{},"Initial Rust workspace with cpd-core, cpd-tokenizer, cpd-finder, cpd-reporter, and jscpd crates",[286,3215,3216],{},"Cross-format detection for Vue SFC, Svelte, Astro, and Markdown",[286,3218,3219],{},"Shebang detection for extensionless scripts",[278,3221,3223],{"id":3222},"v500","v5.0.0",[283,3225,3226,3229],{},[286,3227,3228],{},"First stable Rust release — replaces the TypeScript CLI with a native binary",[286,3230,3231],{},"Reporter trait signature changed to use ReportContext instead of Statistics directly",[267,3233,3235],{"id":3234},"v425","v4.2.5",[283,3237,3238],{},[286,3239,3240],{},"JSON reporter token count fix, gitignore parent-directory walk, Commander v15, Vitest 4.1.0",[267,3242,3244],{"id":3243},"v423","v4.2.3",[283,3246,3247,3253],{},[286,3248,3249,3252],{},[289,3250,3251],{},"fix(finder):"," resolve relative ignore patterns against scan dirs (#611)",[286,3254,3255],{},"Dependency bumps across all packages",[267,3257,3259],{"id":3258},"v422","v4.2.2",[283,3261,3262],{},[286,3263,3264,3267],{},[289,3265,3266],{},"fix(tokenizer):"," resolve quadratic bash tokenization hang",[267,3269,3271],{"id":3270},"v421","v4.2.1",[283,3273,3274],{},[286,3275,3276,3278],{},[289,3277,3266],{}," fix tokenization issue for cross-format detection",[267,3280,3282],{"id":3281},"v420","v4.2.0",[278,3284,281],{"id":3285},"new-features-13",[283,3287,3288,3297,3314,3324,3334,3342,3354],{},[286,3289,3290,1222,3293,3296],{},[289,3291,3292],{},"Custom tokenizer backend",[261,3294,3295],{},"@jscpd\u002Ftokenizer"," now uses a self-contained reprism-based engine. ~11.5% faster tokenization on real projects (avg 1126 ms → 997 ms on a 548-file, 223-format scan).",[286,3298,3299,3301,3302,3305,3306,3309,3310,3313],{},[289,3300,55],{}," — Vue SFC (",[261,3303,3304],{},".vue","), Svelte (",[261,3307,3308],{},".svelte","), Astro (",[261,3311,3312],{},".astro","), and Markdown files are tokenized per-block\u002Fper-section, enabling duplicate detection between embedded blocks and standalone source files.",[286,3315,3316,3319,3320,3323],{},[289,3317,3318],{},"223 supported formats"," — Apex, CFML\u002FColdFusion, GDScript, Svelte, Astro, and 70+ additional languages (up from 152). Run ",[261,3321,3322],{},"jscpd --list"," to see the full list.",[286,3325,3326,3329,3330,3333],{},[289,3327,3328],{},"Shebang detection"," — extensionless executable scripts are auto-detected via their ",[261,3331,3332],{},"#!"," shebang line.",[286,3335,3336,3341],{},[289,3337,3338],{},[261,3339,3340],{},"--store-path"," — specify a custom directory for the LevelDB token cache, eliminating collisions when multiple jscpd processes run concurrently.",[286,3343,3344,3349,3350,3353],{},[289,3345,3346],{},[261,3347,3348],{},"--skipComments"," — shorthand for ",[261,3351,3352],{},"--mode weak",". Strips comments before tokenization.",[286,3355,3356,3360,3361,319,3364,3367],{},[289,3357,3358],{},[261,3359,3080],{}," — map specific filenames (e.g. ",[261,3362,3363],{},"Makefile",[261,3365,3366],{},"Dockerfile",") to a detection format.",[278,3369,563],{"id":3370},"bug-fixes-11",[283,3372,3373,3382,3390,3398,3404,3412],{},[286,3374,3375,3378,3379,265],{},[289,3376,3377],{},"Entire-file duplicates silently dropped"," (#728) — fixed RabinKarp end-of-file flush bug in ",[261,3380,3381],{},"@jscpd\u002Fcore",[286,3383,3384,3387,3388,265],{},[289,3385,3386],{},"ReDoS hang on Lisp\u002FElisp files"," (#737) — replaced catastrophic backtracking with a linear regex in ",[261,3389,3295],{},[286,3391,3392,3397],{},[289,3393,3394,3395],{},"Process crash on malformed ",[261,3396,843],{}," (#739) — now emits a warning and continues.",[286,3399,3400,3403],{},[289,3401,3402],{},"Vue SFC cross-file detection broken"," — blocks now use resolved sub-format namespace.",[286,3405,3406,3409,3410,265],{},[289,3407,3408],{},"Vue SFC incorrect column numbers"," — fixed in ",[261,3411,3295],{},[286,3413,3414,3417],{},[289,3415,3416],{},"50 dependency security vulnerabilities"," remediated.",[267,3419,3421],{"id":3420},"v411","v4.1.1",[283,3423,3424],{},[286,3425,3426],{},"Update hash function, improve performance and keep browser support.",[267,3428,3430],{"id":3429},"v410","v4.1.0",[283,3432,3433,3443,3452,3458,3464,3470],{},[286,3434,3435,3438,3439,3442],{},[289,3436,3437],{},"AI reporter"," (",[261,3440,3441],{},"--reporters ai",") — compact, token-efficient output for LLMs.",[286,3444,3445,3451],{},[289,3446,3447,3450],{},[261,3448,3449],{},"--noTips"," flag"," — suppress usage-tip messages after detection.",[286,3453,3454,3457],{},[289,3455,3456],{},"Execution timer"," — timing summary shown after detection completes.",[286,3459,3460,3463],{},[289,3461,3462],{},"Tokenizer speed"," — lazy Prism grammar loading, O(1) extension lookup, native MD5 hashing.",[286,3465,3466,3469],{},[289,3467,3468],{},"New languages:"," Apex and CFML (ColdFusion).",[286,3471,3472],{},"Test coverage raised to 98%+.",[267,3474,3476],{"id":3475},"earlier-releases-v1x-v40x","Earlier releases (v1.x – v4.0.x)",[245,3478,3021,3479,3486],{},[249,3480,3483,3484,264],{"href":3481,"rel":3482},"https:\u002F\u002Fgithub.com\u002Fkucherenko\u002Fjscpd\u002Fblob\u002Fmaster-v4\u002FCHANGELOG.md",[253],"root CHANGELOG on the ",[261,3485,263],{}," for the full history of jscpd versions 1.0.0 through 4.0.9, covering the tool's origins, the TypeScript rewrite, LevelDB store, pluggable reporters, monorepo extraction, and all the improvements made from 2018 through 2024.",{"title":3488,"searchDepth":3489,"depth":3489,"links":3490},"",2,[3491,3496,3501,3506,3511,3516,3522,3528,3533,3537,3542,3547,3552,3557,3566,3567,3568,3569,3570,3574,3575,3576],{"id":269,"depth":3489,"text":270,"children":3492},[3493,3495],{"id":280,"depth":3494,"text":281},3,{"id":395,"depth":3494,"text":396},{"id":431,"depth":3489,"text":432,"children":3497},[3498,3499,3500],{"id":440,"depth":3494,"text":281},{"id":562,"depth":3494,"text":563},{"id":618,"depth":3494,"text":619},{"id":668,"depth":3489,"text":669,"children":3502},[3503,3504,3505],{"id":677,"depth":3494,"text":281},{"id":737,"depth":3494,"text":563},{"id":795,"depth":3494,"text":619},{"id":821,"depth":3489,"text":822,"children":3507},[3508,3509,3510],{"id":830,"depth":3494,"text":281},{"id":935,"depth":3494,"text":563},{"id":1054,"depth":3494,"text":619},{"id":1074,"depth":3489,"text":1075,"children":3512},[3513,3514,3515],{"id":1083,"depth":3494,"text":281},{"id":1254,"depth":3494,"text":563},{"id":1338,"depth":3494,"text":1339},{"id":1357,"depth":3489,"text":1358,"children":3517},[3518,3519,3520,3521],{"id":1366,"depth":3494,"text":281},{"id":1469,"depth":3494,"text":563},{"id":1536,"depth":3494,"text":619},{"id":1602,"depth":3494,"text":1339},{"id":1620,"depth":3489,"text":1621,"children":3523},[3524,3525,3526,3527],{"id":1629,"depth":3494,"text":281},{"id":1837,"depth":3494,"text":563},{"id":1911,"depth":3494,"text":619},{"id":1941,"depth":3494,"text":1339},{"id":1990,"depth":3489,"text":1991,"children":3529},[3530,3531,3532],{"id":1999,"depth":3494,"text":281},{"id":2065,"depth":3494,"text":563},{"id":2149,"depth":3494,"text":619},{"id":2230,"depth":3489,"text":2231,"children":3534},[3535,3536],{"id":2239,"depth":3494,"text":563},{"id":2284,"depth":3494,"text":619},{"id":2302,"depth":3489,"text":2303,"children":3538},[3539,3540,3541],{"id":2306,"depth":3494,"text":281},{"id":2439,"depth":3494,"text":563},{"id":2481,"depth":3494,"text":1339},{"id":2558,"depth":3489,"text":2559,"children":3543},[3544,3545,3546],{"id":2562,"depth":3494,"text":281},{"id":2652,"depth":3494,"text":2653},{"id":2670,"depth":3494,"text":1339},{"id":2690,"depth":3489,"text":2691,"children":3548},[3549,3550,3551],{"id":2694,"depth":3494,"text":281},{"id":2766,"depth":3494,"text":563},{"id":2810,"depth":3494,"text":1339},{"id":2839,"depth":3489,"text":2840,"children":3553},[3554,3555,3556],{"id":2843,"depth":3494,"text":281},{"id":2894,"depth":3494,"text":563},{"id":2913,"depth":3494,"text":2914},{"id":3006,"depth":3489,"text":3007,"children":3558},[3559,3560,3561,3562,3563,3564,3565],{"id":3010,"depth":3494,"text":3011},{"id":3028,"depth":3494,"text":281},{"id":3109,"depth":3494,"text":3110},{"id":3168,"depth":3494,"text":3169},{"id":3189,"depth":3494,"text":3190},{"id":3207,"depth":3494,"text":3208},{"id":3222,"depth":3494,"text":3223},{"id":3234,"depth":3489,"text":3235},{"id":3243,"depth":3489,"text":3244},{"id":3258,"depth":3489,"text":3259},{"id":3270,"depth":3489,"text":3271},{"id":3281,"depth":3489,"text":3282,"children":3571},[3572,3573],{"id":3285,"depth":3494,"text":281},{"id":3370,"depth":3494,"text":563},{"id":3420,"depth":3489,"text":3421},{"id":3429,"depth":3489,"text":3430},{"id":3475,"depth":3489,"text":3476},"Release history and what's new in jscpd.","md",null,{},{"icon":193},{"title":190,"description":3583},"jscpd release notes and version history.","xZvfqsGed6smrLbiKXHGzmlPohSmK_Zr4U2TAwhmZzU",[3586,3588],{"title":181,"path":182,"stem":183,"description":3587,"icon":68,"children":-1},"The library crates behind the jscpd binary, what each one exposes, a compiling example for each, and their current versions.",{"title":195,"path":196,"stem":197,"description":3589,"icon":198,"children":-1},"Guide for upgrading from jscpd v4 (TypeScript) to v5 (Rust).",1791302980028]