jscpd-rs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/Cargo.lock +1323 -0
- package/Cargo.toml +54 -0
- package/LICENSE +21 -0
- package/README.md +372 -0
- package/docs/api-parity.md +49 -0
- package/docs/cloning-plan.md +281 -0
- package/docs/compat-baseline.md +535 -0
- package/docs/format-porting.md +86 -0
- package/docs/junior-task-template.md +62 -0
- package/docs/junior-workflow.md +87 -0
- package/docs/migrating-from-jscpd.md +193 -0
- package/docs/npm-release.md +116 -0
- package/docs/public-benchmark-suite.md +81 -0
- package/docs/release-checklist.md +200 -0
- package/docs/release-decisions.md +103 -0
- package/docs/release-readiness.md +51 -0
- package/docs/upstream-bugs.md +501 -0
- package/docs/upstream-issue-drafts.md +393 -0
- package/docs/user-guide.md +309 -0
- package/examples/dump_oxc_tokens.rs +112 -0
- package/examples/library_api.rs +42 -0
- package/npm/bin/jscpd-rs.js +6 -0
- package/npm/bin/jscpd-server.js +6 -0
- package/npm/lib/run-binary.js +68 -0
- package/npm/scripts/postinstall.js +50 -0
- package/package.json +53 -0
- package/skills/dry-refactoring/SKILL.md +63 -0
- package/skills/jscpd/SKILL.md +85 -0
- package/src/app.rs +512 -0
- package/src/bin/jscpd-server.rs +429 -0
- package/src/blame.rs +130 -0
- package/src/cli/config.rs +543 -0
- package/src/cli/parsing.rs +301 -0
- package/src/cli/tests.rs +543 -0
- package/src/cli.rs +671 -0
- package/src/detector/matching/secondary.rs +387 -0
- package/src/detector/matching.rs +274 -0
- package/src/detector/model.rs +190 -0
- package/src/detector/prepare.rs +71 -0
- package/src/detector/skip_local.rs +40 -0
- package/src/detector/statistics.rs +138 -0
- package/src/detector/store.rs +96 -0
- package/src/detector/tests.rs +238 -0
- package/src/detector.rs +265 -0
- package/src/files/discovery.rs +508 -0
- package/src/files/gitignore.rs +203 -0
- package/src/files/paths.rs +68 -0
- package/src/files/shebang.rs +106 -0
- package/src/files/tests.rs +523 -0
- package/src/files.rs +25 -0
- package/src/formats.rs +570 -0
- package/src/lib.rs +433 -0
- package/src/main.rs +26 -0
- package/src/report/ai.rs +125 -0
- package/src/report/badge.rs +238 -0
- package/src/report/console.rs +180 -0
- package/src/report/console_common.rs +37 -0
- package/src/report/console_full.rs +139 -0
- package/src/report/csv.rs +65 -0
- package/src/report/escape.rs +8 -0
- package/src/report/file_output.rs +28 -0
- package/src/report/html/assets.rs +47 -0
- package/src/report/html.rs +336 -0
- package/src/report/json.rs +119 -0
- package/src/report/markdown.rs +125 -0
- package/src/report/sarif.rs +302 -0
- package/src/report/silent.rs +22 -0
- package/src/report/source.rs +38 -0
- package/src/report/summary.rs +50 -0
- package/src/report/test_support.rs +133 -0
- package/src/report/threshold.rs +76 -0
- package/src/report/xcode.rs +90 -0
- package/src/report/xml.rs +119 -0
- package/src/report.rs +250 -0
- package/src/server/mcp.rs +942 -0
- package/src/server.rs +1081 -0
- package/src/tokenizer/apex.rs +97 -0
- package/src/tokenizer/blocks.rs +532 -0
- package/src/tokenizer/embedded.rs +106 -0
- package/src/tokenizer/generic.rs +511 -0
- package/src/tokenizer/hash.rs +27 -0
- package/src/tokenizer/ignore.rs +33 -0
- package/src/tokenizer/line_index.rs +33 -0
- package/src/tokenizer/markdown.rs +289 -0
- package/src/tokenizer/markup_attrs.rs +289 -0
- package/src/tokenizer/oxc/fallback.rs +275 -0
- package/src/tokenizer/oxc/jsx.rs +168 -0
- package/src/tokenizer/oxc/kind.rs +177 -0
- package/src/tokenizer/oxc/lexical.rs +67 -0
- package/src/tokenizer/oxc.rs +659 -0
- package/src/tokenizer/scan.rs +88 -0
- package/src/tokenizer/tap.rs +150 -0
- package/src/tokenizer/tests.rs +915 -0
- package/src/tokenizer.rs +328 -0
- package/src/verbose.rs +195 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Junior Task Template
|
|
2
|
+
|
|
3
|
+
Use this as the prompt body for `pi --no-session --tools read,edit,bash -p`.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
Junior helper task.
|
|
7
|
+
Goal: <one concrete deliverable>
|
|
8
|
+
Scope: edit only <exact file list>; read <exact reference files>.
|
|
9
|
+
Allowed actions:
|
|
10
|
+
- read <files>
|
|
11
|
+
- edit <files>
|
|
12
|
+
- run exactly `<verification command>` from <worktree path>
|
|
13
|
+
Verification: <exact command and expected high-level result>
|
|
14
|
+
Rules:
|
|
15
|
+
- stay in scope
|
|
16
|
+
- follow the nearest existing pattern
|
|
17
|
+
- do not change production logic unless explicitly requested
|
|
18
|
+
- do not edit generated files unless the task says so
|
|
19
|
+
- do not touch external repositories
|
|
20
|
+
- stop on blockers instead of guessing
|
|
21
|
+
Output: Russian report with Result, Evidence, Verification, Blockers.
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Example: Add One Test
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
Junior helper task.
|
|
28
|
+
Goal: Add one unit test proving weak mode skips TOML hash comments in the generic tokenizer.
|
|
29
|
+
Scope: edit only src/tokenizer.rs, preferably only the #[cfg(test)] module.
|
|
30
|
+
Allowed actions:
|
|
31
|
+
- read src/tokenizer.rs
|
|
32
|
+
- edit src/tokenizer.rs
|
|
33
|
+
- run exactly `cargo test tokenizer::tests::weak_mode_skips_generic_toml_comments` from /tmp/jscpd-rs-junior/toml-comments
|
|
34
|
+
Verification: the exact cargo test above passes.
|
|
35
|
+
Rules:
|
|
36
|
+
- follow the existing weak_mode_skips_generic_comments test style
|
|
37
|
+
- do not change production tokenizer logic
|
|
38
|
+
- use format `toml`
|
|
39
|
+
- assert exact token slices for the non-comment tokens
|
|
40
|
+
- stop on blockers
|
|
41
|
+
Output: Russian report with Result, Evidence, Verification, Blockers.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Example: Add One Format Smoke Fixture
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
Junior helper task.
|
|
48
|
+
Goal: Add a tiny smoke fixture and test for format <format>.
|
|
49
|
+
Scope: edit only <fixture files> and <one test file>.
|
|
50
|
+
Allowed actions:
|
|
51
|
+
- read docs/format-porting.md
|
|
52
|
+
- read the nearest existing test
|
|
53
|
+
- edit only the files listed in Scope
|
|
54
|
+
- run exactly `scripts/check-format.sh <format> <target>` from /tmp/jscpd-rs-junior/<task>
|
|
55
|
+
Verification: the exact check-format command passes.
|
|
56
|
+
Rules:
|
|
57
|
+
- keep fixtures minimal
|
|
58
|
+
- do not claim upstream parity
|
|
59
|
+
- do not edit src/formats.rs by hand
|
|
60
|
+
- stop on blockers
|
|
61
|
+
Output: Russian report with Result, Evidence, Verification, Blockers.
|
|
62
|
+
```
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Junior Workflow
|
|
2
|
+
|
|
3
|
+
This project can use a local junior agent for bounded implementation tasks. The
|
|
4
|
+
main agent remains responsible for scope, architecture, review, verification,
|
|
5
|
+
commits, and pushes.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
- Run at most one junior agent process at a time.
|
|
10
|
+
- Do not run junior work in the main checkout. Use a dedicated git worktree.
|
|
11
|
+
- Give small implementation tasks with an example, exact files, and exact tests.
|
|
12
|
+
- Do not delegate architecture, compatibility policy, broad reviews, or release
|
|
13
|
+
decisions.
|
|
14
|
+
- Do not let a junior touch external repositories outside the dedicated
|
|
15
|
+
worktree.
|
|
16
|
+
- Treat junior output as a patch proposal. Review every diff before merging.
|
|
17
|
+
- Prefer `pi` for one-shot tasks because `--no-session` and `--tools` make the
|
|
18
|
+
allowed surface explicit. Use `opencode` only as fallback.
|
|
19
|
+
|
|
20
|
+
## Worktree Loop
|
|
21
|
+
|
|
22
|
+
Create a worktree:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
scripts/junior-worktree.sh <task-slug>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Run the junior from the printed worktree path:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
cd "${JUNIOR_WORKTREE_ROOT:-${TMPDIR:-/tmp}/jscpd-rs-junior}/<task-slug>"
|
|
32
|
+
pi --no-session --tools read,edit,bash -p '<prompt from docs/junior-task-template.md>'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Review from the main checkout:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git -C "${JUNIOR_WORKTREE_ROOT:-${TMPDIR:-/tmp}/jscpd-rs-junior}/<task-slug>" status --short
|
|
39
|
+
git -C "${JUNIOR_WORKTREE_ROOT:-${TMPDIR:-/tmp}/jscpd-rs-junior}/<task-slug>" diff
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
If the patch is useful, apply it deliberately from the main checkout using
|
|
43
|
+
`git diff`, `git apply`, cherry-pick, or a manual patch. After review:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git worktree remove "${JUNIOR_WORKTREE_ROOT:-${TMPDIR:-/tmp}/jscpd-rs-junior}/<task-slug>"
|
|
47
|
+
git branch -D junior/<branch-name>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Good Junior Tasks
|
|
51
|
+
|
|
52
|
+
- Add one unit test following an existing nearby test.
|
|
53
|
+
- Add one small reporter or output-format test after the implementation exists.
|
|
54
|
+
- Add support for one comment style in a generic/native tokenizer.
|
|
55
|
+
- Add or update a small fixture for one format.
|
|
56
|
+
- Port one small function from upstream when the target shape is already clear.
|
|
57
|
+
- Run `scripts/check-format.sh <format> <target>` and report exact output.
|
|
58
|
+
|
|
59
|
+
## Prompt Notes
|
|
60
|
+
|
|
61
|
+
- Prefer implementation or test tasks over broad read-only scouting. A scout
|
|
62
|
+
prompt that is too procedural may produce a task plan instead of executing the
|
|
63
|
+
checks.
|
|
64
|
+
- For read-only fact gathering, explicitly say: "Execute the checks now; do not
|
|
65
|
+
write instructions or a plan."
|
|
66
|
+
- Keep fact-gathering prompts to exact files and exact commands. If there are
|
|
67
|
+
many commands, give a shell loop instead of asking the junior to design one.
|
|
68
|
+
- Do not use junior output as evidence until the main agent verifies the exact
|
|
69
|
+
commands or diff.
|
|
70
|
+
|
|
71
|
+
## Bad Junior Tasks
|
|
72
|
+
|
|
73
|
+
- Review a whole commit or subsystem.
|
|
74
|
+
- Decide whether compatibility is acceptable.
|
|
75
|
+
- Refactor detector/tokenizer architecture.
|
|
76
|
+
- Change generated format registry by hand.
|
|
77
|
+
- Touch multiple unrelated files.
|
|
78
|
+
- Run broad benchmarks or modify local third-party repositories.
|
|
79
|
+
|
|
80
|
+
## Review Checklist
|
|
81
|
+
|
|
82
|
+
- The diff only touches allowed files.
|
|
83
|
+
- The implementation follows an existing local pattern.
|
|
84
|
+
- Tests are exact enough to catch broken structure, not only `contains` checks.
|
|
85
|
+
- Commands in the report match commands actually run.
|
|
86
|
+
- `cargo fmt`, `cargo test`, and relevant scripts pass from the main checkout.
|
|
87
|
+
- Any accepted patch is committed by the main agent, not by the junior.
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Migrating From jscpd
|
|
2
|
+
|
|
3
|
+
`jscpd-rs` is a native Rust implementation of the common upstream `jscpd`
|
|
4
|
+
workflow. It scans source trees, reports duplicated fragments, and can fail CI
|
|
5
|
+
when duplication crosses a configured threshold.
|
|
6
|
+
|
|
7
|
+
The migration goal for the first release is practical CLI/reporting
|
|
8
|
+
compatibility for CI and local scans, not exact JavaScript package API parity.
|
|
9
|
+
|
|
10
|
+
## Quick Command Mapping
|
|
11
|
+
|
|
12
|
+
Cargo install:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
cargo install jscpd-rs --locked
|
|
16
|
+
jscpd --threshold 5 --exitCode 1 src
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
npm/npx after npm publication:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx jscpd-rs --threshold 5 --exitCode 1 src
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Common upstream command:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx jscpd src --reporters console,json --threshold 5 --exitCode 1
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Equivalent `jscpd-rs` command:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
jscpd src --reporters console,json --threshold 5 --exitCode 1
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
When installed from npm, the package exposes `jscpd-rs`, `jscpd`, and
|
|
38
|
+
`jscpd-server` bin names. The `jscpd` bin is an installed alias for the native
|
|
39
|
+
CLI so existing scripts can be tested with minimal command changes in a
|
|
40
|
+
controlled environment.
|
|
41
|
+
|
|
42
|
+
## Config Files
|
|
43
|
+
|
|
44
|
+
`jscpd-rs` reads the same common config locations:
|
|
45
|
+
|
|
46
|
+
- `.jscpd.json`
|
|
47
|
+
- `package.json#jscpd`
|
|
48
|
+
|
|
49
|
+
Example:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"path": ["src", "packages"],
|
|
54
|
+
"format": ["javascript", "typescript", "rust"],
|
|
55
|
+
"minLines": 5,
|
|
56
|
+
"minTokens": 50,
|
|
57
|
+
"threshold": 5,
|
|
58
|
+
"reporters": ["console", "json", "sarif"],
|
|
59
|
+
"output": "report",
|
|
60
|
+
"ignore": ["target/**", "node_modules/**", "dist/**"],
|
|
61
|
+
"gitignore": true,
|
|
62
|
+
"noTips": true
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
CLI arguments are applied after config loading, so command-line values can
|
|
67
|
+
override project defaults.
|
|
68
|
+
|
|
69
|
+
## Commonly Compatible Workflows
|
|
70
|
+
|
|
71
|
+
The first release targets these upstream-style workflows:
|
|
72
|
+
|
|
73
|
+
- local duplicate scan with `jscpd .`;
|
|
74
|
+
- threshold-based CI failure with `--threshold` and `--exitCode`;
|
|
75
|
+
- format filtering with `--format`;
|
|
76
|
+
- `.gitignore` and explicit `--ignore` handling;
|
|
77
|
+
- report generation with built-in reporters;
|
|
78
|
+
- Git blame reports with `--blame`;
|
|
79
|
+
- server startup with `jscpd-server`;
|
|
80
|
+
- snippet checks through the native REST/MCP server.
|
|
81
|
+
|
|
82
|
+
Built-in native reporters:
|
|
83
|
+
|
|
84
|
+
- `ai`
|
|
85
|
+
- `badge`
|
|
86
|
+
- `console`
|
|
87
|
+
- `consoleFull`
|
|
88
|
+
- `csv`
|
|
89
|
+
- `html`
|
|
90
|
+
- `json`
|
|
91
|
+
- `markdown`
|
|
92
|
+
- `sarif`
|
|
93
|
+
- `silent`
|
|
94
|
+
- `threshold`
|
|
95
|
+
- `xcode`
|
|
96
|
+
- `xml`
|
|
97
|
+
|
|
98
|
+
Machine-readable reporters are treated as compatibility-sensitive: JSON, SARIF,
|
|
99
|
+
XML, CSV, and Markdown should keep the shape expected by automation.
|
|
100
|
+
|
|
101
|
+
## Compatibility Model
|
|
102
|
+
|
|
103
|
+
The release gate is coverage-first. On the same inputs and options, `jscpd-rs`
|
|
104
|
+
must not miss duplicated source lines reported by upstream `jscpd`.
|
|
105
|
+
|
|
106
|
+
Exact clone pair identity, pair ordering, token totals, and some fragment
|
|
107
|
+
boundaries may differ while duplicated upstream source lines remain covered.
|
|
108
|
+
Extra Rust findings are allowed during convergence, but compatibility reports
|
|
109
|
+
keep them visible as `extra` findings.
|
|
110
|
+
|
|
111
|
+
This policy matters for multi-way clones: two implementations can pick
|
|
112
|
+
different clone pairs while still covering the same duplicated source ranges.
|
|
113
|
+
|
|
114
|
+
## Known First-Release Limits
|
|
115
|
+
|
|
116
|
+
These are intentional first-release limits:
|
|
117
|
+
|
|
118
|
+
- dynamic npm reporters, stores, listeners, and plugins are not loaded;
|
|
119
|
+
- unknown external reporter/store names keep upstream-style warnings where
|
|
120
|
+
upstream continues;
|
|
121
|
+
- HTML reports are self-contained and practically compatible, not
|
|
122
|
+
pixel-perfect;
|
|
123
|
+
- long-tail formats use a synchronized format registry plus generic native
|
|
124
|
+
tokenization unless a fixture or public-repo gate proves a more specific
|
|
125
|
+
tokenizer is needed;
|
|
126
|
+
- the Rust crate exposes a native Rust API, not the upstream JavaScript package
|
|
127
|
+
API;
|
|
128
|
+
- first npm packaging is source-build: a Rust/Cargo toolchain is required during
|
|
129
|
+
install until prebuilt platform packages are added.
|
|
130
|
+
|
|
131
|
+
## Compare On Your Repository
|
|
132
|
+
|
|
133
|
+
Run upstream and `jscpd-rs` with the same high-level options and compare the
|
|
134
|
+
generated JSON reports:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
node jscpd/apps/jscpd/bin/jscpd src \
|
|
138
|
+
--reporters json \
|
|
139
|
+
--output /tmp/jscpd-upstream \
|
|
140
|
+
--min-tokens 50 \
|
|
141
|
+
--min-lines 5 \
|
|
142
|
+
--exitCode 0
|
|
143
|
+
|
|
144
|
+
jscpd src \
|
|
145
|
+
--reporters json \
|
|
146
|
+
--output /tmp/jscpd-rs \
|
|
147
|
+
--min-tokens 50 \
|
|
148
|
+
--min-lines 5 \
|
|
149
|
+
--exitCode 0
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The repository scripts include the same coverage-first comparator used by the
|
|
153
|
+
release gates:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
FORMAT=typescript MIN_TOKENS=50 MIN_LINES=5 STRICT=coverage \
|
|
157
|
+
scripts/compat.sh /path/to/project
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
If `jscpd-rs` misses duplicated lines that upstream reports, that is a
|
|
161
|
+
compatibility bug. If `jscpd-rs` reports additional findings, include them in
|
|
162
|
+
the issue too; they help decide whether a tokenizer or boundary rule needs
|
|
163
|
+
tightening.
|
|
164
|
+
|
|
165
|
+
## CI Migration Pattern
|
|
166
|
+
|
|
167
|
+
Existing upstream-style CI:
|
|
168
|
+
|
|
169
|
+
```yaml
|
|
170
|
+
- run: npx jscpd src --reporters console,json --threshold 5 --exitCode 1
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Cargo-based `jscpd-rs` CI:
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
177
|
+
- run: cargo install jscpd-rs --locked
|
|
178
|
+
- run: jscpd src --reporters console,json --threshold 5 --exitCode 1
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
npm/npx-based `jscpd-rs` CI after npm publication:
|
|
182
|
+
|
|
183
|
+
```yaml
|
|
184
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
185
|
+
- uses: actions/setup-node@v5
|
|
186
|
+
with:
|
|
187
|
+
node-version: 22
|
|
188
|
+
- run: npx jscpd-rs src --reporters console,json --threshold 5 --exitCode 1
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The npm source-build package still needs Rust available during installation.
|
|
192
|
+
Prebuilt npm platform packages are planned as a publication improvement.
|
|
193
|
+
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Npm Release Preparation
|
|
2
|
+
|
|
3
|
+
Current npm readiness snapshot:
|
|
4
|
+
|
|
5
|
+
- Date: 2026-06-01.
|
|
6
|
+
- Baseline commit: `e343350`; rerun `scripts/npm-package-check.sh` on the
|
|
7
|
+
exact checkout before npm publish.
|
|
8
|
+
- GitHub Actions `release-gate`: passed on run `26743839098`.
|
|
9
|
+
- Local checks passed: `cargo test`, `scripts/package-check.sh`,
|
|
10
|
+
`scripts/npm-package-check.sh`, local `npx --no-install` smoke for
|
|
11
|
+
`jscpd-rs`, `jscpd`, and `jscpd-server`.
|
|
12
|
+
- Package name status: `npm view jscpd-rs version` returned `E404`.
|
|
13
|
+
- Packed artifact audit: `jscpd-rs-0.1.0.tgz`, 96 files, about 169 KiB packed,
|
|
14
|
+
about 708 KiB unpacked.
|
|
15
|
+
|
|
16
|
+
The first npm package is `jscpd-rs`. It exposes these bin commands:
|
|
17
|
+
|
|
18
|
+
- `jscpd-rs`: primary `npx jscpd-rs` entrypoint, runs the native `jscpd` CLI.
|
|
19
|
+
- `jscpd`: installed alias for the native `jscpd` CLI.
|
|
20
|
+
- `jscpd-server`: installed alias for the native server binary.
|
|
21
|
+
|
|
22
|
+
The package is intentionally source-build for the first release candidate:
|
|
23
|
+
`postinstall` runs `cargo build --release --locked --bin jscpd --bin
|
|
24
|
+
jscpd-server` inside the installed npm package. This keeps the npm path simple
|
|
25
|
+
and verifiable before publication. Users installing from npm need Node, npm, and
|
|
26
|
+
a Rust/Cargo toolchain. Prebuilt platform packages can be added later without
|
|
27
|
+
changing the CLI behavior.
|
|
28
|
+
|
|
29
|
+
Local verification:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
scripts/npm-package-check.sh
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
That script verifies:
|
|
36
|
+
|
|
37
|
+
- `package.json` version matches `Cargo.toml`;
|
|
38
|
+
- `npm pack` includes the expected Rust source and npm shim files;
|
|
39
|
+
- `npm pack` includes the advertised `skills/` files used by the terminal tip;
|
|
40
|
+
- forbidden paths such as `jscpd/`, `target/`, `report/`, `scripts/`, and
|
|
41
|
+
`node_modules/` are not packed;
|
|
42
|
+
- `npm publish --dry-run --json` succeeds without publishing;
|
|
43
|
+
- installing the packed tarball without Cargo fails with the expected Rust
|
|
44
|
+
toolchain hint;
|
|
45
|
+
- a local npm install exposes working `jscpd-rs`, `jscpd`, and `jscpd-server`
|
|
46
|
+
bin commands;
|
|
47
|
+
- `npx --package <local-tarball> jscpd-rs --version` works.
|
|
48
|
+
|
|
49
|
+
Before actual publication, run:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git status --short
|
|
53
|
+
npm whoami
|
|
54
|
+
scripts/npm-package-check.sh
|
|
55
|
+
npm view jscpd-rs version
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`npm view` should return `E404` for the first publication, or the package must
|
|
59
|
+
already be owned by this project. Do not run `npm publish` until explicit
|
|
60
|
+
release approval.
|
|
61
|
+
|
|
62
|
+
Do not use `scripts/prepublish-check.sh` as the npm-only gate after the Cargo
|
|
63
|
+
crate and GitHub tag have already been published: that script is the full
|
|
64
|
+
Cargo/GitHub first-publication gate and intentionally checks that the crate name
|
|
65
|
+
and release tag are still available.
|
|
66
|
+
|
|
67
|
+
If the package name is still free and the npm account is logged in:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
scripts/npm-package-check.sh
|
|
71
|
+
npm publish --access public
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If the account requires a one-time password for publish:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm publish --access public --otp 123456
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Trusted Publishing
|
|
81
|
+
|
|
82
|
+
Trusted Publishing is the preferred npm path for CI/CD publishing. npm trusts a
|
|
83
|
+
specific GitHub Actions workflow through OIDC, so the workflow can publish
|
|
84
|
+
without a long-lived npm token. For public packages published from public
|
|
85
|
+
repositories, npm also generates provenance attestations automatically.
|
|
86
|
+
|
|
87
|
+
This repository provides a manual publish workflow:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
.github/workflows/npm-publish.yml
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Configure npm:
|
|
94
|
+
|
|
95
|
+
1. Open the `jscpd-rs` package settings on npmjs.com.
|
|
96
|
+
2. Go to **Trusted Publisher**.
|
|
97
|
+
3. Select **GitHub Actions**.
|
|
98
|
+
4. Use these values:
|
|
99
|
+
- Organization or user: `vv-bogdanov`
|
|
100
|
+
- Repository: `jscpd-rs`
|
|
101
|
+
- Workflow filename: `npm-publish.yml`
|
|
102
|
+
- Environment name: leave empty
|
|
103
|
+
- Allowed actions: `npm publish`
|
|
104
|
+
|
|
105
|
+
Then publish from GitHub:
|
|
106
|
+
|
|
107
|
+
1. Open GitHub Actions.
|
|
108
|
+
2. Select the `npm-publish` workflow.
|
|
109
|
+
3. Click **Run workflow** on `main`.
|
|
110
|
+
4. Enter `jscpd-rs` for `package_name`.
|
|
111
|
+
5. Run the workflow.
|
|
112
|
+
|
|
113
|
+
If npm does not allow Trusted Publishing configuration before the first package
|
|
114
|
+
version exists, publish the first version with either interactive 2FA or a
|
|
115
|
+
short-lived granular token with bypass 2FA enabled, then immediately configure
|
|
116
|
+
Trusted Publishing for future releases.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Public Benchmark Suite
|
|
2
|
+
|
|
3
|
+
The release benchmark suite uses popular public repositories cloned under
|
|
4
|
+
`${XDG_CACHE_HOME:-$HOME/.cache}/jscpd-rs/public-bench/repos` by default. These
|
|
5
|
+
clones are generated local state outside this git repo.
|
|
6
|
+
|
|
7
|
+
Keep benchmark repositories outside this project tree unless you intentionally
|
|
8
|
+
disable parent `.gitignore` effects. Upstream `jscpd` respects parent ignore
|
|
9
|
+
files and can silently skip repo-internal benchmark directories that are
|
|
10
|
+
gitignored.
|
|
11
|
+
|
|
12
|
+
Upstream `jscpd` does not currently ship a public-repository performance suite.
|
|
13
|
+
Its monorepo scripts expose `pnpm test`, CI runs build/lint/test plus
|
|
14
|
+
`./apps/jscpd/bin/jscpd ./fixtures`, and the README benchmark note is based on
|
|
15
|
+
the local `fixtures/` directory. This suite is therefore a project-owned release
|
|
16
|
+
gate for product-scale speed checks.
|
|
17
|
+
|
|
18
|
+
Configured cases:
|
|
19
|
+
|
|
20
|
+
| Case | Repository | Branch | Format |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `react` | `https://github.com/facebook/react.git` | `main` | `javascript` |
|
|
23
|
+
| `next` | `https://github.com/vercel/next.js.git` | `canary` | `typescript` |
|
|
24
|
+
| `vscode` | `https://github.com/microsoft/vscode.git` | `main` | `typescript` |
|
|
25
|
+
| `prometheus` | `https://github.com/prometheus/prometheus.git` | `main` | `go` |
|
|
26
|
+
| `rust` | `https://github.com/rust-lang/rust.git` | `main` | `rust` |
|
|
27
|
+
|
|
28
|
+
Usage:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
LIST=1 scripts/public-bench-suite.sh
|
|
32
|
+
CASES=react,next RUNS=3 scripts/public-bench-suite.sh
|
|
33
|
+
CHECK_COMPAT=1 CASES=react scripts/public-bench-suite.sh
|
|
34
|
+
MIN_SPEEDUP=10 CASES=react,next RUNS=3 scripts/public-bench-suite.sh
|
|
35
|
+
UPSTREAM_TIMEOUT=600s CASES=vscode RUNS=1 scripts/public-bench-suite.sh
|
|
36
|
+
PUBLIC=1 PUBLIC_CASES=react,next PUBLIC_RUNS=3 scripts/release-gate.sh
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Default behavior clones missing repositories with `--depth=1`, runs Rust and
|
|
40
|
+
upstream `jscpd` through `scripts/bench.sh`, and writes raw benchmark output to
|
|
41
|
+
`$BENCH_ROOT/results`. It also writes a TSV summary to
|
|
42
|
+
`$BENCH_ROOT/results/summary.tsv` with case, commit, format, Rust average,
|
|
43
|
+
upstream average, speedup, and compatibility status. Set `UPDATE=1` to refresh
|
|
44
|
+
existing clones. Set `MIN_SPEEDUP` to make the suite fail when any selected
|
|
45
|
+
case falls below the required upstream/Rust speedup. Each upstream timing run is
|
|
46
|
+
bounded by `UPSTREAM_TIMEOUT` (`600s` by default) so optional stress cases cannot
|
|
47
|
+
hang a release gate indefinitely; set `RUST_TIMEOUT` or `UPSTREAM_TIMEOUT` to an
|
|
48
|
+
empty value to disable that side's timeout.
|
|
49
|
+
|
|
50
|
+
When `CHECK_COMPAT=1` is enabled, the suite runs the same coverage-first report
|
|
51
|
+
comparison used by the fixture gates. `react`, `next`, and `prometheus` include
|
|
52
|
+
narrow allowlists for upstream overextended ranges documented in
|
|
53
|
+
`docs/upstream-bugs.md`; those entries are printed as ignored line-coverage
|
|
54
|
+
exceptions in the comparison output. New public benchmark misses should be fixed
|
|
55
|
+
or documented before they are added to this allowlist.
|
|
56
|
+
|
|
57
|
+
Recorded release-candidate measurements on May 31, 2026:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
scripts/release-candidate.sh
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Case | Commit | Format | Rust avg | Upstream avg | Speedup | Compat |
|
|
64
|
+
| --- | --- | --- | ---: | ---: | ---: | --- |
|
|
65
|
+
| `react` | `f0dfee3` | `javascript` | 0.199097s | 10.079214s | 50.62x | pass |
|
|
66
|
+
| `next` | `2bbb67b9` | `typescript` | 0.262433s | 14.715736s | 56.07x | pass |
|
|
67
|
+
| `prometheus` | `a0524ee` | `go` | 0.085239s | 4.642435s | 54.46x | pass |
|
|
68
|
+
|
|
69
|
+
`kubernetes` was also checked as a Go stress case, but upstream `jscpd` ran out
|
|
70
|
+
of memory with the default Node heap, so it is intentionally not part of the
|
|
71
|
+
default release suite.
|
|
72
|
+
|
|
73
|
+
`vscode` is configured as an optional TypeScript stress case, but it is not part
|
|
74
|
+
of the default release suite yet. On May 31, 2026, Rust completed the timing run
|
|
75
|
+
in `1.464358s` at commit `e4074382`, while upstream was still running after
|
|
76
|
+
more than nine minutes and the exploratory run was stopped before compatibility
|
|
77
|
+
comparison. Keep it behind an explicit `CASES=vscode` run until we decide on a
|
|
78
|
+
separate slow-suite policy.
|
|
79
|
+
|
|
80
|
+
Before publication, rerun the suite on the selected cases and copy the measured
|
|
81
|
+
averages into `docs/compat-baseline.md` or release notes with commit hashes.
|