@avi2dg/checks 0.24.1 → 0.25.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 +22 -0
- package/README.md +27 -19
- package/dist/effect-channel/index.js +4 -4
- package/dist/readability/index.js +5 -5
- package/docs/configs/commit-messages.md +1 -1
- package/docs/configs/native-settings.md +3 -2
- package/docs/design.md +9 -3
- package/docs/gates/checks-changelog.md +5 -1
- package/docs/gates/checks-comment-gate.md +3 -4
- package/docs/gates/checks-docs.md +5 -5
- package/docs/gates/checks-flake.md +1 -1
- package/docs/gates/checks-lint.md +1 -1
- package/docs/gates/checks-quarantine-clock.md +1 -1
- package/docs/gates/checks-test-layout.md +14 -9
- package/docs/gates/checks-test.md +1 -1
- package/docs/gates/checks-unused.md +65 -0
- package/knip-base.json +4 -0
- package/package.json +68 -104
- package/{scripts → src/complexity}/repetition.ts +2 -2
- package/{scripts → src/complexity}/suppressions-ratchet.ts +2 -2
- package/src/complexity/unused.ts +97 -0
- package/src/core/gates.ts +45 -0
- package/{scripts → src/core}/lint.ts +2 -2
- package/{scripts → src/delivery}/changelog-write.ts +30 -6
- package/{scripts → src/delivery}/changelog.ts +14 -4
- package/{scripts → src/delivery}/ci-wiring.ts +3 -3
- package/{scripts → src/delivery}/commit-identity.ts +2 -2
- package/{scripts → src/delivery}/release-notes.ts +1 -1
- package/{scripts → src/delivery}/release-report.ts +2 -2
- package/{scripts → src/dependencies}/vendor-args.ts +1 -1
- package/{scripts → src/dependencies}/vendor.ts +2 -2
- package/{scripts → src/docs}/doc-snapshot.ts +1 -1
- package/{scripts → src/docs}/doc-templates.ts +1 -1
- package/{scripts → src/docs}/docs.ts +2 -2
- package/{scripts → src/quality}/comment-gate.ts +2 -2
- package/{scripts → src/quality}/comment-matchers.ts +1 -1
- package/{scripts → src/testing}/flake.ts +1 -1
- package/{scripts → src/testing}/mutation-compare.ts +1 -1
- package/{scripts → src/testing}/quarantine-clock.ts +2 -2
- package/{scripts → src/testing}/subsumed-tests.ts +2 -2
- package/{scripts → src/testing}/test-layout.ts +47 -14
- package/{scripts → src/testing}/test-skips.ts +1 -1
- package/{scripts → src/testing}/test.ts +2 -2
- package/templates/changelog.md +2 -0
- package/CONTRIBUTING.md +0 -93
- package/docs/gates/checks-backtest.md +0 -54
- package/scripts/backtest.ts +0 -122
- package/scripts/gates.ts +0 -37
- package/scripts/range-gate.ts +0 -8
- /package/{scripts → src/core}/git.ts +0 -0
- /package/{scripts → src/core}/main.ts +0 -0
- /package/{scripts → src/core}/swc.ts +0 -0
- /package/{scripts → src/delivery}/shell-command.ts +0 -0
- /package/{scripts → src/docs}/doc-outline.ts +0 -0
- /package/{scripts → src/docs}/doc-references.ts +0 -0
- /package/{scripts → src/docs}/doc-rules.ts +0 -0
- /package/{scripts → src/docs}/prose-matchers.ts +0 -0
- /package/{scripts → src/quality}/comments.ts +0 -0
- /package/{scripts → src/quality}/lint-coverage.sh +0 -0
- /package/{scripts → src/testing}/test-report.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
Every release of `@avi2dg/checks`, newest first, written by the release from its conventional commits.
|
|
4
4
|
|
|
5
|
+
## 0.25.0
|
|
6
|
+
|
|
7
|
+
Released 2026-09-27.
|
|
8
|
+
|
|
9
|
+
### Breaking changes
|
|
10
|
+
|
|
11
|
+
- stop shipping checks-backtest and unused exports keys, guard the tarball with Knip [#86](https://github.com/avi2d/checks/pull/86)
|
|
12
|
+
- sort the kit into src/<vector>/ and require tests/<level>/ [#84](https://github.com/avi2d/checks/pull/84)
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
- add checks-unused gate that rejects unreferenced TypeScript files via Knip [#85](https://github.com/avi2d/checks/pull/85)
|
|
17
|
+
|
|
18
|
+
## 0.24.2
|
|
19
|
+
|
|
20
|
+
Released 2026-09-27.
|
|
21
|
+
|
|
22
|
+
### Fixes
|
|
23
|
+
|
|
24
|
+
- **scripts:** list commits merged in after a bump under that release [#82](https://github.com/avi2d/checks/pull/82)
|
|
25
|
+
- **scripts:** leave versions with no listable commits out of the changelog [#81](https://github.com/avi2d/checks/pull/81)
|
|
26
|
+
|
|
5
27
|
## 0.24.1
|
|
6
28
|
|
|
7
29
|
Released 2026-09-27.
|
package/README.md
CHANGED
|
@@ -65,6 +65,14 @@ To consume the kit from a repository:
|
|
|
65
65
|
cp node_modules/@avi2dg/checks/bunfig.toml bunfig.toml
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
1. Name the repository's entry files in `knip.config.ts`, spreading the kit's Knip base:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import base from "@avi2dg/checks/knip-base.json";
|
|
72
|
+
|
|
73
|
+
export default { ...base, entry: ["src/index.ts", "tests/**/*.test.ts"] };
|
|
74
|
+
```
|
|
75
|
+
|
|
68
76
|
1. Add scripts to `package.json`, replacing the build entry with the repository's own build command:
|
|
69
77
|
|
|
70
78
|
```json
|
|
@@ -100,22 +108,24 @@ Add a pull request title lint step in another workflow using `./node_modules/.bi
|
|
|
100
108
|
|
|
101
109
|
## What runs
|
|
102
110
|
|
|
103
|
-
`checks-lint` runs these gates
|
|
111
|
+
`checks-lint` runs these gates, each over the working tree or over the range it resolves, and names every one that fails.
|
|
104
112
|
`checks-lint` runs every applicable gate, including the TypeScript gates once the repository tracks TypeScript.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
| [`checks-
|
|
112
|
-
| [`checks-
|
|
113
|
-
| [`checks-
|
|
114
|
-
| [`checks-
|
|
115
|
-
| [`checks-
|
|
116
|
-
| [`checks-
|
|
117
|
-
| [`checks-
|
|
118
|
-
| [`checks-
|
|
113
|
+
Each gate belongs to the vector it judges a repository on, and the table groups the gates by vector.
|
|
114
|
+
|
|
115
|
+
<!-- generated gates: bun run build writes it from KIT_GATES in src/core/gates.ts and scripts/doc-blocks.ts -->
|
|
116
|
+
|
|
117
|
+
| Vector | Gate | Reads | Runs in |
|
|
118
|
+
| --- | --- | --- | --- |
|
|
119
|
+
| complexity | [`checks-suppressions-ratchet`](docs/gates/checks-suppressions-ratchet.md) | the range | every repository |
|
|
120
|
+
| complexity | [`checks-repetition`](docs/gates/checks-repetition.md) | the range | a repository tracking `*.ts` or `*.tsx` |
|
|
121
|
+
| complexity | [`checks-unused`](docs/gates/checks-unused.md) | the working tree | a repository tracking `*.ts` or `*.tsx` |
|
|
122
|
+
| quality | [`checks-lint-coverage`](docs/gates/checks-lint-coverage.md) | the working tree | a repository tracking `*.ts` or `*.tsx` |
|
|
123
|
+
| quality | [`checks-comment-gate`](docs/gates/checks-comment-gate.md) | the range | every repository |
|
|
124
|
+
| testing | [`checks-test-layout`](docs/gates/checks-test-layout.md) | the working tree | a repository tracking `*.ts` or `*.tsx` |
|
|
125
|
+
| testing | [`checks-quarantine-clock`](docs/gates/checks-quarantine-clock.md) | the range | every repository |
|
|
126
|
+
| docs | [`checks-docs`](docs/gates/checks-docs.md) | the range | every repository |
|
|
127
|
+
| delivery | [`checks-commit-identity`](docs/gates/checks-commit-identity.md) | the range | every repository |
|
|
128
|
+
| delivery | [`checks-ci-wiring`](docs/gates/checks-ci-wiring.md) | the working tree | every repository |
|
|
119
129
|
|
|
120
130
|
<!-- end generated gates -->
|
|
121
131
|
|
|
@@ -125,7 +135,6 @@ These bins run on their own:
|
|
|
125
135
|
- [`checks-flake`](docs/gates/checks-flake.md) runs the suite on a schedule and records the seeds a flaky test fails with.
|
|
126
136
|
- [`checks-mutation-compare`](docs/gates/checks-mutation-compare.md) holds every mutant in a pull request to no regression.
|
|
127
137
|
- [`checks-subsumed-tests`](docs/gates/checks-subsumed-tests.md) lists each test another test subsumes in a mutation run.
|
|
128
|
-
- [`checks-backtest`](docs/gates/checks-backtest.md) reports what the comment check would have refused in recent history.
|
|
129
138
|
- [`checks-changelog`](docs/gates/checks-changelog.md) writes the pending release into `CHANGELOG.md` from the conventional commits since the last release.
|
|
130
139
|
- [`checks-release-notes`](docs/gates/checks-release-notes.md) writes one `CHANGELOG.md` section to a file for a GitHub release.
|
|
131
140
|
- [`checks-release-report`](docs/gates/checks-release-report.md) tells whether the history holds unreleased features or fixes since the last tag.
|
|
@@ -156,12 +165,12 @@ Every path is relative to the installed package, `node_modules/@avi2dg/checks/`.
|
|
|
156
165
|
| Path | What it holds |
|
|
157
166
|
| --- | --- |
|
|
158
167
|
| `CHANGELOG.md` | every release, and what it changed |
|
|
159
|
-
| `CONTRIBUTING.md` | how this repository is developed and released |
|
|
160
168
|
| `docs/` | a reference page per bin and per shared config, and why the kit is shaped this way |
|
|
161
169
|
| `bunfig.toml` | the bunfig preset a repository copies |
|
|
162
170
|
| `commitlint.config.js` | the shared commitlint config |
|
|
163
171
|
| `dependency-cruiser.config.js` | the shared dependency-cruiser base |
|
|
164
|
-
| `
|
|
172
|
+
| `knip-base.json` | the Knip base a repository's configuration imports |
|
|
173
|
+
| `src/` | every bin, which a package script calls by its `checks-` name, and the modules the bins import |
|
|
165
174
|
| `templates/` | one template per kind of doc file, which a new doc file starts from |
|
|
166
175
|
| `presets/` | the Effect rule blocks a repository copies into its native config |
|
|
167
176
|
| `oxlintrc.json` | the oxlint base config `.oxlintrc.json` extends |
|
|
@@ -179,4 +188,3 @@ Every path is relative to the installed package, `node_modules/@avi2dg/checks/`.
|
|
|
179
188
|
- [The dependency rules](docs/configs/dependency-rules.md)
|
|
180
189
|
- [The commit message lint](docs/configs/commit-messages.md)
|
|
181
190
|
- [Why it is shaped this way](docs/design.md)
|
|
182
|
-
- [Contribute to checks](CONTRIBUTING.md)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// effect-channel/no-error-channel-escape.ts
|
|
1
|
+
// src/quality/effect-channel/no-error-channel-escape.ts
|
|
2
2
|
var EFFECT_SOURCES = new Set(["effect", "effect/Effect"]);
|
|
3
3
|
var INSTEAD = {
|
|
4
4
|
drops: "it drops the failure and the success together, so no caller can tell one from the other. Handle the error by tag, or keep it as a value with Effect.result or Effect.exit",
|
|
@@ -69,7 +69,7 @@ var rule = {
|
|
|
69
69
|
};
|
|
70
70
|
var no_error_channel_escape_default = rule;
|
|
71
71
|
|
|
72
|
-
// effect-channel/no-throw.ts
|
|
72
|
+
// src/quality/effect-channel/no-throw.ts
|
|
73
73
|
var rule2 = {
|
|
74
74
|
meta: {
|
|
75
75
|
type: "problem",
|
|
@@ -88,7 +88,7 @@ var rule2 = {
|
|
|
88
88
|
};
|
|
89
89
|
var no_throw_default = rule2;
|
|
90
90
|
|
|
91
|
-
// effect-channel/no-try-catch.ts
|
|
91
|
+
// src/quality/effect-channel/no-try-catch.ts
|
|
92
92
|
var rule3 = {
|
|
93
93
|
meta: {
|
|
94
94
|
type: "problem",
|
|
@@ -107,7 +107,7 @@ var rule3 = {
|
|
|
107
107
|
};
|
|
108
108
|
var no_try_catch_default = rule3;
|
|
109
109
|
|
|
110
|
-
// effect-channel/index.ts
|
|
110
|
+
// src/quality/effect-channel/index.ts
|
|
111
111
|
var plugin = {
|
|
112
112
|
meta: { name: "effect-channel" },
|
|
113
113
|
rules: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// readability/cognitive-nodes.ts
|
|
1
|
+
// src/complexity/readability/cognitive-nodes.ts
|
|
2
2
|
var CONTROL_TYPES = ["IfStatement", "ConditionalExpression", "SwitchStatement", "SwitchCase", "TryStatement", "CatchClause"];
|
|
3
3
|
var LOOP_TYPES = ["ForStatement", "ForInStatement", "ForOfStatement", "WhileStatement", "DoWhileStatement", "LabeledStatement"];
|
|
4
4
|
var CALL_TYPES = ["LogicalExpression", "BreakStatement", "ContinueStatement", "CallExpression", "NewExpression", "ImportExpression"];
|
|
@@ -7,7 +7,7 @@ var PLAIN_A_TYPES = ["BlockStatement", "ExpressionStatement", "ReturnStatement",
|
|
|
7
7
|
var PLAIN_B_TYPES = ["ClassDeclaration", "ClassExpression", "ClassBody", "MethodDefinition", "TSAbstractMethodDefinition", "PropertyDefinition", "TSAbstractPropertyDefinition", "AccessorProperty", "TSAbstractAccessorProperty", "ObjectExpression", "ArrayExpression"];
|
|
8
8
|
var PLAIN_C_TYPES = ["AwaitExpression", "UnaryExpression", "UpdateExpression", "SpreadElement", "YieldExpression", "BinaryExpression", "AssignmentExpression", "TSAsExpression", "TSSatisfiesExpression", "TSTypeAssertion", "TSNonNullExpression", "ChainExpression", "ParenthesizedExpression", "Decorator", "TSInstantiationExpression", "MemberExpression", "JSXMemberExpression", "TemplateLiteral", "TaggedTemplateExpression", "SequenceExpression", "JSXElement", "JSXFragment", "JSXOpeningElement", "JSXAttribute", "JSXExpressionContainer", "JSXSpreadChild", "JSXSpreadAttribute"];
|
|
9
9
|
|
|
10
|
-
// readability/cognitive-plain.ts
|
|
10
|
+
// src/complexity/readability/cognitive-plain.ts
|
|
11
11
|
function isControl(node) {
|
|
12
12
|
return CONTROL_TYPES.includes(node.type);
|
|
13
13
|
}
|
|
@@ -142,7 +142,7 @@ function plainChildrenC(node) {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
// readability/cognitive.ts
|
|
145
|
+
// src/complexity/readability/cognitive.ts
|
|
146
146
|
function unreachable2(_value) {}
|
|
147
147
|
function scoreList(state, nodes, nesting, parent) {
|
|
148
148
|
for (const node of nodes) {
|
|
@@ -334,7 +334,7 @@ function cognitiveComplexity(root, names) {
|
|
|
334
334
|
return state.recursive ? state.total + 1 : state.total;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
// readability/cognitive-complexity.ts
|
|
337
|
+
// src/complexity/readability/cognitive-complexity.ts
|
|
338
338
|
var DEFAULT_MAX = 15;
|
|
339
339
|
function maxOf(options) {
|
|
340
340
|
const [first] = options;
|
|
@@ -416,7 +416,7 @@ var rule = {
|
|
|
416
416
|
};
|
|
417
417
|
var cognitive_complexity_default = rule;
|
|
418
418
|
|
|
419
|
-
// readability/index.ts
|
|
419
|
+
// src/complexity/readability/index.ts
|
|
420
420
|
var plugin = {
|
|
421
421
|
meta: { name: "readability" },
|
|
422
422
|
rules: {
|
|
@@ -8,7 +8,7 @@ The shared commitlint config holds each pull request title to conventional commi
|
|
|
8
8
|
|
|
9
9
|
## Config
|
|
10
10
|
|
|
11
|
-
Commits follow `@commitlint/config-conventional` plus the house prefixes `commitlint.config.js` lists, shared from
|
|
11
|
+
Commits follow `@commitlint/config-conventional` plus the house prefixes `commitlint.config.js` lists, shared from `node_modules/@avi2dg/checks/commitlint.config.js`.
|
|
12
12
|
It arrives with the kit, since `@commitlint/cli` and `@commitlint/config-conventional` are dependencies, not peers.
|
|
13
13
|
|
|
14
14
|
## Workflow
|
|
@@ -14,6 +14,7 @@ A consuming repository puts each setting in the file its tool reads.
|
|
|
14
14
|
| `.oxlintrc.json` | Effect paths, exemptions, file size, function size, statements, cognitive complexity and depth | oxlint |
|
|
15
15
|
| `oxlint-suppressions.json` | The existing violations oxlint suppresses, per file and rule | oxlint and `checks-suppressions-ratchet` |
|
|
16
16
|
| `.jscpd.json` | The `path` and `ignore` globs of the files repetition is measured in | jscpd and `checks-repetition` |
|
|
17
|
+
| `knip.config.ts` | The `entry` globs Knip traces unreferenced files from, spread over the kit's `knip-base.json` | Knip and `checks-unused` |
|
|
17
18
|
| `tsconfig.json` | Effect language service scope and severity | TypeScript and Effect language service |
|
|
18
19
|
| `package.json` | `scripts` with the `checks-vendor` arguments in `prepare`, `author` and `contributors` | Bun, `checks-commit-identity` and `checks-vendor` |
|
|
19
20
|
| `bunfig.toml` | Test discovery and quarantine exclusion | Bun and `checks-test-layout` |
|
|
@@ -55,9 +56,9 @@ A repository records its existing violations with `oxlint --suppress-all`, which
|
|
|
55
56
|
`checks-suppressions-ratchet` refuses any count in that file that rises, so the recorded debt only falls.
|
|
56
57
|
The kit's own `.oxlintrc.json` sets these limits for each size override, and a repository may copy them:
|
|
57
58
|
|
|
58
|
-
<!-- generated size-limits: bun run build writes it from .oxlintrc.json, SIZE_RULES in
|
|
59
|
+
<!-- generated size-limits: bun run build writes it from .oxlintrc.json, SIZE_RULES in src/complexity/size-rules.ts and scripts/doc-blocks.ts -->
|
|
59
60
|
|
|
60
|
-
| Limits | oxlint rule | `
|
|
61
|
+
| Limits | oxlint rule | `src/**/*.ts`, `scripts/**/*.ts` | `tests/**/*.ts` |
|
|
61
62
|
| --- | --- | --- | --- |
|
|
62
63
|
| The most lines a file may hold, blank and comment lines counted | `max-lines` | 400 | 600 |
|
|
63
64
|
| The most lines a function may span, blank and comment lines counted | `max-lines-per-function` | 100 | off |
|
package/docs/design.md
CHANGED
|
@@ -12,8 +12,14 @@ Each entry below is a choice in the kit's shape and the constraint that forced i
|
|
|
12
12
|
- `files` in package.json is the published surface: `tests/`, `AGENTS.md` and the `.ts` plugin source never reach an install.
|
|
13
13
|
npm adds `package.json`, `README` and `LICENSE` to the tarball whatever `files` says.
|
|
14
14
|
`bun pm pack` builds the same tarball the registry serves, which is what the packed-tarball consumer e2e test installs.
|
|
15
|
-
- Each plugin ships compiled under `dist/`, built with `bun build
|
|
15
|
+
- Each plugin ships compiled under `dist/`, built with `bun build src/<vector>/<name>/index.ts --outdir dist/<name> --target node --format esm`.
|
|
16
16
|
Node refuses to type-strip a `.ts` plugin under `node_modules`, so the `.ts` source would fail to load from an installed package.
|
|
17
|
+
- The source sits under `src/<vector>/`, one directory for each thing the kit judges a repository on: complexity, quality, testing, docs, delivery and dependencies.
|
|
18
|
+
`src/core/` holds what every vector runs on, and `scripts/` holds only the kit's own build, which nothing ships.
|
|
19
|
+
Sorting by what loads a file put the two oxlint plugins at the root and every bin in one flat `scripts/`, so the files for one purpose sat in several places and nothing said which gate a helper served.
|
|
20
|
+
A mutation runner's default scope covers `src/`, so the kit's own Stryker run mutates its source without a `mutate` list.
|
|
21
|
+
The testing vector and its directory are named testing rather than tests, since a `src/tests/` beside the root `tests/` would read as a second suite.
|
|
22
|
+
An `exports` key a consumer resolves as a specifier keeps pointing at the file's new home, so that specifier resolves as before while a path read without resolution does not.
|
|
17
23
|
- The size rules are plain oxlint rules at `error` in `.oxlintrc.json`, and `bun run lint` enforces them on the whole tree.
|
|
18
24
|
A repository records its existing violations with `oxlint --suppress-all`, and `checks-suppressions-ratchet` refuses any count that rises.
|
|
19
25
|
The kit runs no size script of its own, since restating how oxlint reads its config and compares sites left corners the native rules never had.
|
|
@@ -72,7 +78,7 @@ Each entry below is a choice in the kit's shape and the constraint that forced i
|
|
|
72
78
|
Setting your own `options.enhancedResolveOptions` replaces the base's, so restate `exportsFields` and `conditionNames` if you do.
|
|
73
79
|
- dependency-cruiser `extends` merges same-name `forbidden` rules with the child's fields winning.
|
|
74
80
|
That is the entry-point and layer recipe under Boundaries in [The dependency rules](configs/dependency-rules.md).
|
|
75
|
-
- The templates in `templates/` are rendered from `
|
|
81
|
+
- The templates in `templates/` are rendered from `src/docs/doc-templates.ts`, the spec `checks-docs` reads.
|
|
76
82
|
A template written by hand beside the check agrees with it only until someone edits one of them.
|
|
77
83
|
- A page's Diátaxis mode comes from `kind` front matter on the page, whatever directory holds it.
|
|
78
84
|
The repository makes the judgment beside the page, and the check holds it to that template.
|
|
@@ -86,7 +92,7 @@ Each entry below is a choice in the kit's shape and the constraint that forced i
|
|
|
86
92
|
Under a hard wrap a one-word edit reflows a paragraph, and the gate would then demand fixes to sentences the edit never touched.
|
|
87
93
|
- An agent file such as `AGENTS.md` takes the separator rules and no other prose rule.
|
|
88
94
|
One sentence per line serves the people who review a doc's diffs, and an agent file keeps each entry to one line however many sentences it holds.
|
|
89
|
-
- `
|
|
95
|
+
- `src/docs/prose-matchers.ts` imports nothing, so the gate and a write-time hook run one matcher and refuse in the same words.
|
|
90
96
|
A hook bundle ships without `node_modules`, so a matcher that needed Vale or a package could not refuse at write time.
|
|
91
97
|
- Readability grades and words such as easy stay out of the prose rules.
|
|
92
98
|
A score cannot fail a change without failing correct prose, and a suggestion nobody runs an editor for is never seen.
|
|
@@ -10,11 +10,15 @@ audience: consumers
|
|
|
10
10
|
|
|
11
11
|
It reads the version from `package.json` and treats that version as the release being prepared.
|
|
12
12
|
It lists every conventional commit the release closes, grouped as Features, Fixes, Performance, Reverts and Breaking changes.
|
|
13
|
+
It lists the commits a branch merged in after its bump under that bump, since the squash merge releases them there.
|
|
14
|
+
It leaves out what the branch added past its bump, since the squash merge folds it into the release commit.
|
|
15
|
+
Only a branch carrying its own unlanded bump lists the commits of an unlanded branch it merges, so such a branch takes in only main.
|
|
16
|
+
CI must build the pull request head commit, the `actions/checkout` ref `github.event.pull_request.head.sha`, and not the GitHub merge ref, since the merge ref puts main first and the branch's own bump off the first-parent chain.
|
|
13
17
|
It links each entry to its pull request under the repository address `package.json` names.
|
|
14
18
|
It keeps the date a released section already carries and dates a new section today.
|
|
15
19
|
It writes the whole file newest first, so the changelog is never edited by hand.
|
|
16
20
|
A repository with no tag yet releases from its first commit.
|
|
17
|
-
A
|
|
21
|
+
A version with no conventional commit worth listing writes no section.
|
|
18
22
|
|
|
19
23
|
## What it reads
|
|
20
24
|
|
|
@@ -16,15 +16,15 @@ A refusal counts when any line of the comment carrying it was added.
|
|
|
16
16
|
|
|
17
17
|
## What it reads
|
|
18
18
|
|
|
19
|
-
It reads the diff between two commits, and the added lines of each file whose extension has a comment syntax in `
|
|
19
|
+
It reads the diff between two commits, and the added lines of each file whose extension has a comment syntax in `src/quality/comment-matchers.ts`.
|
|
20
20
|
It passes over a file with any other extension.
|
|
21
21
|
|
|
22
|
-
`
|
|
22
|
+
`src/quality/comment-matchers.ts` holds the scanner, the comment syntaxes and a synchronous `refused()`, and imports nothing.
|
|
23
23
|
A host such as a hook bundle can therefore copy it alone into a directory with no `node_modules` and import it as `@avi2dg/checks/scripts/comment-matchers.ts`.
|
|
24
24
|
The kit's own dependency cruise fails when that file gains an import.
|
|
25
25
|
`REFUSED_DIRECTIVES` in that file owns the refused directive names, and the checker builds its directive pattern from that list, so the two cannot disagree.
|
|
26
26
|
A consumer reads the same contract by importing `REFUSED_DIRECTIVES` from `@avi2dg/checks/scripts/comment-matchers.ts`.
|
|
27
|
-
`
|
|
27
|
+
`src/quality/comments.ts` wraps the same matchers in Effect for the gate.
|
|
28
28
|
|
|
29
29
|
## Arguments
|
|
30
30
|
|
|
@@ -60,5 +60,4 @@ It applies to every repository, so no selection leaves it out.
|
|
|
60
60
|
|
|
61
61
|
## Related topics
|
|
62
62
|
|
|
63
|
-
- [checks-backtest](checks-backtest.md)
|
|
64
63
|
- [checks-lint](checks-lint.md)
|
|
@@ -17,7 +17,7 @@ The package ships one template per kind under `templates/`, and a repository sta
|
|
|
17
17
|
cp node_modules/@avi2dg/checks/templates/how-to.md docs/add-a-supplier.md
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
<!-- generated doc-kinds: bun run build writes it from
|
|
20
|
+
<!-- generated doc-kinds: bun run build writes it from src/docs/doc-rules.ts, src/docs/doc-templates.ts and scripts/doc-blocks.ts -->
|
|
21
21
|
|
|
22
22
|
| File | Kind | Template |
|
|
23
23
|
| --- | --- | --- |
|
|
@@ -60,7 +60,7 @@ A template decides a file's structure, and the template file itself is the refer
|
|
|
60
60
|
|
|
61
61
|
A line a change adds or edits in a living doc or an agent file is held to the prose rules, and a line the change leaves alone is not, so a repository needs no cleanup pass before it runs them.
|
|
62
62
|
|
|
63
|
-
<!-- generated living-docs: bun run build writes it from
|
|
63
|
+
<!-- generated living-docs: bun run build writes it from src/docs/prose-matchers.ts and scripts/doc-blocks.ts -->
|
|
64
64
|
|
|
65
65
|
A living doc is one of these:
|
|
66
66
|
|
|
@@ -77,7 +77,7 @@ These are records, and take no prose rule:
|
|
|
77
77
|
|
|
78
78
|
<!-- end generated living-docs -->
|
|
79
79
|
|
|
80
|
-
<!-- generated prose-rules: bun run build writes it from PROSE_RULES in
|
|
80
|
+
<!-- generated prose-rules: bun run build writes it from PROSE_RULES in src/docs/prose-matchers.ts and scripts/doc-blocks.ts -->
|
|
81
81
|
|
|
82
82
|
| Refused | For example | Write instead | In agent files |
|
|
83
83
|
| --- | --- | --- | --- |
|
|
@@ -98,14 +98,14 @@ A bold label that opens a line, as in `**Status.**`, heads the sentence after it
|
|
|
98
98
|
Fenced code, inline code, link destinations, URLs, HTML comments and front matter are not prose, so no rule reads them.
|
|
99
99
|
Readability scores and word choice, such as easy, are not checked.
|
|
100
100
|
|
|
101
|
-
`
|
|
101
|
+
`src/docs/prose-matchers.ts` holds the rules and a synchronous `proseRefused()`, and imports nothing.
|
|
102
102
|
A host such as a hook bundle can therefore copy it alone into a directory with no `node_modules` and import it as `@avi2dg/checks/scripts/prose-matchers.ts`, to refuse the same lines at write time.
|
|
103
103
|
|
|
104
104
|
## Paths, links and commands
|
|
105
105
|
|
|
106
106
|
Each reference a living doc names has to resolve at the head commit:
|
|
107
107
|
|
|
108
|
-
- A path in inline code that ends in a file extension, such as `
|
|
108
|
+
- A path in inline code that ends in a file extension, such as `src/core/lint.ts`, names a file from the root or from the doc's directory.
|
|
109
109
|
- A relative Markdown link names a file or a directory, and its anchor names a heading in the file it links, as GitHub derives the anchor, or an explicit `id`.
|
|
110
110
|
- A `bun run` command in code names a script in the nearest `package.json`, a bin in `node_modules/.bin`, or a file that exists.
|
|
111
111
|
|
|
@@ -43,7 +43,7 @@ checks-flake: 3 of 10 run(s) failed, 1 test(s) failing in them
|
|
|
43
43
|
|
|
44
44
|
| Test | Failed | Seeds |
|
|
45
45
|
| --- | --- | --- |
|
|
46
|
-
| tests/cache.test.ts:6 reads the cache | 3 of 10 runs | 2170533150, 4046124386, 180394251 |
|
|
46
|
+
| tests/unit/cache.test.ts:6 reads the cache | 3 of 10 runs | 2170533150, 4046124386, 180394251 |
|
|
47
47
|
|
|
48
48
|
Reproduce a failing run with bun test --randomize --seed=<seed>.
|
|
49
49
|
```
|
|
@@ -8,7 +8,7 @@ audience: consumers
|
|
|
8
8
|
|
|
9
9
|
## What it checks
|
|
10
10
|
|
|
11
|
-
It runs the gates under [What runs](../../README.md#what-runs)
|
|
11
|
+
It runs the gates under [What runs](../../README.md#what-runs), each in its own process.
|
|
12
12
|
Gates requiring tracked TypeScript files begin running when the repository tracks TypeScript.
|
|
13
13
|
All other gates run for every repository.
|
|
14
14
|
|
|
@@ -43,7 +43,7 @@ With one it judges that commit, including a repository's first commit.
|
|
|
43
43
|
|
|
44
44
|
```
|
|
45
45
|
quarantine-clock: 1 test(s) in tests/quarantine/ is past 30 days; fix each and move it back, or delete it:
|
|
46
|
-
tests/quarantine/billing.test.ts entered quarantine on 2026-08-01 (45 days ago)
|
|
46
|
+
tests/quarantine/unit/billing.test.ts entered quarantine on 2026-08-01 (45 days ago)
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
## Opting out
|
|
@@ -10,18 +10,20 @@ audience: consumers
|
|
|
10
10
|
|
|
11
11
|
It fails unless the repository holds this shape, and names the file and the path to move it to when it does not.
|
|
12
12
|
|
|
13
|
-
- Every test file is `tests
|
|
14
|
-
A
|
|
13
|
+
- Every test file is `tests/<level>/**/*.test.ts` or `.tsx`, and the level is `unit`, `e2e`, `live` or `pixel`.
|
|
14
|
+
A quarantined test keeps its level as `tests/quarantine/<level>/**/*.test.ts`.
|
|
15
|
+
A `*.test.ts`, `*.spec.ts` or `*_test.ts` under `src/`, `test/`, `__tests__/`, the repository root or a directory under `tests/` that names no level fails.
|
|
16
|
+
The path it names for the move is under `tests/unit/` unless the file already sits under a level.
|
|
15
17
|
- `tests/lib/**` holds helpers and `tests/fixtures/**` holds data, and neither may hold a test file.
|
|
16
|
-
|
|
18
|
+
Under its level, a test may sit in groups nested as deep as it likes.
|
|
17
19
|
- `tests/live/**` holds tests that need a live machine, and `tests/pixel/**` holds tests that need a display.
|
|
18
20
|
Bun ignores both directories in the default suite.
|
|
19
21
|
A live tier with test files requires `test:live` set to `checks-test --tier=live`.
|
|
20
22
|
A pixel tier with test files requires `test:pixel` set to `checks-test --tier=pixel`.
|
|
21
|
-
- A test runs
|
|
22
|
-
A test outside `
|
|
23
|
+
- A test runs in-process or in a process of its own.
|
|
24
|
+
A test outside the `e2e`, `live` and `pixel` levels runs in-process, quarantined or not, so it may not import `node:child_process`, `net`, `http`, `https`, `http2`, `tls` or `dgram`.
|
|
23
25
|
It may not import `$`, `spawn`, `spawnSync`, `connect`, `serve` or `listen` from `bun`, may not touch `Bun.$` or `Bun.spawn`, and may not call `fetch`.
|
|
24
|
-
A test
|
|
26
|
+
A test at the `e2e`, `live` or `pixel` level may do all of it, under `tests/quarantine/` as well.
|
|
25
27
|
Helpers in `tests/lib/**` answer to the same rule, since an in-process test reaches them.
|
|
26
28
|
- `scripts.test` is exactly `checks-test`, which runs `bun test --randomize` as [checks-test](checks-test.md) says.
|
|
27
29
|
- `scripts.lint` runs this check, itself or through `checks-lint` called by its bare bin name.
|
|
@@ -30,12 +32,15 @@ It fails unless the repository holds this shape, and names the file and the path
|
|
|
30
32
|
The check also accepts the list without `repos/**`, so a repository that links no library under `repos/` may drop it.
|
|
31
33
|
Other tables, and extra `[test]` keys, are the repository's own.
|
|
32
34
|
|
|
33
|
-
The in-process
|
|
35
|
+
The in-process tests under `tests/unit/` are what a mutation run takes as its tests, and a runner names them by that path rather than by a list of paths to ignore.
|
|
34
36
|
`tests/e2e/**` is left out of a mutate scope by construction, because a subprocess kills both the speed and the coverage signal a mutant needs.
|
|
35
37
|
|
|
36
38
|
The preset also skips `tests/quarantine/**` and `repos/**` on a default run.
|
|
37
39
|
The `repos/**` entry keeps the suite from following the library links `checks-vendor` manages into trees whose tests are not this repository's.
|
|
38
|
-
A test that turns flaky moves there, so the suite stays trustworthy
|
|
40
|
+
A test that turns flaky moves there at its own level, so the suite stays trustworthy.
|
|
41
|
+
A flaky test under `tests/e2e/stack/` moves to the same path under `tests/quarantine/e2e/stack/`, where it may still spawn, and moves back once fixed.
|
|
42
|
+
A `quarantine` directory below a level is refused, since the preset's ignore does not reach it and the test would still run.
|
|
43
|
+
The flake still runs on demand:
|
|
39
44
|
|
|
40
45
|
```sh
|
|
41
46
|
bun test --path-ignore-patterns='' tests/quarantine
|
|
@@ -72,7 +77,7 @@ It checks the directory it runs in, or the directory it is given.
|
|
|
72
77
|
|
|
73
78
|
```
|
|
74
79
|
test-layout: 4 violation(s)
|
|
75
|
-
src/a.test.ts: a test file must live at tests
|
|
80
|
+
src/a.test.ts: a test file must live at tests/<level>/**/*.test.ts, or tests/quarantine/<level>/**/*.test.ts while quarantined, with unit, e2e, live, or pixel as the level; move it to tests/unit/a.test.ts
|
|
76
81
|
package.json: scripts.test must be exactly "checks-test", which runs bun test --randomize and judges its skips, found "bun test"
|
|
77
82
|
package.json: scripts.lint must run the layout check: add "checks-lint"
|
|
78
83
|
bunfig.toml: bunfig.toml is missing; bun has no bunfig extends, so copy node_modules/@avi2dg/checks/bunfig.toml
|
|
@@ -87,7 +87,7 @@ It refuses test filters because every test excluded by a filter would look skipp
|
|
|
87
87
|
|
|
88
88
|
```
|
|
89
89
|
checks-test: 1 skipped test(s) undeclared in this local run:
|
|
90
|
-
tests/pricing.test.ts:12 rounds half to even: skipped with no reason at its test site; use test.skipIf(condition)(skipReason(reason, name), fn)
|
|
90
|
+
tests/unit/pricing.test.ts:12 rounds half to even: skipped with no reason at its test site; use test.skipIf(condition)(skipReason(reason, name), fn)
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
A run with no skipped tests ends with:
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: reference
|
|
3
|
+
audience: consumers
|
|
4
|
+
---
|
|
5
|
+
# checks-unused
|
|
6
|
+
|
|
7
|
+
`checks-unused` is the gate that refuses a TypeScript file no entry point reaches, and a reader looks it up when a file seems dead but every other check passes.
|
|
8
|
+
|
|
9
|
+
## What it checks
|
|
10
|
+
|
|
11
|
+
It runs Knip with the repository's own configuration and names each `.ts` or `.tsx` file no entry reaches.
|
|
12
|
+
It reads only the files issue type, so an unused export or dependency never fails it.
|
|
13
|
+
It asks Knip for that issue type itself, so a configuration that narrows `include`, excludes files or turns the files rule off still has its files judged.
|
|
14
|
+
It fails when the repository tracks no TypeScript source, since an empty scan would pass without judging anything.
|
|
15
|
+
It fails when the repository holds no Knip configuration, since Knip's default entries cannot tell a dead file from an entry point.
|
|
16
|
+
|
|
17
|
+
## What it reads
|
|
18
|
+
|
|
19
|
+
It reads the working tree, so an uncommitted file is judged like a committed one.
|
|
20
|
+
It reads the repository's Knip configuration, which names the entries.
|
|
21
|
+
Knip configurations do not extend a package file, so the consumer configuration imports the kit's base and spreads it:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import base from "@avi2dg/checks/knip-base.json";
|
|
25
|
+
|
|
26
|
+
export default { ...base, entry: ["src/index.ts", "tests/**/*.test.ts"] };
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The base in `knip-base.json` reports only unreferenced files.
|
|
30
|
+
The gate resolves the Knip binary from the installed kit, so a consumer installs nothing beyond the kit.
|
|
31
|
+
|
|
32
|
+
## Arguments
|
|
33
|
+
|
|
34
|
+
It takes none.
|
|
35
|
+
|
|
36
|
+
## Exit codes
|
|
37
|
+
|
|
38
|
+
| Code | When |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| 0 | no tracked file is unreferenced |
|
|
41
|
+
| 1 | a tracked file is unreferenced or the repository holds no Knip configuration |
|
|
42
|
+
| 2 | the repository tracks no TypeScript source, Knip cannot run, or its configuration does not parse |
|
|
43
|
+
|
|
44
|
+
## Sample output
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
unused: 1 unreferenced file(s):
|
|
48
|
+
src/planted-dead.ts
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
A passing run counts the files it judged:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
unused: no unreferenced files among 110 tracked .ts/.tsx file(s)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Opting out
|
|
58
|
+
|
|
59
|
+
`checks-lint` runs this gate only when the repository tracks `.ts` or `.tsx` files.
|
|
60
|
+
A repository that tracks one names its entries in a Knip configuration.
|
|
61
|
+
|
|
62
|
+
## Related topics
|
|
63
|
+
|
|
64
|
+
- [checks-lint](checks-lint.md)
|
|
65
|
+
- [checks-repetition](checks-repetition.md)
|
package/knip-base.json
ADDED