Repository navigation
Expand file tree
/
Copy pathknip.jsonc
More file actions
168 lines (159 loc) · 8.37 KB
/
Copy pathknip.jsonc
File metadata and controls
168 lines (159 loc) · 8.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
{
// Anti-dead-code gate: unused files, exports and types nothing imports, and
// dependencies declared but never used (plus the inverse). Run it with
// `npm run knip`; .github/workflows/knip.yml enforces it.
//
// Every issue type knip reports is an error by default, so this file sets no
// `rules`. There is no parked backlog either: `--max-issues 0` means the run
// must come back empty, and one new unused export fails the job.
//
// `--include nsExports,nsTypes` adds two types knip leaves out by default.
// Naming only those add-on types keeps every default type too, so one run
// covers them all.
//
// Run it the way CI does, against a tree with no build output: whether a
// workspace resolves `main`/`types` to a file that exists changes what knip
// reaches, so a run after a local `tsc --build` is no evidence the job will
// pass.
"$schema": "https://unpkg.com/knip@6/schema.json",
// Makes a stale exemption here fail the job instead of printing a hint below
// the backlog — an `ignoreDependencies` name that suppresses nothing, an
// `entry` that matches nothing or is already reached, an `ignoreWorkspaces`
// path that does not exist. Mind that last one: if the submodule directory
// below goes missing the hint fires advising you to drop the entry, which is
// the one thing not to do. Restore the directory instead.
"treatConfigHintsAsErrors": true,
// client.ts imports tool-args.generated.js, which the build writes (tool-server's
// src/sdk-tool-args.ts). CI runs knip unbuilt, where it does not resolve. An
// `ignoreUnresolved` entry would turn into a hint, and so an error, on a built
// tree; `ignoreIssues` passes in both. tsc still catches a broken import there.
"ignoreIssues": { "packages/argent/src/client.ts": ["unresolved"] },
// Ships from its own repo with its own CI, and eslint and prettier skip it the
// same way. It becomes a workspace the moment `git submodule update --init`
// puts a package.json where the root `packages/*` glob matches it.
"ignoreWorkspaces": ["packages/argent-private"],
// Host tools spawned by name, never npm packages. `skills` is the npm CLI
// that `npx` fetches on demand, deliberately not a dependency.
"ignoreBinaries": [
"ffmpeg",
"ffprobe",
"locale",
"netstat",
"pgrep",
"pkill",
"plutil",
"skills",
"tail",
"xctrace",
],
"workspaces": {
// Knip finds the root scripts on its own — via package.json `scripts`, the
// scripts/*.test.mjs files those run, and `run:` steps in .github/workflows.
// What its github-actions plugin cannot parse is a PowerShell body, so the
// Windows E2E driver, invoked from the windows-latest job where that is the
// default shell, is the one entry declared by hand.
//
// Knip analyzes JS and TS only, so the shell half of scripts/ — the whole
// scripts/e2e-full/ harness included — is outside the gate however it runs.
".": {
"entry": ["scripts/ci/windows-chromium-e2e.mjs"],
},
// @swmansion/argent is a thin dispatcher whose real payload is an esbuild
// bundle of the OTHER workspaces (see this workspace's
// scripts/bundle-tools.cjs); the hand-written dispatcher copied into bin/ at
// build time is an entry, not dead code.
//
// Knip cannot follow imports across that esbuild boundary, so a package
// consumed only by the bundled-in code reads as unused here. They are named
// one by one rather than waved through with a catch-all pattern:
// `ignoreDependencies` also suppresses `unlisted`, so a catch-all would take
// this workspace's own src/ and scripts/ out of that check — where an import
// with no matching declaration is a real bug, not a bundler artifact.
"packages/argent": {
"entry": ["scripts/argent-simulator-server.cjs"],
"ignoreDependencies": [
// dependencies
"@fails-components/webtransport",
// Not bundled-in code reaching it: @fails-components/webtransport
// imports this itself at runtime, so nothing first-party imports it.
"@fails-components/webtransport-transport-http3-quiche",
"@modelcontextprotocol/sdk",
"tree-sitter",
"tree-sitter-typescript",
// devDependencies
"@clack/prompts",
"@opentelemetry/api-logs",
"@opentelemetry/exporter-logs-otlp-http",
"@opentelemetry/resources",
"@opentelemetry/sdk-logs",
"picocolors",
"semver",
"smol-toml",
"yaml",
],
},
// tool-server reaches a few packages in ways knip can't trace statically.
// `ignoreDependencies` works in both directions, so this one list silences
// two different issue classes; they are kept apart below so each entry's
// stated reason matches the finding it actually suppresses. Each entry
// exempts the NAME across the whole workspace, not the call site it
// documents — while `sharp` is listed, an undeclared import of it from any
// file here passes too — so the list holds only packages this workspace
// genuinely cannot declare.
"packages/tool-server": {
// Reached only dynamically, so knip cannot see them: the executor puts
// the runner in front of the script as an `--import` preload by path, and
// the runner starts each watchdog with `new Worker(url)`.
"entry": [
// Run by the build as `node dist/sdk-tool-args.js`.
"src/sdk-tool-args.ts",
"src/tools/flows/script/flow-script-runner.mjs",
"src/tools/flows/script/flow-script-watchdog-lifeline.mjs",
"src/tools/flows/script/flow-script-watchdog-deadline.mjs",
],
"ignoreDependencies": [
// --- Declared in package.json, loaded too dynamically to detect.
// Without these: "unused dependencies". ---
// Dynamic `_require("tree-sitter")` / `_require("tree-sitter-typescript")`
// in react-profiler/pipeline/.../ast-index.ts, behind a one-shot flag.
"tree-sitter",
"tree-sitter-typescript",
// Optional peers of @swmansion/argent-cloud-sdk, which leaves them to
// the host to declare. utils/moq-client.ts calls the SDK's
// `installNodeWebTransport()`, but the dynamic import of the polyfill
// sits inside the SDK's own /node entry, so no first-party file names
// it; the transport is a second hop, imported by the polyfill itself.
"@fails-components/webtransport",
"@fails-components/webtransport-transport-http3-quiche",
// --- Imported here but deliberately absent from this package.json.
// Without these: "unlisted dependencies". ---
// Lazy `require("sharp")` in chromium-server/screenshot.ts. Kept out of
// the manifest on purpose so the ~30 MB native binary isn't a cost every
// consumer pays; the caller degrades gracefully when it isn't installed.
"sharp",
// `require("electron")` twice, for two different reasons. In
// utils/preview-window.ts it resolves the Electron executable's path
// from the install root, where it is an optionalDependency of the
// published @swmansion/argent. In test/fixtures/electron-smoke-app it
// is the Electron main-process API; that fixture declares electron in
// its own package.json and CI installs it there, but knip attributes
// the file to this workspace's manifest and never reads the nested one.
"electron",
],
},
},
// Blind spot in the `files` check: test files are entry points, so a
// production module that nothing but its own test imports still counts as
// reached — which in this repo is most of them. What `files` reliably catches
// is a module with no test at all. A file orphaned inside test/ is invisible
// for the same reason, knip's node plugin registering those trees as entries.
// `knip --production` is the lens that reports the whole class; the repo is
// not clean under it yet, so expect findings there that this gate does not
// raise.
//
// Reachability has a wider hole still: whatever a workspace's entry re-exports
// is reached, so one `export { x } from "./dead-module";` in a src/index.ts
// takes that module out of `files` altogether. The entry's own exports count
// as public API, members included, so a dead `ServiceState` member passes
// too. A clean run means nothing knip can see is dead — not that nothing is.
}