@poleski/quality-tools 0.1.3
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 +13 -0
- package/LICENSE +21 -0
- package/README.md +269 -0
- package/dist/cli/main.js +4826 -0
- package/package.json +62 -0
- package/stryker/quality-tools-vitest-runner.mjs +83 -0
- package/stryker.config.cjs +65 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @poleski/quality-tools
|
|
2
|
+
|
|
3
|
+
## 0.1.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c0b6623: Generalize CRAP coverage config, report output, workspace discovery, and mutation Stryker integration for non-CodeGraphy projects.
|
|
8
|
+
|
|
9
|
+
## 0.1.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Extract the quality tools into a standalone package repo.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Joe Soboleski
|
|
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,269 @@
|
|
|
1
|
+
# @poleski/quality-tools
|
|
2
|
+
|
|
3
|
+
Portable TypeScript quality checks for project structure, complexity,
|
|
4
|
+
reachability, mutation, and test health.
|
|
5
|
+
|
|
6
|
+
The tools are intentionally project-agnostic. They discover packages from
|
|
7
|
+
`pnpm-workspace.yaml` or `package.json#workspaces`, accept explicit file/folder
|
|
8
|
+
targets, and read project-specific behavior from `quality.config.json`.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pnpm add -D @poleski/quality-tools
|
|
14
|
+
pnpm exec quality-tools init
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Before publish, use a local link from a host project:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm add -D link:/absolute/path/to/quality-tools
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm exec quality-tools organize .
|
|
27
|
+
pnpm exec quality-tools boundaries . --strict
|
|
28
|
+
pnpm exec quality-tools reachability . --strict
|
|
29
|
+
pnpm exec quality-tools scrap ./tests
|
|
30
|
+
pnpm exec quality-tools crap ./src
|
|
31
|
+
pnpm exec quality-tools mutate .
|
|
32
|
+
pnpm exec quality-tools mutate ./src/parser.ts --force
|
|
33
|
+
pnpm exec quality-tools mutate -- --mutate ./src/parser.ts
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Targets can be the repo root, a package shorthand, a package root, a directory,
|
|
37
|
+
or a file. Package shorthand is resolved from workspace package names, not from
|
|
38
|
+
hardcoded folder names. The starter config uses `src` as a conventional default,
|
|
39
|
+
but the tools scope from the target path plus your configured include/exclude
|
|
40
|
+
globs.
|
|
41
|
+
|
|
42
|
+
## Reports
|
|
43
|
+
|
|
44
|
+
All quality-tool artifacts use one report root:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"reportsDir": "reports/quality-tools"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Current outputs:
|
|
53
|
+
|
|
54
|
+
- `reportsDir/organize/*.json` for organize baselines
|
|
55
|
+
- `reportsDir/scrap/*.json` for scrap baselines
|
|
56
|
+
- `reportsDir/crap/<target>/coverage-final.json` for CRAP coverage input
|
|
57
|
+
- `reportsDir/mutation/mutation.json` and `mutation.html` from Stryker
|
|
58
|
+
- `reportsDir/mutation/<target>/mutation.json` copied per mutation target
|
|
59
|
+
|
|
60
|
+
CRAP reads the coverage report path you configure. The starter Vitest command
|
|
61
|
+
writes that coverage under `reportsDir/crap/<target>/`.
|
|
62
|
+
|
|
63
|
+
## Config
|
|
64
|
+
|
|
65
|
+
Run `quality-tools init` to create a starter `quality.config.json`.
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"reportsDir": "reports/quality-tools",
|
|
70
|
+
"defaults": {
|
|
71
|
+
"crap": {
|
|
72
|
+
"coverage": {
|
|
73
|
+
"command": "pnpm",
|
|
74
|
+
"args": [
|
|
75
|
+
"exec",
|
|
76
|
+
"vitest",
|
|
77
|
+
"run",
|
|
78
|
+
"--coverage",
|
|
79
|
+
"--coverage.reportsDirectory",
|
|
80
|
+
"{repoRoot}/{reportsDir}/crap/{reportKey}"
|
|
81
|
+
],
|
|
82
|
+
"coveragePath": "{repoRoot}/{reportsDir}/crap/{reportKey}/coverage-final.json"
|
|
83
|
+
},
|
|
84
|
+
"exclude": ["**/*.test.ts", "**/*.test.tsx", "**/*.d.ts"]
|
|
85
|
+
},
|
|
86
|
+
"mutation": {
|
|
87
|
+
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
88
|
+
"exclude": ["src/**/*.d.ts"]
|
|
89
|
+
},
|
|
90
|
+
"scrap": {
|
|
91
|
+
"include": ["tests/**/*.test.ts", "tests/**/*.test.tsx"],
|
|
92
|
+
"exclude": []
|
|
93
|
+
},
|
|
94
|
+
"boundaries": {
|
|
95
|
+
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
96
|
+
"exclude": ["src/**/*.d.ts", "**/*.test.ts", "**/*.test.tsx"],
|
|
97
|
+
"entrypoints": [],
|
|
98
|
+
"layers": []
|
|
99
|
+
},
|
|
100
|
+
"organize": {
|
|
101
|
+
"lowInfoNames": {
|
|
102
|
+
"banned": ["utils", "helpers", "misc", "common", "shared", "_shared", "lib", "index"],
|
|
103
|
+
"discouraged": ["types", "constants", "config", "base", "core"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"packages": {}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Package-specific config lives under `packages.<packageName>`. The package name
|
|
112
|
+
is the unscoped manifest name by default, so `@scope/parser` is configured as
|
|
113
|
+
`parser`.
|
|
114
|
+
|
|
115
|
+
## CRAP
|
|
116
|
+
|
|
117
|
+
CRAP calculates complexity plus coverage risk and fails when a function exceeds
|
|
118
|
+
the threshold. The default threshold is `8`.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pnpm exec quality-tools crap ./src
|
|
122
|
+
pnpm exec quality-tools crap parser --threshold 10
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
CRAP needs Istanbul `coverage-final.json`. Configure the command and report path
|
|
126
|
+
for your project. Put generated coverage under `{reportsDir}` when possible so
|
|
127
|
+
all artifacts stay together:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"defaults": {
|
|
132
|
+
"crap": {
|
|
133
|
+
"coverage": {
|
|
134
|
+
"command": "pnpm",
|
|
135
|
+
"args": [
|
|
136
|
+
"exec",
|
|
137
|
+
"vitest",
|
|
138
|
+
"run",
|
|
139
|
+
"--coverage",
|
|
140
|
+
"--coverage.reportsDirectory",
|
|
141
|
+
"{repoRoot}/{reportsDir}/crap/{reportKey}"
|
|
142
|
+
],
|
|
143
|
+
"coveragePath": "{repoRoot}/{reportsDir}/crap/{reportKey}/coverage-final.json"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"packages": {
|
|
148
|
+
"parser": {
|
|
149
|
+
"crap": {
|
|
150
|
+
"coverage": {
|
|
151
|
+
"command": "pnpm",
|
|
152
|
+
"args": [
|
|
153
|
+
"--filter",
|
|
154
|
+
"{packageJsonName}",
|
|
155
|
+
"exec",
|
|
156
|
+
"vitest",
|
|
157
|
+
"run",
|
|
158
|
+
"--coverage",
|
|
159
|
+
"--coverage.reportsDirectory",
|
|
160
|
+
"{repoRoot}/{reportsDir}/crap/{reportKey}"
|
|
161
|
+
],
|
|
162
|
+
"coveragePath": "{repoRoot}/{reportsDir}/crap/{reportKey}/coverage-final.json"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Supported template values in CRAP coverage command fields:
|
|
171
|
+
|
|
172
|
+
- `{repoRoot}`
|
|
173
|
+
- `{packageRoot}`
|
|
174
|
+
- `{packageName}`
|
|
175
|
+
- `{packageJsonName}`
|
|
176
|
+
- `{reportKey}`
|
|
177
|
+
- `{target}` or `{targetPath}`
|
|
178
|
+
- `{reportsDir}`
|
|
179
|
+
|
|
180
|
+
## Mutation
|
|
181
|
+
|
|
182
|
+
Mutation runs Stryker against the selected source target. The CLI does not run
|
|
183
|
+
typecheck first and does not assume any package is special.
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
pnpm exec quality-tools mutate .
|
|
187
|
+
pnpm exec quality-tools mutate parser
|
|
188
|
+
pnpm exec quality-tools mutate ./src/parser.ts --force
|
|
189
|
+
pnpm exec quality-tools mutate -- --mutate ./src/parser.ts
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`mutate` requires an explicit target. Use `.` for a repo-wide run, a package
|
|
193
|
+
shorthand for a workspace package, or a file/folder path for a narrower run.
|
|
194
|
+
Bare `quality-tools mutate` is intentionally invalid so host projects can own
|
|
195
|
+
their own all-package wrappers. `--force` is passed through to Stryker when you
|
|
196
|
+
need to ignore incremental mutation state.
|
|
197
|
+
|
|
198
|
+
The CLI passes Stryker:
|
|
199
|
+
|
|
200
|
+
- the Stryker config path
|
|
201
|
+
- scoped mutate globs from `quality.config.json`
|
|
202
|
+
- an incremental file path under `reportsDir/mutation/<target>/`
|
|
203
|
+
- `QUALITY_TOOLS_REPORTS_DIR`, so the bundled base config writes to the shared
|
|
204
|
+
report root
|
|
205
|
+
|
|
206
|
+
Long mutation runs print a progress heartbeat once per minute. The bundled base
|
|
207
|
+
config also accepts these environment knobs:
|
|
208
|
+
|
|
209
|
+
- `QUALITY_TOOLS_STRYKER_CONCURRENCY`, default `2`
|
|
210
|
+
- `QUALITY_TOOLS_STRYKER_MAX_TEST_RUNNER_REUSE`, default `0`
|
|
211
|
+
|
|
212
|
+
Use a project Stryker config when you need custom Vitest wiring:
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
const base = require('@poleski/quality-tools/stryker.config.cjs');
|
|
216
|
+
|
|
217
|
+
module.exports = {
|
|
218
|
+
...base,
|
|
219
|
+
vitest: {
|
|
220
|
+
...base.vitest,
|
|
221
|
+
configFile: 'vitest.config.ts'
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Then reference it in `quality.config.json`:
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
{
|
|
230
|
+
"defaults": {
|
|
231
|
+
"mutation": {
|
|
232
|
+
"strykerConfig": "stryker.config.cjs",
|
|
233
|
+
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
234
|
+
"exclude": ["src/**/*.d.ts"]
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
If `strykerConfig` is omitted, the tool looks for `stryker.config.cjs`,
|
|
241
|
+
`stryker.config.mjs`, `stryker.config.js`, or `stryker.conf.js` in the repo
|
|
242
|
+
root, then falls back to the bundled base config.
|
|
243
|
+
|
|
244
|
+
## Other Tools
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
pnpm exec quality-tools organize ./src
|
|
248
|
+
pnpm exec quality-tools boundaries parser --strict
|
|
249
|
+
pnpm exec quality-tools reachability parser --strict
|
|
250
|
+
pnpm exec quality-tools scrap ./tests --strict
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
- `organize` checks directory size, depth, naming, barrels, and cohesion. Use
|
|
254
|
+
`--write-baseline` and `--compare <path>` for baseline workflows.
|
|
255
|
+
- `boundaries` checks configured layers, entrypoints, dead surfaces, and dead
|
|
256
|
+
ends.
|
|
257
|
+
- `reachability` reports dead surfaces and dead ends without boundary-layer
|
|
258
|
+
failures.
|
|
259
|
+
- `scrap` reviews test files for split pressure, repeated setup, weak
|
|
260
|
+
assertions, validation issues, and refactor recommendations.
|
|
261
|
+
|
|
262
|
+
## Development
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
pnpm run test
|
|
266
|
+
pnpm run lint
|
|
267
|
+
pnpm run typecheck
|
|
268
|
+
pnpm run build
|
|
269
|
+
```
|