cuke-dedup 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 ADDED
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ All notable changes to CukeDedup are documented in this file. The project follows
4
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+
6
+ ## [0.1.0] - 2026-09-07
7
+
8
+ Initial public release.
9
+
10
+ ### Added
11
+
12
+ - Static duplicate, near-duplicate, ambiguous, reusable, and unused Cucumber step analysis.
13
+ - JavaScript, JSX, TypeScript, and TSX source adapters and Gherkin Markdown support.
14
+ - Terminal, JSON, JSON Lines, HTML, and SARIF reporters.
15
+ - Duplication thresholds, semantic baselines, changed-file analysis, suppressions, and ignore files.
16
+ - Native Cargo and npm distributions for eight supported targets.
17
+ - A checksum-verified GitHub Action and an agent-oriented CukeDedup skill.
18
+
19
+ [0.1.0]: https://github.com/figueiredoluiz/cuke-dedup/releases/tag/v0.1.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luiz Figueiredo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,386 @@
1
+ # CukeDedup
2
+
3
+ [![CI](https://github.com/figueiredoluiz/cuke-dedup/actions/workflows/ci.yml/badge.svg)](https://github.com/figueiredoluiz/cuke-dedup/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
+
6
+ CukeDedup finds duplicate, near-duplicate, ambiguous, reusable, and unused Cucumber/Gherkin step definitions. It analyzes source code statically: project configuration and test code are never executed.
7
+
8
+ Current support includes:
9
+
10
+ - JavaScript/JSX and TypeScript/TSX step definitions, including common module variants.
11
+ - Cucumber.js, Playwright BDD, and Cypress Cucumber workflows.
12
+ - Classic `.feature` files and Gherkin Markdown `.feature.md` files.
13
+ - Terminal, JSON, JSON Lines, HTML, and SARIF reports.
14
+ - Threshold, baseline, changed-file, suppression, and ignore-file workflows.
15
+
16
+ ## Install
17
+
18
+ Install the native CLI through Cargo:
19
+
20
+ ```sh
21
+ cargo install cuke-dedup
22
+ ```
23
+
24
+ Or install the native launcher in a JavaScript project:
25
+
26
+ ```sh
27
+ npm install --save-dev cuke-dedup
28
+ npx cuke-dedup .
29
+ ```
30
+
31
+ To build from source, clone the repository with Rust 1.90 or newer and run
32
+ `cargo build --release --locked`.
33
+
34
+ ## Usage
35
+
36
+ The path-only and explicit `check` forms are equivalent when both include a path:
37
+
38
+ ```sh
39
+ cuke-dedup .
40
+ cuke-dedup check .
41
+ cuke-dedup . --threshold 5
42
+ cuke-dedup . --print-config
43
+ cuke-dedup . --reporters terminal,json,html,sarif
44
+ cuke-dedup . --reporters jsonl
45
+ cuke-dedup . --output reports/cuke-dedup
46
+ ```
47
+
48
+ `check` is reserved as the explicit subcommand and requires a path. To analyze a directory literally named `check`, use `cuke-dedup ./check`.
49
+
50
+ With no configuration, CukeDedup respects `.gitignore` and `.cuke-dedupignore`, excludes common generated directories, discovers classic `.feature` files and Gherkin Markdown `.feature.md` files, and inspects conventional JavaScript/TypeScript step registrations such as `Given`, `When`, `Then`, and `defineStep`, including common aliases.
51
+
52
+ ## Configuration
53
+
54
+ ### Precedence and config files
55
+
56
+ Configuration precedence is:
57
+
58
+ ```text
59
+ CLI flags > explicit --config > auto-discovered CukeDedup config > detected framework configuration > built-in defaults
60
+ ```
61
+
62
+ CukeDedup accepts `--config/-c <file>`, auto-discovers one configuration source, and lets CLI values replace matching config values. Automatic discovery stops at the first valid source in this order:
63
+
64
+ ```text
65
+ .cuke-dedup.json
66
+ .config/cuke-dedup.json
67
+ .config/.cuke-dedup.json
68
+ cuke-dedup.config.json (legacy compatibility)
69
+ package.json#cukeDedup
70
+ ```
71
+
72
+ An explicit `--config` path bypasses automatic discovery and is a fatal configuration error when it cannot be read or parsed. Relative config, output, and baseline paths are resolved from the analyzed root. An invalid auto-discovered file emits a warning and falls through to the next source. JavaScript projects may use the `cukeDedup` key in `package.json`; other repositories should prefer `.cuke-dedup.json`.
73
+
74
+ ### Example configuration
75
+
76
+ ```json
77
+ {
78
+ "definitions": ["features/steps/**/*.ts"],
79
+ "features": ["features/**/*.{feature,feature.md}"],
80
+ "exclude": ["dist/**"],
81
+ "excludeDefaults": true,
82
+ "includeHidden": false,
83
+ "threshold": 5,
84
+ "requireFeatures": true,
85
+ "noMetrics": false,
86
+ "reporters": ["terminal", "json", "html", "sarif"],
87
+ "output": "reports/cuke-dedup",
88
+ "rules": {
89
+ "duplicate-matcher": "error",
90
+ "duplicate-handler": "error",
91
+ "near-duplicate-step": "warning",
92
+ "unused-definition": "off"
93
+ },
94
+ "suppressions": [
95
+ {
96
+ "rule": "duplicate-handler",
97
+ "path": "features/steps/legacy.ts",
98
+ "matcher": "the legacy flow is complete",
99
+ "reason": "Kept distinct while the legacy flow is retired"
100
+ }
101
+ ]
102
+ }
103
+ ```
104
+
105
+ ### Suppressions
106
+
107
+ Every suppression must include a non-empty `reason` and select at least a `path` or `matcher`:
108
+
109
+ - When both selectors are present, both must match.
110
+ - For a pair finding, a configured `path` must contain every involved definition.
111
+ - A matcher selector must select at least one involved definition.
112
+
113
+ These rules prevent a directory-scoped exception from hiding a conflict that crosses into maintained code.
114
+
115
+ One definition can instead carry an auditable source-local suppression. The directive must be immediately above the registration, select one rule, and include a reason:
116
+
117
+ ```ts
118
+ // cuke-dedup:ignore duplicate-handler -- retained for an external compatibility contract
119
+ Given("the legacy flow completes", legacyHandler);
120
+ ```
121
+
122
+ Malformed directives are operational errors rather than silently ignored comments. A directive suppresses findings involving its attached definition only.
123
+
124
+ ### Framework discovery and corpus boundaries
125
+
126
+ When `features` is not explicitly configured, CukeDedup statically reads literal paths from the project's BDD setup: Playwright-BDD's `defineBddConfig`, Cypress `e2e.specPattern` when the Badeball Cucumber preprocessor is installed, and Cucumber.js configuration. It never executes project configuration. Cucumber directories include both `.feature` and `.feature.md`; Playwright-BDD directories follow that framework's `.feature` default. Explicit file or glob paths are preserved, so a project can select names such as `*.spec`. Dynamic paths produce a warning and can be made deterministic by setting `features` in CukeDedup's own configuration.
127
+
128
+ Analysis is intentionally scoped to the supplied root: every discovered definition and feature under that root belongs to one comparison corpus. In a monorepo whose packages use independent step registries, run CukeDedup once per package (for example, `cuke-dedup packages/accounts`) instead of treating the monorepo root as one suite. Framework detection selects the appropriate registration patterns but does not silently split the corpus because mixed-framework projects can deliberately share definitions.
129
+
130
+ `.feature.md` selects the Gherkin Markdown parser. Other extensions selected by a custom or framework glob are treated as classic Gherkin. This prevents ordinary Markdown files from being scanned while still allowing conventions such as `.spec`.
131
+
132
+ ### Exclusions and ignore files
133
+
134
+ Configured `exclude` patterns replace custom patterns from lower-precedence layers, while built-in generated-directory exclusions remain independently enabled. An exclusion may name one file, one directory, or a glob.
135
+
136
+ - Set `excludeDefaults` to `false` to analyze an explicitly selected workspace under `node_modules`, `target`, or another protected directory.
137
+ - Set `includeHidden` to `true` to descend into dot-directories.
138
+ - Definitions, features, excludes, reporters, and suppressions replace the corresponding lower-precedence value.
139
+ - Scalar values and individual rule severities merge by precedence and rule name.
140
+
141
+ Configured `definitions`, `features`, `exclude`, and suppression-path values use `globset` syntax against root-relative paths normalized with `/`. `*` and `?` may cross `/`; use `**` when a recursive directory boundary should be obvious to readers. Character classes such as `[ab]`, brace alternatives such as `{js,ts}`, and backslash escaping are supported. These configuration globs are distinct from `.gitignore` and `.cuke-dedupignore`, which use directory-scoped gitignore semantics and support negation.
142
+
143
+ Repositories may also place a `.cuke-dedupignore` file at the analyzed root or in any descendant directory. It uses gitignore syntax: blank lines and `#` comments are ignored, `/` anchors a rule to the ignore file's directory, a trailing `/` selects directories, and `!` negates an earlier matching rule. Nested files apply only to their directory subtree. These rules are applied in addition to `.gitignore`, built-in exclusions, and configured `exclude` patterns. `--no-default-excludes` disables only the built-in generated-directory list; it does not disable either ignore file. Configured `exclude` patterns remain hard exclusions and cannot be negated from `.cuke-dedupignore`.
144
+
145
+ Example `.cuke-dedupignore`:
146
+
147
+ ```gitignore
148
+ # Generated feature sources
149
+ features/generated/*
150
+ **/*.generated.ts
151
+
152
+ # Keep one reviewed generated definition
153
+ !features/generated/reviewed.generated.ts
154
+ ```
155
+
156
+ ### CLI overrides and discovery diagnostics
157
+
158
+ Equivalent discovery and rule overrides are available from the CLI:
159
+
160
+ ```sh
161
+ cuke-dedup . \
162
+ --config .cuke-dedup.json \
163
+ --definitions 'features/steps/**/*.ts' \
164
+ --features 'features/**/*.feature' \
165
+ --exclude 'generated/legacy.ts' \
166
+ --exclude 'vendor' \
167
+ --exclude 'dist/**/*.ts' \
168
+ --threshold 5 \
169
+ --rule duplicate-matcher=warning
170
+ ```
171
+
172
+ `--exclude` may be repeated or receive comma-separated patterns. Patterns are resolved relative to the analyzed root. The CLI equivalents for the discovery escape hatches are `--no-default-excludes` and `--include-hidden`. Explicit definition globs do not implicitly weaken either safety default.
173
+
174
+ Use `--explain-discovery` to print the effective pattern origin, selected parser, matching pattern, and definition inputs without changing report output. Unmatched feature patterns are warnings. If definitions exist but no feature files match, CukeDedup warns and disables `unused-definition` findings rather than presenting an incomplete corpus as proof that every definition is unused. Set `requireFeatures: true` or pass `--require-features` to make that condition an operational failure (exit code `2`).
175
+
176
+ Malformed discovered JavaScript or TypeScript remains a fail-closed operational error because partial extraction could make a duplication gate pass incorrectly. Fix the syntax, use a `.tsx` extension for JSX-bearing TypeScript, or narrow `definitions` to the actual step-definition sources.
177
+
178
+ Use `--print-config` to serialize the fully merged and validated configuration as JSON and exit without discovery. The output includes the selected CukeDedup configuration source, framework-derived feature-pattern origin, CLI overrides, effective default exclusions, rule severities, and configuration warnings.
179
+
180
+ ## Rules
181
+
182
+ | Rule | Default | Meaning |
183
+ | --- | --- | --- |
184
+ | `duplicate-matcher` | Error | Definitions use the same effective matcher. |
185
+ | `normalized-matcher` | Error | Matchers become equivalent after normalization. |
186
+ | `ambiguous-step` | Error | A concrete feature step matches multiple definitions. |
187
+ | `duplicate-handler` | Error | Different matchers have the same alpha-normalized handler. |
188
+ | `near-duplicate-step` | Warning | Matcher wording is close and handler structure agrees. |
189
+ | `parameterization-candidate` | Warning | Handler structures differ primarily in literal values. |
190
+ | `unused-definition` | Warning | No discovered feature step uses the definition. |
191
+
192
+ Set a rule to `off`, `warning`, or `error` in configuration. The CLI also accepts `warn` as an alias for `warning`.
193
+
194
+ Exact handler equivalence is always reported as `duplicate-handler` when matchers are not equivalent. If the matcher wording is also close, the same retained pair may carry the advisory `near-duplicate-step` finding as additional evidence.
195
+
196
+ ## Duplication threshold
197
+
198
+ `threshold` controls the percentage of discovered definitions that may participate in active, error-level duplication findings. It accepts a value from `0` through `100` and defaults to `0`.
199
+
200
+ ```sh
201
+ cuke-dedup . --threshold 5
202
+ ```
203
+
204
+ The numerator contains unique definition locations involved in `duplicate-matcher`, `normalized-matcher`, `duplicate-handler`, and any `near-duplicate-step` or `parameterization-candidate` rule configured as an error. A definition is counted once even when it participates in several pairs. Suppressed and baselined findings do not count. The denominator is every discovered definition, including definitions without findings.
205
+
206
+ The threshold passes when the unrounded percentage is less than or equal to the configured value. Active `ambiguous-step` and `unused-definition` errors remain independently fatal because they are correctness and usage policies rather than duplication tolerance. Empty projects have a `0%` duplication rate.
207
+
208
+ ## Reports
209
+
210
+ Choose reporters according to how the result will be consumed:
211
+
212
+ | Reporter | Destination | Best for |
213
+ | --- | --- | --- |
214
+ | `terminal` | stdout | Interactive local use and concise CI logs. |
215
+ | `json` | File | Structured integration data. |
216
+ | `jsonl` | stdout | Streaming shell and agent workflows. |
217
+ | `html` | File | Human review with search, filters, and theme switching. |
218
+ | `sarif` | File | Code-scanning platforms such as GitHub. |
219
+
220
+ The `jsonl` reporter emits one compact object per finding followed by a final summary object. Because `terminal` and `jsonl` both own stdout, they cannot be selected together. JSONL can be combined with file reporters without contaminating the stream.
221
+
222
+ JSON, HTML, and SARIF reports default to `reports/cuke-dedup/` and can be redirected with `--output`. Relative output paths are resolved from the analyzed root, not the shell's current directory. File-only reporter runs print the generated report paths to stdout.
223
+
224
+ ### JSON and HTML
225
+
226
+ The JSON report uses schema version `1`. It includes relative source spans, severity, suppressions, similarity scores, suggested actions, structured matcher/handler evidence, threshold calculations, input counts, and execution metrics. The self-contained HTML report presents the same result with search, severity and rule filters, a light/dark theme switch, matcher differences, and side-by-side handler snippets.
227
+
228
+ Set `noMetrics: true`, pass `--no-metrics`, or use the Action's `no-metrics: true` input to omit timing data when byte-reproducible artifacts matter.
229
+
230
+ ### JSON Lines
231
+
232
+ JSONL schema version `1` is intended for streaming agent and shell consumption:
233
+
234
+ ```sh
235
+ cuke-dedup . --reporters jsonl \
236
+ | jq -c 'select(.type == "finding" and .active)'
237
+ ```
238
+
239
+ Each finding record is self-contained and carries a location-independent semantic fingerprint, active/suppressed state, threshold contribution, relative source spans, suggested action, and structured evidence. Free-text fields are capped at 2,000 Unicode characters; `truncatedFields` names every shortened field.
240
+
241
+ The final `type: "summary"` record declares `recordCount` and `truncated: false`, and includes aggregate counts, threshold outcome, and execution metrics. Operational warnings and errors remain on stderr, so stdout can be parsed incrementally.
242
+
243
+ ### SARIF, safety, and scale
244
+
245
+ SARIF 2.1.0 contains active findings, portable relative Unicode-aware locations, stable partial fingerprints, severity, similarity properties, suggested actions, and the threshold outcome for GitHub code scanning or another compatible consumer. Handler snippets are bounded before being embedded. HTML-visible text is escaped, bidirectional and invisible-format controls—including Unicode Tag characters—are removed, and embedded JSON characters that could close a script element are encoded.
246
+
247
+ Terminal, JSON, HTML, and SARIF output retain at most 10,000 findings, prioritizing active errors before warnings and clearly reporting truncation. Their summaries still describe the complete analysis. JSONL remains the uncapped finding stream.
248
+
249
+ ## Agent Skill
250
+
251
+ CukeDedup ships a portable Agent Skill that teaches coding assistants how to run the JSONL reporter, interpret its records, choose safe step-definition remediations, and verify the result without weakening the configured quality gate.
252
+
253
+ Install it from a local checkout:
254
+
255
+ ```sh
256
+ npx skills add ./skills --skill cuke-dedup
257
+ ```
258
+
259
+ Install it directly from GitHub:
260
+
261
+ ```sh
262
+ npx skills add figueiredoluiz/cuke-dedup --skill cuke-dedup
263
+ ```
264
+
265
+ The installer can target supported coding agents or install globally; consult `npx skills add --help` for the available agent and scope flags. The skill is delivered from [`skills/cuke-dedup`](https://github.com/figueiredoluiz/cuke-dedup/blob/main/skills/cuke-dedup/SKILL.md), independently of the Cargo and npm packages. Invoke it explicitly as `$cuke-dedup` where supported, or ask the agent to analyze and safely fix duplicate Cucumber step definitions.
266
+
267
+ ## GitHub Action
268
+
269
+ CukeDedup can run as a native, checksum- and provenance-verified GitHub Action without compiling Rust in the consumer repository:
270
+
271
+ ```yaml
272
+ permissions:
273
+ contents: read
274
+
275
+ steps:
276
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
277
+ with:
278
+ fetch-depth: 0
279
+ persist-credentials: false
280
+ - uses: figueiredoluiz/cuke-dedup@v0.1.0
281
+ id: cuke-dedup
282
+ with:
283
+ path: .
284
+ threshold: 5
285
+ config: .cuke-dedup.json
286
+ exclude: |
287
+ generated/**
288
+ fixtures/vendor/**
289
+ reporters: terminal,json,html,sarif
290
+ changed-since: ${{ github.event.pull_request.base.sha }}
291
+ no-metrics: true
292
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
293
+ if: always()
294
+ with:
295
+ name: cuke-dedup-reports
296
+ path: reports/cuke-dedup/
297
+ ```
298
+
299
+ The Action adds JSON internally when needed so its outputs are always available: `exit-code`, `duplicate-rate`, `duplicate-definitions`, `total-definitions`, `json-report`, `html-report`, and `sarif-report`. Omitted threshold, reporter, and output inputs retain the resolved project configuration; explicitly supplied Action inputs override it. Set `reporters: jsonl` when an agent-oriented workflow should receive the stream in the step log; the Action also creates its internal JSON report for outputs. Its optional `baseline` and `fail-on-new` inputs expose the semantic new-finding gate to pull-request workflows. Inputs are passed directly to the native process as an argument array. The `version` input selects one exact compatible release. Downloads fail closed when the archive, adjacent SHA-256 checksum, provenance bundle, or exact archive contents are missing or invalid. Provenance verification uses the GitHub CLI available on GitHub-hosted runners; self-hosted runners must provide `gh` on `PATH`.
300
+
301
+ For security-sensitive workflows, pin CukeDedup to the release tag's complete commit SHA. Exit codes retain the CLI contract; use `continue-on-error` only when a later workflow step intentionally evaluates the `exit-code` output.
302
+
303
+ ## Incremental CI adoption
304
+
305
+ Only report findings involving files changed from a Git revision while still comparing those files against the complete definition corpus. Paths remain correct when analyzing a repository subdirectory, and untracked files are included:
306
+
307
+ ```sh
308
+ cuke-dedup . --changed-since origin/main
309
+ ```
310
+
311
+ Create or refresh a compact semantic baseline from the complete current analysis:
312
+
313
+ ```sh
314
+ cuke-dedup . \
315
+ --baseline .cuke-dedup-baseline.json \
316
+ --update-baseline
317
+ ```
318
+
319
+ Subsequent runs suppress the recorded multiplicity of each semantic finding. File renames and unrelated line shifts do not make a finding new, while adding another occurrence beyond the recorded count does:
320
+
321
+ ```sh
322
+ cuke-dedup . --baseline .cuke-dedup-baseline.json --fail-on-new
323
+ cuke-dedup . --baseline .cuke-dedup-baseline.json --fail-on-new 3
324
+ ```
325
+
326
+ `--fail-on-new` defaults to zero when no count is supplied. `--update-baseline` and `--fail-on-new` require `--baseline`; they cannot be combined. Baseline updates also reject `--changed-since`, preventing a partial scan from erasing accepted findings outside the changed-file set. The sorted, versioned baseline records one semantic fingerprint per line with a multiplicity count for reviewable diffs.
327
+
328
+ Changed-file mode still analyzes the complete discovered corpus so a changed definition can be compared with unchanged definitions. It filters the reported findings to those touching a changed file, while summary definition counts and the duplication-threshold denominator remain the complete corpus.
329
+
330
+ An empty changed-file set emits a warning so an ignored target cannot look indistinguishable from a clean incremental run. Parse errors in unchanged files do not fail changed-file mode.
331
+
332
+ ## Exit codes
333
+
334
+ | Code | Meaning |
335
+ | --- | --- |
336
+ | `0` | The duplication rate is within the threshold and no independent error rule failed. |
337
+ | `1` | The duplication threshold was exceeded, an active non-duplication error rule failed, or the configured new-finding allowance was exceeded. |
338
+ | `2` | Discovery, parsing, configuration, or another operational failure. |
339
+
340
+ Warnings do not produce exit code `1`.
341
+
342
+ ## Compatibility and limitations
343
+
344
+ - The minimum supported Rust version is 1.90. Node.js 20 and 24 are tested for the npm launcher.
345
+ - Source adapters currently cover JavaScript and TypeScript, including JSX and common module variants. Unsupported languages are rejected rather than guessed.
346
+ - CukeDedup uses static analysis and never executes framework configuration or test code. Dynamic configuration may require explicit `features` or `definitions` patterns.
347
+ - Named handlers declared in the same source file are resolved to their bodies. Imported or unresolved handler references remain available for matcher and usage rules but are not compared by identifier text.
348
+ - Malformed JavaScript or TypeScript fails closed. Unsupported regular-expression constructs emit a warning; malformed matcher escapes are operational errors.
349
+ - One analysis root is one comparison corpus. Run independent monorepo packages separately when their step registries are unrelated.
350
+ - Exact matcher and handler equivalence groups produce a linear spanning set of findings. Fuzzy structural comparisons are bounded at two million candidates and fail closed with exit code `2`; split independent suites or narrow the root if that limit is reached.
351
+ - Before version 1.0, configuration and machine-report schemas may evolve between minor releases. Schema changes will be explicit and versioned.
352
+
353
+ CukeDedup is an independent project. It is not affiliated with or endorsed by the Cucumber project or its maintainers.
354
+
355
+ ## Support
356
+
357
+ Use the repository issue templates for reproducible bugs and focused feature requests. Include a minimal sanitized fixture and remove application-specific names, credentials, and source code. Report vulnerabilities privately according to [SECURITY.md](SECURITY.md).
358
+
359
+ ## Development
360
+
361
+ The minimum supported Rust version is 1.90. The repository pins and tests that toolchain and also runs its quality checks on current stable Rust.
362
+
363
+ Enable the tracked pre-commit hook once per clone and run the same compliance gate directly when needed:
364
+
365
+ ```sh
366
+ git config core.hooksPath .githooks
367
+ scripts/check/check.sh
368
+ ```
369
+
370
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for prerequisites, focused commands, corpus and benchmark guidance, pull-request expectations, and the project decision process. Public Rust items carry rustdoc, and CI treats missing API documentation as an error.
371
+
372
+ ## Releases and verification
373
+
374
+ Release notes and native archives are published on [GitHub Releases](https://github.com/figueiredoluiz/cuke-dedup/releases). Each archive has an adjacent SHA-256 checksum, a keyless Sigstore bundle, and GitHub build provenance. Verify provenance with:
375
+
376
+ ```sh
377
+ gh attestation verify <archive> \
378
+ --repo figueiredoluiz/cuke-dedup \
379
+ --signer-workflow figueiredoluiz/cuke-dedup/.github/workflows/release.yml
380
+ ```
381
+
382
+ Cargo, npm, the Git tag, and the GitHub release use the same version. See [CHANGELOG.md](CHANGELOG.md) for release history and [THIRD-PARTY-LICENSES.md](THIRD-PARTY-LICENSES.md) for the runtime dependency license inventory.
383
+
384
+ ## License
385
+
386
+ [MIT](LICENSE)
package/SECURITY.md ADDED
@@ -0,0 +1,42 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes are released for the latest published minor version. Before the first
6
+ stable release, only the latest `0.x` release is supported.
7
+
8
+ | Version | Supported |
9
+ | --- | --- |
10
+ | 0.1.x | Yes |
11
+ | Older versions | No |
12
+
13
+ ## Reporting a vulnerability
14
+
15
+ Please do not open a public issue for a suspected vulnerability. Use
16
+ [GitHub private vulnerability reporting](https://github.com/figueiredoluiz/cuke-dedup/security/advisories/new)
17
+ to send a private report with the affected version, impact, reproduction steps, and
18
+ any suggested mitigation. Remove credentials, proprietary source code, and unrelated
19
+ personal data from the report.
20
+
21
+ You should receive an acknowledgement within seven days. The maintainer will validate
22
+ the report, coordinate a fix and disclosure with the reporter, and publish an advisory
23
+ when users can take action. Please allow a reasonable remediation period before public
24
+ disclosure.
25
+
26
+ ## Security boundaries
27
+
28
+ CukeDedup treats analyzed repositories as untrusted input. It parses source and
29
+ configuration files without executing project code. Terminal and machine-readable
30
+ report content may contain attacker-controlled text from the analyzed repository and
31
+ must not be treated as commands or agent instructions.
32
+
33
+ The GitHub Action downloads native binaries only from this repository's versioned
34
+ releases and verifies their published checksum and archive structure before execution.
35
+ Consumers should pin the Action to a complete commit SHA.
36
+
37
+ ## Compromised releases
38
+
39
+ Published Cargo and npm versions and GitHub release assets are immutable. If a release
40
+ is compromised, the maintainer will publish a GitHub security advisory, deprecate the
41
+ affected npm version, yank the affected Cargo version when appropriate, and issue a
42
+ new patched version. Existing assets or version tags will not be silently replaced.
@@ -0,0 +1,98 @@
1
+ # Third-party licenses
2
+
3
+ CukeDedup's native binary contains the following non-development Rust dependencies.
4
+ The declared SPDX expressions and upstream locations are generated from the locked
5
+ Cargo dependency graph. Each dependency remains copyright its respective authors and
6
+ is distributed under its declared license terms.
7
+
8
+ The complete corresponding source and license files are available from the linked
9
+ upstream projects and from each crate's source package on crates.io. This inventory is
10
+ regenerated whenever `Cargo.lock` changes.
11
+
12
+ | Package | Version | Declared license | Authors | Upstream |
13
+ | --- | --- | --- | --- | --- |
14
+ | aho-corasick | 1.1.5 | Unlicense OR MIT | Andrew Gallant <jamslam@gmail.com> | https://github.com/BurntSushi/aho-corasick |
15
+ | anstream | 1.0.0 | MIT OR Apache-2.0 | Not declared | https://github.com/rust-cli/anstyle.git |
16
+ | anstyle | 1.0.14 | MIT OR Apache-2.0 | Not declared | https://github.com/rust-cli/anstyle.git |
17
+ | anstyle-parse | 1.0.0 | MIT OR Apache-2.0 | Not declared | https://github.com/rust-cli/anstyle.git |
18
+ | anstyle-query | 1.1.5 | MIT OR Apache-2.0 | Not declared | https://github.com/rust-cli/anstyle.git |
19
+ | anstyle-wincon | 3.0.11 | MIT OR Apache-2.0 | Not declared | https://github.com/rust-cli/anstyle.git |
20
+ | anyhow | 1.0.104 | MIT OR Apache-2.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/anyhow |
21
+ | bstr | 1.13.1 | MIT OR Apache-2.0 | Andrew Gallant <jamslam@gmail.com> | https://github.com/BurntSushi/bstr |
22
+ | bytecount | 0.6.9 | Apache-2.0/MIT | Andre Bogus <bogusandre@gmail.de>, Joshua Landau <joshua@landau.ws> | https://github.com/llogiq/bytecount |
23
+ | cc | 1.4.4 | MIT OR Apache-2.0 | Not declared | https://github.com/rust-lang/cc-rs |
24
+ | clap | 4.6.6 | MIT OR Apache-2.0 | Not declared | https://github.com/clap-rs/clap |
25
+ | clap_builder | 4.6.6 | MIT OR Apache-2.0 | Not declared | https://github.com/clap-rs/clap |
26
+ | clap_derive | 4.6.4 | MIT OR Apache-2.0 | Not declared | https://github.com/clap-rs/clap |
27
+ | clap_lex | 1.1.0 | MIT OR Apache-2.0 | Not declared | https://github.com/clap-rs/clap |
28
+ | colorchoice | 1.0.5 | MIT OR Apache-2.0 | Not declared | https://github.com/rust-cli/anstyle.git |
29
+ | convert_case | 0.10.0 | MIT | rutrum <dave@rutrum.net> | https://github.com/rutrum/convert-case |
30
+ | crossbeam-deque | 0.8.7 | MIT OR Apache-2.0 | Not declared | https://github.com/crossbeam-rs/crossbeam |
31
+ | crossbeam-epoch | 0.9.20 | MIT OR Apache-2.0 | Not declared | https://github.com/crossbeam-rs/crossbeam |
32
+ | crossbeam-utils | 0.8.22 | MIT OR Apache-2.0 | Not declared | https://github.com/crossbeam-rs/crossbeam |
33
+ | cucumber-expressions | 0.5.0 | MIT OR Apache-2.0 | Ilya Solovyiov <ilya.solovyiov@gmail.com>, Kai Ren <tyranron@gmail.com> | https://github.com/cucumber-rs/cucumber-expressions |
34
+ | derive_more | 2.1.1 | MIT | Jelte Fennema <github-tech@jeltef.nl> | https://github.com/JelteF/derive_more |
35
+ | derive_more-impl | 2.1.1 | MIT | Jelte Fennema <github-tech@jeltef.nl> | https://github.com/JelteF/derive_more |
36
+ | either | 1.18.0 | MIT OR Apache-2.0 | Not declared | https://github.com/rayon-rs/either |
37
+ | equivalent | 1.0.2 | Apache-2.0 OR MIT | Not declared | https://github.com/indexmap-rs/equivalent |
38
+ | find-msvc-tools | 0.1.11 | MIT OR Apache-2.0 | Not declared | https://github.com/rust-lang/cc-rs |
39
+ | gherkin | 0.16.0 | MIT OR Apache-2.0 | Brendan Molloy <brendan@bbqsrc.net> | https://github.com/cucumber-rs/gherkin |
40
+ | globset | 0.4.20 | Unlicense OR MIT | Andrew Gallant <jamslam@gmail.com> | https://github.com/BurntSushi/ripgrep/tree/master/crates/globset |
41
+ | hashbrown | 0.17.1 | MIT OR Apache-2.0 | Not declared | https://github.com/rust-lang/hashbrown |
42
+ | heck | 0.5.0 | MIT OR Apache-2.0 | Not declared | https://github.com/withoutboats/heck |
43
+ | ignore | 0.4.33 | Unlicense OR MIT | Andrew Gallant <jamslam@gmail.com> | https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore |
44
+ | indexmap | 2.14.1 | Apache-2.0 OR MIT | Not declared | https://github.com/indexmap-rs/indexmap |
45
+ | is_terminal_polyfill | 1.70.2 | MIT OR Apache-2.0 | Not declared | https://github.com/polyfill-rs/is_terminal_polyfill |
46
+ | itoa | 1.0.18 | MIT OR Apache-2.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/itoa |
47
+ | libyaml-rs | 0.3.0 | MIT | David Tolnay <dtolnay@gmail.com>, YAML Organization <noreply@yaml.org> | https://github.com/yaml/libyaml-rs |
48
+ | log | 0.4.34 | MIT OR Apache-2.0 | The Rust Project Developers | https://github.com/rust-lang/log |
49
+ | memchr | 2.8.3 | Unlicense OR MIT | Andrew Gallant <jamslam@gmail.com>, bluss | https://github.com/BurntSushi/memchr |
50
+ | nom | 8.0.0 | MIT | contact@geoffroycouprie.com | https://github.com/rust-bakery/nom |
51
+ | nom_locate | 5.0.0 | MIT | Florent FAYOLLE <florent.fayolle69@gmail.com>, Christopher Durham <cad97@cad97.com>, Valentin Lorentz <progval+git@progval.net> | https://github.com/fflorent/nom_locate |
52
+ | once_cell_polyfill | 1.70.2 | MIT OR Apache-2.0 | Not declared | https://github.com/polyfill-rs/once_cell_polyfill |
53
+ | peg | 0.6.3 | MIT | Kevin Mehall <km@kevinmehall.net> | https://github.com/kevinmehall/rust-peg |
54
+ | peg-macros | 0.6.3 | MIT | Kevin Mehall <km@kevinmehall.net> | https://github.com/kevinmehall/rust-peg |
55
+ | peg-runtime | 0.6.3 | MIT | Kevin Mehall <km@kevinmehall.net> | https://github.com/kevinmehall/rust-peg |
56
+ | proc-macro2 | 1.0.107 | MIT OR Apache-2.0 | David Tolnay <dtolnay@gmail.com>, Alex Crichton <alex@alexcrichton.com> | https://github.com/dtolnay/proc-macro2 |
57
+ | quote | 1.0.47 | MIT OR Apache-2.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/quote |
58
+ | regex | 1.13.1 | MIT OR Apache-2.0 | The Rust Project Developers, Andrew Gallant <jamslam@gmail.com> | https://github.com/rust-lang/regex |
59
+ | regex-automata | 0.4.18 | MIT OR Apache-2.0 | The Rust Project Developers, Andrew Gallant <jamslam@gmail.com> | https://github.com/rust-lang/regex |
60
+ | regex-syntax | 0.8.11 | MIT OR Apache-2.0 | The Rust Project Developers, Andrew Gallant <jamslam@gmail.com> | https://github.com/rust-lang/regex |
61
+ | rustc_version | 0.4.1 | MIT OR Apache-2.0 | Not declared | https://github.com/djc/rustc-version-rs |
62
+ | ryu | 1.0.23 | Apache-2.0 OR BSL-1.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/ryu |
63
+ | same-file | 1.0.6 | Unlicense/MIT | Andrew Gallant <jamslam@gmail.com> | https://github.com/BurntSushi/same-file |
64
+ | semver | 1.0.28 | MIT OR Apache-2.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/semver |
65
+ | serde | 1.0.229 | MIT OR Apache-2.0 | Erick Tryzelaar <erick.tryzelaar@gmail.com>, David Tolnay <dtolnay@gmail.com> | https://github.com/serde-rs/serde |
66
+ | serde_core | 1.0.229 | MIT OR Apache-2.0 | Erick Tryzelaar <erick.tryzelaar@gmail.com>, David Tolnay <dtolnay@gmail.com> | https://github.com/serde-rs/serde |
67
+ | serde_derive | 1.0.229 | MIT OR Apache-2.0 | Erick Tryzelaar <erick.tryzelaar@gmail.com>, David Tolnay <dtolnay@gmail.com> | https://github.com/serde-rs/serde |
68
+ | serde_json | 1.0.151 | MIT OR Apache-2.0 | Erick Tryzelaar <erick.tryzelaar@gmail.com>, David Tolnay <dtolnay@gmail.com> | https://github.com/serde-rs/json |
69
+ | shlex | 2.0.1 | MIT OR Apache-2.0 | comex <comexk@gmail.com>, Fenhl <fenhl@fenhl.net>, Adrian Taylor <adetaylor@chromium.org>, Alex Touchet <alextouchet@outlook.com>, Daniel Parks <dp+git@oxidized.org>, Garrett Berg <googberg@gmail.com> | https://github.com/comex/rust-shlex |
70
+ | smawk | 0.3.3 | MIT | Martin Geisler <martin@geisler.net> | https://github.com/mgeisler/smawk |
71
+ | streaming-iterator | 0.1.9 | MIT OR Apache-2.0 | Steven Fackler <sfackler@gmail.com> | https://github.com/sfackler/streaming-iterator |
72
+ | strsim | 0.11.1 | MIT | Danny Guo <danny@dannyguo.com>, maxbachmann <oss@maxbachmann.de> | https://github.com/rapidfuzz/strsim-rs |
73
+ | syn | 2.0.119 | MIT OR Apache-2.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/syn |
74
+ | syn | 3.0.4 | MIT OR Apache-2.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/syn |
75
+ | textwrap | 0.16.2 | MIT | Martin Geisler <martin@geisler.net> | https://github.com/mgeisler/textwrap |
76
+ | thiserror | 2.0.20 | MIT OR Apache-2.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/thiserror |
77
+ | thiserror-impl | 2.0.20 | MIT OR Apache-2.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/thiserror |
78
+ | tinyvec | 1.12.0 | Zlib OR Apache-2.0 OR MIT | Lokathor <zefria@gmail.com> | https://github.com/Lokathor/tinyvec |
79
+ | tinyvec_macros | 0.1.1 | MIT OR Apache-2.0 OR Zlib | Soveu <marx.tomasz@gmail.com> | https://github.com/Soveu/tinyvec_macros |
80
+ | tree-sitter | 0.26.13 | MIT | Max Brunsfeld <maxbrunsfeld@gmail.com>, Amaan Qureshi <amaanq12@gmail.com> | https://github.com/tree-sitter/tree-sitter |
81
+ | tree-sitter-javascript | 0.25.0 | MIT | Max Brunsfeld <maxbrunsfeld@gmail.com>, Amaan Qureshi <amaanq12@gmail.com> | https://github.com/tree-sitter/tree-sitter-javascript |
82
+ | tree-sitter-language | 0.1.8 | MIT | Max Brunsfeld <maxbrunsfeld@gmail.com>, Amaan Qureshi <amaanq12@gmail.com> | https://github.com/tree-sitter/tree-sitter |
83
+ | tree-sitter-typescript | 0.23.2 | MIT | Max Brunsfeld <maxbrunsfeld@gmail.com>, Amaan Qureshi <amaanq12@gmail.com> | https://github.com/tree-sitter/tree-sitter-typescript |
84
+ | typed-builder | 0.23.2 | MIT OR Apache-2.0 | IdanArye <idanarye@gmail.com>, Chris Morgan <me@chrismorgan.info> | https://github.com/idanarye/rust-typed-builder |
85
+ | typed-builder-macro | 0.23.2 | MIT OR Apache-2.0 | IdanArye <idanarye@gmail.com>, Chris Morgan <me@chrismorgan.info> | https://github.com/idanarye/rust-typed-builder |
86
+ | unicode-ident | 1.0.24 | (MIT OR Apache-2.0) AND Unicode-3.0 | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/unicode-ident |
87
+ | unicode-linebreak | 0.1.5 | Apache-2.0 | Axel Forsman <axelsfor@gmail.com> | https://github.com/axelf4/unicode-linebreak |
88
+ | unicode-normalization | 0.1.25 | MIT OR Apache-2.0 | kwantam <kwantam@gmail.com>, Manish Goregaokar <manishsmail@gmail.com> | https://github.com/unicode-rs/unicode-normalization |
89
+ | unicode-segmentation | 1.13.3 | MIT OR Apache-2.0 | kwantam <kwantam@gmail.com>, Manish Goregaokar <manishsmail@gmail.com> | https://github.com/unicode-rs/unicode-segmentation |
90
+ | unicode-width | 0.2.2 | MIT OR Apache-2.0 | kwantam <kwantam@gmail.com>, Manish Goregaokar <manishsmail@gmail.com> | https://github.com/unicode-rs/unicode-width |
91
+ | unicode-xid | 0.2.6 | MIT OR Apache-2.0 | erick.tryzelaar <erick.tryzelaar@gmail.com>, kwantam <kwantam@gmail.com>, Manish Goregaokar <manishsmail@gmail.com> | https://github.com/unicode-rs/unicode-xid |
92
+ | utf8parse | 0.2.2 | Apache-2.0 OR MIT | Joe Wilm <joe@jwilm.com>, Christian Duerr <contact@christianduerr.com> | https://github.com/alacritty/vte |
93
+ | walkdir | 2.5.0 | Unlicense/MIT | Andrew Gallant <jamslam@gmail.com> | https://github.com/BurntSushi/walkdir |
94
+ | winapi-util | 0.1.11 | Unlicense OR MIT | Andrew Gallant <jamslam@gmail.com> | https://github.com/BurntSushi/winapi-util |
95
+ | windows-link | 0.2.1 | MIT OR Apache-2.0 | Not declared | https://github.com/microsoft/windows-rs |
96
+ | windows-sys | 0.61.2 | MIT OR Apache-2.0 | Not declared | https://github.com/microsoft/windows-rs |
97
+ | yaml_serde | 0.10.7 | MIT OR Apache-2.0 | YAML Organization <noreply@yaml.org> | https://github.com/yaml/yaml-serde |
98
+ | zmij | 1.0.23 | MIT | David Tolnay <dtolnay@gmail.com> | https://github.com/dtolnay/zmij |
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { run } from "../lib/launcher.mjs";
4
+
5
+ process.exitCode = run(process.argv.slice(2));
@@ -0,0 +1,107 @@
1
+ import { accessSync, constants, existsSync, readFileSync } from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, resolve } from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ import { constants as osConstants } from "node:os";
6
+
7
+ const require = createRequire(import.meta.url);
8
+
9
+ const targetManifest = JSON.parse(
10
+ readFileSync(new URL("../prebuilt-targets.json", import.meta.url), "utf8"),
11
+ );
12
+
13
+ export const TARGETS = Object.freeze(targetManifest.targets);
14
+
15
+ export function detectLibc(report = process.report) {
16
+ try {
17
+ return report?.getReport()?.header?.glibcVersionRuntime ? "gnu" : "musl";
18
+ } catch {
19
+ return "musl";
20
+ }
21
+ }
22
+
23
+ export function targetFor(
24
+ platform = process.platform,
25
+ arch = process.arch,
26
+ libc = platform === "linux" ? detectLibc() : undefined,
27
+ ) {
28
+ const key = platform === "linux" ? `${platform}-${arch}-${libc}` : `${platform}-${arch}`;
29
+ const target = TARGETS[key];
30
+ if (!target) {
31
+ throw new Error(
32
+ `unsupported platform ${key}; supported platforms: ${Object.keys(TARGETS).join(", ")}`,
33
+ );
34
+ }
35
+ return target;
36
+ }
37
+
38
+ export function resolveBinary({
39
+ platform = process.platform,
40
+ arch = process.arch,
41
+ libc = platform === "linux" ? detectLibc() : undefined,
42
+ override = process.env.CUKE_DEDUP_BINARY,
43
+ resolvePackage = require.resolve,
44
+ } = {}) {
45
+ if (override) {
46
+ const binary = resolve(override);
47
+ assertUsableBinary(binary, platform);
48
+ return binary;
49
+ }
50
+
51
+ const target = targetFor(platform, arch, libc);
52
+ let manifest;
53
+ try {
54
+ manifest = resolvePackage(`${target.packageName}/package.json`);
55
+ } catch (error) {
56
+ throw new Error(
57
+ `native package ${target.packageName} is missing; reinstall cuke-dedup with optional dependencies enabled`,
58
+ { cause: error },
59
+ );
60
+ }
61
+ const binary = resolve(dirname(manifest), "bin", target.binaryName);
62
+ assertUsableBinary(binary, platform);
63
+ return binary;
64
+ }
65
+
66
+ function assertUsableBinary(binary, platform) {
67
+ if (!existsSync(binary)) {
68
+ throw new Error(`cuke-dedup binary was not found at ${binary}`);
69
+ }
70
+ if (platform !== "win32") {
71
+ try {
72
+ accessSync(binary, constants.X_OK);
73
+ } catch (error) {
74
+ throw new Error(`cuke-dedup binary is not executable at ${binary}`, {
75
+ cause: error,
76
+ });
77
+ }
78
+ }
79
+ }
80
+
81
+ export function run(
82
+ args,
83
+ {
84
+ binary = undefined,
85
+ spawn = spawnSync,
86
+ stderr = process.stderr,
87
+ } = {},
88
+ ) {
89
+ let resolvedBinary;
90
+ try {
91
+ resolvedBinary = binary ?? resolveBinary();
92
+ } catch (error) {
93
+ stderr.write(`cuke-dedup: ${error.message}\n`);
94
+ return 2;
95
+ }
96
+
97
+ const result = spawn(resolvedBinary, args, { stdio: "inherit" });
98
+ if (result.error) {
99
+ stderr.write(`cuke-dedup: failed to start ${resolvedBinary}: ${result.error.message}\n`);
100
+ return 2;
101
+ }
102
+ if (result.signal) {
103
+ stderr.write(`cuke-dedup: native process terminated by ${result.signal}\n`);
104
+ return 128 + (osConstants.signals[result.signal] ?? 0);
105
+ }
106
+ return result.status ?? 2;
107
+ }
@@ -0,0 +1,81 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "targets": {
4
+ "darwin-arm64": {
5
+ "rustTarget": "aarch64-apple-darwin",
6
+ "packageName": "cuke-dedup-darwin-arm64",
7
+ "packageDirectory": "darwin-arm64",
8
+ "platform": "darwin",
9
+ "arch": "arm64",
10
+ "runner": "macos-15",
11
+ "binaryName": "cuke-dedup"
12
+ },
13
+ "darwin-x64": {
14
+ "rustTarget": "x86_64-apple-darwin",
15
+ "packageName": "cuke-dedup-darwin-x64",
16
+ "packageDirectory": "darwin-x64",
17
+ "platform": "darwin",
18
+ "arch": "x64",
19
+ "runner": "macos-15-intel",
20
+ "binaryName": "cuke-dedup"
21
+ },
22
+ "linux-arm64-gnu": {
23
+ "rustTarget": "aarch64-unknown-linux-gnu",
24
+ "packageName": "cuke-dedup-linux-arm64-gnu",
25
+ "packageDirectory": "linux-arm64-gnu",
26
+ "platform": "linux",
27
+ "arch": "arm64",
28
+ "libc": "gnu",
29
+ "runner": "ubuntu-22.04-arm",
30
+ "binaryName": "cuke-dedup"
31
+ },
32
+ "linux-arm64-musl": {
33
+ "rustTarget": "aarch64-unknown-linux-musl",
34
+ "packageName": "cuke-dedup-linux-arm64-musl",
35
+ "packageDirectory": "linux-arm64-musl",
36
+ "platform": "linux",
37
+ "arch": "arm64",
38
+ "libc": "musl",
39
+ "runner": "ubuntu-22.04-arm",
40
+ "binaryName": "cuke-dedup"
41
+ },
42
+ "linux-x64-gnu": {
43
+ "rustTarget": "x86_64-unknown-linux-gnu",
44
+ "packageName": "cuke-dedup-linux-x64-gnu",
45
+ "packageDirectory": "linux-x64-gnu",
46
+ "platform": "linux",
47
+ "arch": "x64",
48
+ "libc": "gnu",
49
+ "runner": "ubuntu-22.04",
50
+ "binaryName": "cuke-dedup"
51
+ },
52
+ "linux-x64-musl": {
53
+ "rustTarget": "x86_64-unknown-linux-musl",
54
+ "packageName": "cuke-dedup-linux-x64-musl",
55
+ "packageDirectory": "linux-x64-musl",
56
+ "platform": "linux",
57
+ "arch": "x64",
58
+ "libc": "musl",
59
+ "runner": "ubuntu-22.04",
60
+ "binaryName": "cuke-dedup"
61
+ },
62
+ "win32-arm64": {
63
+ "rustTarget": "aarch64-pc-windows-msvc",
64
+ "packageName": "cuke-dedup-win32-arm64",
65
+ "packageDirectory": "win32-arm64",
66
+ "platform": "win32",
67
+ "arch": "arm64",
68
+ "runner": "windows-11-arm",
69
+ "binaryName": "cuke-dedup.exe"
70
+ },
71
+ "win32-x64": {
72
+ "rustTarget": "x86_64-pc-windows-msvc",
73
+ "packageName": "cuke-dedup-win32-x64",
74
+ "packageDirectory": "win32-x64",
75
+ "platform": "win32",
76
+ "arch": "x64",
77
+ "runner": "windows-latest",
78
+ "binaryName": "cuke-dedup.exe"
79
+ }
80
+ }
81
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "cuke-dedup",
3
+ "version": "0.1.0",
4
+ "description": "Static analysis for duplicate and reusable Cucumber step definitions",
5
+ "type": "module",
6
+ "bin": {
7
+ "cuke-dedup": "npm/bin/cuke-dedup.js"
8
+ },
9
+ "files": [
10
+ "npm/bin/",
11
+ "npm/lib/",
12
+ "npm/prebuilt-targets.json",
13
+ "README.md",
14
+ "LICENSE",
15
+ "CHANGELOG.md",
16
+ "SECURITY.md",
17
+ "THIRD-PARTY-LICENSES.md"
18
+ ],
19
+ "scripts": {
20
+ "test": "node --test npm/test/*.test.mjs",
21
+ "skills:check": "node scripts/check/check-agent-skills.mjs",
22
+ "check:versions": "node scripts/check/check-release-version.mjs",
23
+ "pack:check": "npm pack --dry-run",
24
+ "corpus:check": "node scripts/check/check-corpus.mjs",
25
+ "benchmark": "node scripts/benchmark/benchmark-analysis.mjs"
26
+ },
27
+ "engines": {
28
+ "node": ">=20"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/figueiredoluiz/cuke-dedup.git"
33
+ },
34
+ "homepage": "https://github.com/figueiredoluiz/cuke-dedup",
35
+ "bugs": "https://github.com/figueiredoluiz/cuke-dedup/issues",
36
+ "license": "MIT",
37
+ "keywords": [
38
+ "cucumber",
39
+ "gherkin",
40
+ "lint",
41
+ "testing",
42
+ "cli"
43
+ ],
44
+ "workspaces": [
45
+ "npm/platforms/*"
46
+ ],
47
+ "optionalDependencies": {
48
+ "cuke-dedup-darwin-arm64": "0.1.0",
49
+ "cuke-dedup-darwin-x64": "0.1.0",
50
+ "cuke-dedup-linux-arm64-gnu": "0.1.0",
51
+ "cuke-dedup-linux-arm64-musl": "0.1.0",
52
+ "cuke-dedup-linux-x64-gnu": "0.1.0",
53
+ "cuke-dedup-linux-x64-musl": "0.1.0",
54
+ "cuke-dedup-win32-arm64": "0.1.0",
55
+ "cuke-dedup-win32-x64": "0.1.0"
56
+ }
57
+ }