@avi2dg/checks 0.56.0 → 0.56.1

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 CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  Every release of `@avi2dg/checks`, newest first, written by the release from its conventional commits.
4
4
 
5
+ ## 0.56.1
6
+
7
+ Released 2026-10-27.
8
+
9
+ ### Fixes
10
+
11
+ - **complexity:** merge unused, exports and imports walks into one pass [#12](https://github.com/avi2d/checks/pull/12)
12
+
5
13
  ## 0.56.0
6
14
 
7
15
  Released 2026-10-27.
package/docs/bins.md CHANGED
@@ -19,8 +19,7 @@ The table groups the gates by vector, the part of a repository each one judges.
19
19
  | --- | --- | --- | --- |
20
20
  | complexity | [`checks-suppressions-ratchet`](gates/checks-suppressions-ratchet.md) | the range | every repository |
21
21
  | complexity | [`checks-repetition`](gates/checks-repetition.md) | the range | a repository tracking `*.ts` or `*.tsx` |
22
- | complexity | [`checks-unused`](gates/checks-unused.md) | the working tree | a repository tracking `*.ts` or `*.tsx` or `*.astro` |
23
- | complexity | [`checks-exports`](gates/checks-exports.md) | the range | a repository tracking `*.ts` or `*.tsx` |
22
+ | complexity | [`checks-graphwalk`](gates/checks-graphwalk.md) | the range | a repository tracking `*.ts` or `*.tsx` or `*.astro` |
24
23
  | quality | [`checks-lint-coverage`](gates/checks-lint-coverage.md) | the working tree | a repository tracking `*.ts` or `*.tsx` or `*.astro` |
25
24
  | quality | [`checks-comment-gate`](gates/checks-comment-gate.md) | the range | every repository |
26
25
  | quality | [`checks-effect-scope`](gates/checks-effect-scope.md) | the working tree | a repository tracking `oxlint.config.ts` |
@@ -34,7 +33,6 @@ The table groups the gates by vector, the part of a repository each one judges.
34
33
  | delivery | [`checks-commit-identity`](gates/checks-commit-identity.md) | the range | every repository |
35
34
  | delivery | [`checks-ci-wiring`](gates/checks-ci-wiring.md) | the working tree | every repository |
36
35
  | delivery | [`checks-secrets`](gates/checks-secrets.md) | the range | every repository |
37
- | dependencies | [`checks-imports`](gates/checks-imports.md) | the working tree | a repository tracking `*.ts` or `*.tsx` |
38
36
  | dependencies | [`checks-advisories`](gates/checks-advisories.md) | the range | a repository tracking `bun.lock` |
39
37
 
40
38
  <!-- end generated gates -->
@@ -11,7 +11,7 @@ The kit's dependency-cruiser rules hold a repository's imports, and a repository
11
11
  `defineConfig` from `@avi2dg/checks/dependency-cruiser` returns these rules, with or without a config of the repository's own:
12
12
 
13
13
  - `no-circular`
14
- - `no-orphans`, which a repository that depends on `astro` gets only by listing its own, as [checks-imports](../gates/checks-imports.md) explains
14
+ - `no-orphans`, which a repository that depends on `astro` gets only by listing its own, as [checks-graphwalk](../gates/checks-graphwalk.md) explains
15
15
  - `not-to-dev-dep`, which refuses shipped source importing a dev-only package, and a package listed in `peerDependencies` too is not dev-only
16
16
  - `no-non-package-json`, which refuses an import of an installed package that the nearest `package.json` does not declare, and counts a peer that `peerDependenciesMeta` marks optional as declared
17
17
  - `not-to-unresolvable`, which refuses a specifier nothing installed answers
@@ -61,9 +61,9 @@ A rule under `forbidden` that takes a kit rule's name replaces that rule whole,
61
61
 
62
62
  ## Running it
63
63
 
64
- `checks-lint` runs [checks-imports](../gates/checks-imports.md) in the full run, which cruises every tracked TypeScript file against `dependency-cruiser.config.ts`, or against the kit's defaults when the repository holds no config.
64
+ `checks-lint` runs [checks-graphwalk](../gates/checks-graphwalk.md) in the full run, which cruises every tracked TypeScript file against `dependency-cruiser.config.ts`, or against the kit's defaults when the repository holds no config.
65
65
 
66
66
  ## Related topics
67
67
 
68
- - [checks-imports](../gates/checks-imports.md)
68
+ - [checks-graphwalk](../gates/checks-graphwalk.md)
69
69
  - [Why it is shaped this way](../design.md)
@@ -14,11 +14,11 @@ A consuming repository puts each setting in the file its tool reads, and no mani
14
14
  | `oxlint.config.ts` | Effect paths and their exemptions, ignore patterns, and any rule or budget the repository sets over the kit's defaults | oxlint and `checks-effect-scope` |
15
15
  | `oxlint-suppressions.json` | The existing violations oxlint suppresses, per file and rule | oxlint and `checks-suppressions-ratchet` |
16
16
  | `stylelint-suppressions.json` | The existing violations stylelint suppresses, per file and rule | stylelint, `checks-frontend-syntax` and `checks-suppressions-ratchet` |
17
- | `exports-baseline.json` | The existing unused exports and types, per file, kind and name | `checks-exports` |
17
+ | `exports-baseline.json` | The existing unused exports and types, per file, kind and name | `checks-graphwalk` |
18
18
  | `.jscpd.json` | The `path` and `ignore` globs of the files repetition is measured in | jscpd and `checks-repetition` |
19
- | `knip.config.ts` | The `entry` globs Knip traces unreferenced files from | Knip, `checks-unused` and `checks-exports` |
19
+ | `knip.config.ts` | The `entry` globs Knip traces unreferenced files from | Knip and `checks-graphwalk` |
20
20
  | `stylelint.config.ts` | The Baseline target, the token files, the CSS families the repository turns on, and any stylelint rule the repository sets over the kit's families | `checks-frontend-syntax` |
21
- | `dependency-cruiser.config.ts` | Entry points nothing imports, paths that may import dev dependencies, and import boundaries, when the kit's defaults do not fit | `checks-imports` |
21
+ | `dependency-cruiser.config.ts` | Entry points nothing imports, paths that may import dev dependencies, and import boundaries, when the kit's defaults do not fit | `checks-graphwalk` |
22
22
  | `tsconfig.json` | Compiler options, and the Effect language service plugin whose `overrides` and kit severities `checks-effect-scope` writes, keeping every other key | TypeScript and Effect language service |
23
23
  | `package.json` | `scripts` with the `checks-vendor` arguments in `prepare`, `author` and `contributors` | Bun, `checks-commit-identity` and `checks-vendor` |
24
24
  | `bunfig.toml` | Test discovery and quarantine exclusion | Bun and `checks-test-layout` |
@@ -69,7 +69,7 @@ import { defineConfig } from "@avi2dg/checks/knip";
69
69
  export default defineConfig({ entry: ["src/index.ts"] });
70
70
  ```
71
71
 
72
- `dependency-cruiser.config.ts` is optional, since `checks-imports` cruises against the kit's defaults without one:
72
+ `dependency-cruiser.config.ts` is optional, since `checks-graphwalk` cruises against the kit's defaults without one:
73
73
 
74
74
  ```ts
75
75
  import { defineConfig } from "@avi2dg/checks/dependency-cruiser";
package/docs/design.md CHANGED
@@ -125,9 +125,9 @@ A gate then behaves the same alone or through `checks-lint`, and `lint-coverage.
125
125
  The gates run one at a time and pass their output straight through, so each report reads whole and in the order of the gate table.
126
126
  `checks-lint` picks the gates that apply from the tracked files for the full run, and a repository cannot select gates.
127
127
  A scoped run selects a subset by changed paths, and the desk run selects the fast tree gates.
128
- A TypeScript gate applies as soon as the repository tracks TypeScript source, and `checks-lint-coverage` and `checks-unused` also apply on tracked Astro source.
128
+ A TypeScript gate applies as soon as the repository tracks TypeScript source, and `checks-lint-coverage` and `checks-graphwalk` also apply on tracked Astro source.
129
129
 
130
- dependency-cruiser runs as the `checks-imports` gate rather than as a script each repository adds to `lint`, so the full run keeps it.
130
+ dependency-cruiser runs inside the `checks-graphwalk` gate rather than as a script each repository adds to `lint`, so the full run keeps it.
131
131
  A repository with no config of its own is cruised against the kit's defaults, since every rule has one.
132
132
  The gate cruises the tracked TypeScript, so a build output or a linked library outside git never reaches the cruise.
133
133
  It runs dependency-cruiser under Bun, which loads a TypeScript config wherever it sits, the kit's defaults under `node_modules` among them.
@@ -0,0 +1,126 @@
1
+ ---
2
+ kind: reference
3
+ audience: consumers
4
+ ---
5
+ # checks-graphwalk
6
+
7
+ `checks-graphwalk` is the gate that judges unreferenced files, unused exports and import violations together, running Knip once over the working tree for unreferenced files and unused exports and dependency-cruiser once for import violations, plus Knip once more on the base checkout when the range adds baseline entries.
8
+
9
+ ## What it checks
10
+
11
+ It runs Knip once with the repository's own configuration and names each `.ts`, `.tsx` or `.astro` file no entry reaches.
12
+ It names each exported value and type no file imports from the same run, so one graph build feeds both findings.
13
+ It reads only the files, exports and types issue types, so an unused dependency never fails it.
14
+ It asks Knip for those issue types itself, so a configuration that narrows `include` or excludes them still judges them.
15
+ A configuration that turns the exports or types rules off silences those symbols, so keep both rules on.
16
+ A configuration that turns the files rule off still has its files judged.
17
+ It holds each reported symbol against `exports-baseline.json`, and fails on any symbol the baseline does not hold.
18
+ It fails on any baseline entry the range adds unless Knip reports that same symbol unused at the base, so the baseline records debt that already existed and never debt the range creates.
19
+ It fails on any baseline entry Knip no longer reports, so the baseline only shrinks.
20
+ It runs dependency-cruiser over every tracked `.ts`, `.tsx`, `.mts` and `.cts` file and names each violation with its rule, the importing module and the module it reaches.
21
+ It fails on a violation whose rule has `error` severity, and lists a `warn` or `info` violation without failing.
22
+ It fails when the repository tracks no `.ts`, `.tsx`, `.astro`, `.mts` or `.cts` file, since an empty scan would pass without judging anything.
23
+ It fails when the repository holds no Knip configuration, since Knip's default entries cannot tell a dead file from an entry point.
24
+
25
+ In a repository whose `package.json` lists `astro` under `dependencies` or `devDependencies`, the kit's defaults leave `no-orphans` out.
26
+ The cruise never reads an `.astro` file, so a `.ts` module only a page imports would read as an orphan.
27
+ The unreferenced-files section already names each file no entry reaches there, and it reads `.astro` imports.
28
+ A repository that wants the rule back lists its own `no-orphans` under `forbidden` in `dependency-cruiser.config.ts`.
29
+
30
+ ## What it reads
31
+
32
+ It runs Knip and dependency-cruiser over the working tree, so an uncommitted file is judged like a committed one.
33
+ It reads the repository's Knip configuration, which names the entries.
34
+ The repository writes `knip.config.ts` with the kit's builder, which requires `entry`, the files nothing imports:
35
+
36
+ ```ts
37
+ import { defineConfig } from "@avi2dg/checks/knip";
38
+
39
+ export default defineConfig({ entry: ["src/index.ts"] });
40
+ ```
41
+
42
+ The builder sets `include` to unreferenced files alone, and adds `tests/**/*.test.ts`, `dependency-cruiser.config.ts` and `oxlint.config.ts` to the entries.
43
+ In a repository that depends on `astro`, Knip reads `.astro` imports, so a file only an `.astro` entry imports counts as used and an `.astro` file no entry reaches is named.
44
+ The gate resolves the Knip binary from the installed kit, so a consumer installs nothing beyond the kit.
45
+ It reads `exports-baseline.json` in the repository root, which holds each accepted unused export as a file, kind and name triple.
46
+ It reads `exports-baseline.json` again at the base of the range, where a commit without the file counts as empty.
47
+ When the range adds baseline entries, it runs Knip again on a temporary checkout of the base and removes the checkout when it ends.
48
+ That checkout links the repository's `node_modules`, so a configuration importing the kit's builder loads there too.
49
+ It cruises against the first config it finds there:
50
+
51
+ 1. `dependency-cruiser.config.ts`, which calls `defineConfig` from `@avi2dg/checks/dependency-cruiser`.
52
+ 1. A config under one of dependency-cruiser's own names, such as `.dependency-cruiser.cjs`.
53
+ 1. The kit's defaults, which `defineConfig()` returns with no argument.
54
+
55
+ It runs dependency-cruiser from the installed kit under Bun, which loads a TypeScript config wherever it sits.
56
+ It leaves out a tracked file the working tree no longer holds.
57
+
58
+ ## Arguments
59
+
60
+ ```sh
61
+ checks-graphwalk
62
+ checks-graphwalk <ref>
63
+ checks-graphwalk <base-ref> <head-ref>
64
+ checks-graphwalk --write
65
+ ```
66
+
67
+ With no argument it judges `HEAD` alone.
68
+ With one the base is that commit's parent, or the empty tree for a repository's first commit, where nothing counts as already unused.
69
+ With two arguments the base is where the head branched off, at their merge-base.
70
+ When the checked-out commit is a merge of the head ref and one other commit, as a pull request's default checkout is, the base is that other commit instead.
71
+ So under `checks-lint` a pull request's merge checkout is judged against the base branch tip it merges, and a symbol that branch already baselined does not count as added.
72
+ With `--write` it records every unused export and type Knip reports into `exports-baseline.json`, the way `oxlint --suppress-all` seeds `oxlint-suppressions.json`.
73
+
74
+ A repository adopting the gate runs `checks-graphwalk --write` on a branch that changes no source and commits the file it writes.
75
+ The gate passes that range, since Knip reports every seeded symbol unused at the base too.
76
+ A seed written after the range adds a dead export, or after it removes the last import of one, fails on that symbol.
77
+
78
+ ## Exit codes
79
+
80
+ | Code | When |
81
+ | --- | --- |
82
+ | 0 | no file is unreferenced, no symbol is unlisted, added or stale, and no import breaks an `error` rule, or `--write` recorded the baseline |
83
+ | 1 | a file is unreferenced, a symbol is unlisted, added or stale, an import breaks an `error` rule, or the repository holds no Knip configuration |
84
+ | 2 | a ref does not resolve, a scanner cannot run, or a Knip report, a cruise report or the baseline does not parse |
85
+
86
+ The gate exits 1 when any section reports a violation, and exits 2 only when no section reports one and at least one section cannot decide.
87
+
88
+ It also exits 2 when the repository tracks no `.ts`, `.tsx`, `.astro`, `.mts` or `.cts` file, or, with `--write`, when it tracks no TypeScript file.
89
+ A repository that tracks `.astro` files but no `.ts`, `.tsx`, `.mts` or `.cts` file prints only the unreferenced-files section.
90
+
91
+ ## Sample output
92
+
93
+ ```
94
+ unused: 1 unreferenced file(s):
95
+ src/dead.ts
96
+ exports: 2 unused export(s) not in exports-baseline.json:
97
+ src/used.ts: unusedExport (export)
98
+ src/used.ts: UnusedOptions (type)
99
+ imports: 1 violation(s) in 5 module(s) cruised against the kit's defaults
100
+ error no-orphans: src/dead.ts
101
+ ```
102
+
103
+ A passing run counts what each section judged:
104
+
105
+ ```
106
+ unused: no unreferenced files among 3 tracked .ts/.tsx/.astro file(s)
107
+ exports: no unused exports or types
108
+ imports: 3 module(s) cruised against the kit's defaults, no violation
109
+ ```
110
+
111
+ A passing run with a held baseline counts what it holds:
112
+
113
+ ```
114
+ exports: 2 unused export(s) in exports-baseline.json, and no new ones
115
+ ```
116
+
117
+ ## When it runs
118
+
119
+ `checks-lint` runs it over each pull request's range when the repository tracks a `.ts`, `.tsx` or `.astro` file.
120
+ Such a repository names its entries in a Knip configuration.
121
+
122
+ ## Related topics
123
+
124
+ - [checks-lint](checks-lint.md)
125
+ - [checks-repetition](checks-repetition.md)
126
+ - [The dependency rules](../configs/dependency-rules.md)
@@ -15,7 +15,7 @@ A Markdown change runs the range gates plus `checks-copy`.
15
15
  A TypeScript source change runs every applicable gate.
16
16
  A test file classifies as TypeScript, so its change runs every applicable gate too.
17
17
  Gates requiring tracked TypeScript files begin running when the repository tracks TypeScript.
18
- `checks-lint-coverage` and `checks-unused` also begin running when the repository tracks an `.astro` file.
18
+ `checks-lint-coverage` and `checks-graphwalk` also begin running when the repository tracks an `.astro` file.
19
19
  `checks-advisories` begins running when the repository tracks `bun.lock`.
20
20
  `checks-lint` defers its scan to the scheduled run, so the desk and the pull request fetch no database.
21
21
  `checks-frontend-syntax` begins running when the repository tracks `frontend-syntax.json` at its root.
@@ -58,7 +58,7 @@ With two arguments, the base and head override range discovery.
58
58
 
59
59
  ```
60
60
  checks-lint: range 2504acf098d120e73a8ece3c96f22b934f35c6a8..10ba7d8935b73ed72624120a1542e51bd21ca7c7 from HEAD against origin/main
61
- checks-lint: 1 of 19 gate(s) failed: checks-comment-gate
61
+ checks-lint: 1 of 17 gate(s) failed: checks-comment-gate
62
62
  ```
63
63
 
64
64
  <!-- end generated lint-sample -->
@@ -66,7 +66,7 @@ checks-lint: 1 of 19 gate(s) failed: checks-comment-gate
66
66
  ## When it runs
67
67
 
68
68
  A repository runs it from `bun run lint` in a pull request workflow that fetches the whole git history.
69
- It leaves out the TypeScript gates while the repository tracks no TypeScript file, except that `checks-lint-coverage` and `checks-unused` run when it tracks an `.astro` file.
69
+ It leaves out the TypeScript gates while the repository tracks no TypeScript file, except that `checks-lint-coverage` and `checks-graphwalk` run when it tracks an `.astro` file.
70
70
  It never runs `checks-browser`, which a product runs after it builds its site.
71
71
  A pull request run scopes the gates to the change.
72
72
 
@@ -57,4 +57,4 @@ no-plain-js: 2 violation(s)
57
57
 
58
58
  - [checks-lint](checks-lint.md)
59
59
  - [checks-test-layout](checks-test-layout.md)
60
- - [checks-unused](checks-unused.md)
60
+ - [checks-graphwalk](checks-graphwalk.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avi2dg/checks",
3
- "version": "0.56.0",
3
+ "version": "0.56.1",
4
4
  "description": "Deterministic checks shared across a set of TypeScript repositories",
5
5
  "author": {
6
6
  "name": "avi2d",
@@ -90,8 +90,7 @@
90
90
  "src/quality/browser/",
91
91
  "src/complexity/suppressions-ratchet.ts",
92
92
  "src/complexity/repetition.ts",
93
- "src/complexity/unused.ts",
94
- "src/complexity/exports.ts",
93
+ "src/complexity/graphwalk.ts",
95
94
  "src/complexity/knip.ts",
96
95
  "src/testing/quarantine-clock.ts",
97
96
  "src/docs/sentence-length.ts",
@@ -121,7 +120,6 @@
121
120
  "src/quality/presets/stylelint.ts",
122
121
  "src/quality/effect-scope.ts",
123
122
  "src/quality/jsonc-patch.ts",
124
- "src/dependencies/imports.ts",
125
123
  "src/dependencies/kit-defaults.ts",
126
124
  "oxlintrc.json",
127
125
  "stryker.preset.js",
@@ -188,8 +186,7 @@
188
186
  "checks-css-size": "src/quality/css-size.ts",
189
187
  "checks-suppressions-ratchet": "src/complexity/suppressions-ratchet.ts",
190
188
  "checks-repetition": "src/complexity/repetition.ts",
191
- "checks-unused": "src/complexity/unused.ts",
192
- "checks-exports": "src/complexity/exports.ts",
189
+ "checks-graphwalk": "src/complexity/graphwalk.ts",
193
190
  "checks-quarantine-clock": "src/testing/quarantine-clock.ts",
194
191
  "checks-docs": "src/docs/docs.ts",
195
192
  "checks-copy": "src/docs/copy.ts",
@@ -201,7 +198,6 @@
201
198
  "checks-frontend-syntax": "src/quality/frontend-syntax.ts",
202
199
  "checks-no-plain-js": "src/quality/no-plain-js.ts",
203
200
  "checks-browser": "src/quality/browser/browser.ts",
204
- "checks-imports": "src/dependencies/imports.ts",
205
201
  "checks-effect-scope": "src/quality/effect-scope.ts"
206
202
  },
207
203
  "scripts": {