Make jscpd actually scan, and tighten its threshold to 3%
.jscpd.json set pattern to an array, but jscpd's --pattern takes a single
glob string. An array matches nothing, so the gate had reported success
without reading a file since 2793a66 introduced it — its 0.074ms
"detection time" and absent stats table were the tell. Bisecting the
config confirmed that key alone reduces the run to zero files.
The ignore entries were also bare names rather than globs, so once the
pattern worked it swept apps/web/dist and .pnpm-store — 948 files.
Excludes __tests__, matching what .jsinspectrc already does. Duplication
between test cases is usually deliberate: parallel arrange/act/assert
blocks read better than shared setup, and the factories under
apps/web/src/__tests__/factories cover the deduplication worth having.
Real duplication is 1.72% across 209 source files, so the threshold drops
from 5% to 3%. jscpd measures a ratio rather than blocking each new clone,
and a 5% budget left roughly 3x headroom before it would ever fire.
Gives jscpd explicit paths behind `pnpm jscpd`, so lefthook and the check
script share one invocation, as jsinspect already does.
Also guards the pattern key in check-gates.mjs, since an array there fails
silently rather than erroring.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+9
-3
@@ -1,8 +1,14 @@
|
||||
{
|
||||
"threshold": 5,
|
||||
"threshold": 3,
|
||||
"minLines": 5,
|
||||
"minTokens": 50,
|
||||
"pattern": ["**/*.ts", "**/*.tsx"],
|
||||
"ignore": ["node_modules", "dist", "build", "coverage", ".specify", "specs"],
|
||||
"pattern": "**/*.{ts,tsx}",
|
||||
"ignore": [
|
||||
"**/node_modules/**",
|
||||
"**/dist/**",
|
||||
"**/build/**",
|
||||
"**/coverage/**",
|
||||
"**/__tests__/**"
|
||||
],
|
||||
"reporters": ["console"]
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ pre-commit:
|
||||
- name: check-props
|
||||
run: node scripts/check-component-props.mjs
|
||||
- name: jscpd
|
||||
run: pnpm exec jscpd
|
||||
run: pnpm jscpd
|
||||
- name: jsinspect
|
||||
run: pnpm jsinspect
|
||||
- name: typecheck-oxlint-test
|
||||
|
||||
+2
-2
@@ -23,12 +23,12 @@
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"knip": "knip",
|
||||
"jscpd": "jscpd",
|
||||
"jscpd": "jscpd apps/web/src packages/domain/src packages/application/src",
|
||||
"jsinspect": "jsinspect -c .jsinspectrc apps/web/src packages/domain/src packages/application/src",
|
||||
"oxlint": "oxlint --tsconfig tsconfig.json --type-aware --deny-warnings",
|
||||
"check:ignores": "node scripts/check-lint-ignores.mjs",
|
||||
"check:classnames": "node scripts/check-cn-classnames.mjs",
|
||||
"check:props": "node scripts/check-component-props.mjs",
|
||||
"check": "pnpm audit --audit-level=high && knip && biome check . && node scripts/check-lint-ignores.mjs && node scripts/check-cn-classnames.mjs && node scripts/check-component-props.mjs && jscpd && pnpm jsinspect && tsc --build && pnpm oxlint && vitest run"
|
||||
"check": "pnpm audit --audit-level=high && knip && biome check . && node scripts/check-lint-ignores.mjs && node scripts/check-cn-classnames.mjs && node scripts/check-component-props.mjs && pnpm jscpd && pnpm jsinspect && tsc --build && pnpm oxlint && vitest run"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,12 @@ export function checkGates() {
|
||||
violations.push("vitest.config.ts sets passWithNoTests");
|
||||
}
|
||||
|
||||
// jscpd's pattern is a single glob string. An array matches no files, and
|
||||
// the run then reports success having read nothing.
|
||||
if (Array.isArray(JSON.parse(read(".jscpd.json")).pattern)) {
|
||||
violations.push(".jscpd.json sets pattern to an array, not a glob string");
|
||||
}
|
||||
|
||||
// The canary rule below is not type-aware, so the probe alone cannot
|
||||
// detect type-aware rules being switched off.
|
||||
if (!scripts.oxlint.includes("--type-aware")) {
|
||||
|
||||
Reference in New Issue
Block a user