Skip to content

build: add knip to find unused files, exports and dependencies - #142

Merged
botandbang merged 2 commits into
mainfrom
bnb/knip
Nov 10, 2026
Merged

botandbang merged 2 commits into
mainfrom
bnb/knip

Conversation

@botandbang

Copy link
Copy Markdown
Contributor

Adds knip 6.44.1 as a pinned root devDependency, a knip script, and runs it at the end of npm run lint. 6.44.1 is from Oct 31, well past the 3-day min-release-age gate in @lavamoat/harden's npm config (#140). The script passes --treat-config-hints-as-errors, so a stale exception in knip.jsonc (an ignored dependency that's no longer needed, say) fails lint instead of only printing a hint.

Adds knip.jsonc. Knip reads the npm workspaces itself and turns on its GitHub Actions, Node.js, oxlint, oxfmt and TypeScript plugins from what's installed, which covers most of the repo, so the config only holds what those can't see:

  • */types/** is ignored. These are generated by npm run types and published through each package's types field, which knip doesn't read as an entry.
  • tools/oxlint/anti-slop/** is ignored. It's the vendored oxlint plugin, and the same path is already excluded in .oxlintrc.json and docov.jsonc.
  • doc-kit.config.mjs and docs/theme/Navigation.jsx are root entries. doc-kit generate loads the config by its name, and the config points doc-kit at the theme by path. Without these, knip also reported @doc-kit/generator-react and @node-core/ui-components as unused, since only the theme imports them.
  • #theme/config and #theme/Logo are ignored as unresolved imports in the root. doc-kit's React generator defines those aliases while it builds.
  • @nodevu/* is ignored as a dependency of the root. test/types.mts imports the published packages through the workspace links.
  • @doc-kit/core is ignored as a dependency of the root. It's only a JSDoc type import in doc-kit.config.mjs, and @doc-kit/cli installs it.
  • luxon is ignored in fetchindex. Knip saw no import and called the devDependency unused, but the tests require core/util/prod/optionsParser.js, which requires luxon, and the CI coverage job installs only the workspace under test (npm ci -w fetchindex). Removing it would break that job.
  • luxon is ignored in static. static/test/test.build.js resolves core's own luxon on purpose, to stop the clock core reads, so it isn't a direct dependency.

Every package's exports stay public: knip treats each workspace's main as an entry and doesn't report what an entry exports.

Changes the CI lint job's install from npm ci --workspaces=false to plain npm ci, which installs the root and every workspace. With only the root installed, knip can't match c8 in each workspace's coverage script to the c8 package, and reports c8 as both unused and an unlisted binary in all nine workspaces that use it.

package-lock.json gains knip and the 58 packages it pulls in, added with npm i -D -E knip@6.44.1. Nothing already in the lockfile changed version.

The README's development section mentions npm run knip.

Removes, in a separate commit that comes first so the knip commit passes with hints as errors:

  • "main": "index.js" from the root package.json. There's no root index.js, and the root package isn't published (release.yml packs only the workspaces). Knip reported it as a missing entry file.

That was the only finding that was actually unused code. Before configuration, knip reported 14 unused files, 3 unused devDependencies, 11 unlisted dependencies, 1 unused export, 7 unused exported types and 1 configuration hint. All of them were generated types, vendored code or the cases above. After both commits, knip reports nothing.

Checked with npm run lint, npm run types (committed types unchanged), npm run coverage (100% in every package with coverage) and npm run docs. Adding an unused export to core/util/prod/schedule.js and an unused semver dependency to oldest made knip exit 1 with both reported. So did a stale left-pad entry in an ignoreDependencies list, reported as a configuration hint.

…ndex.js

The root package isn't published and has no index.js. knip, added next, reports it as a missing entry file.
knip runs as part of npm run lint and treats configuration hints as errors. knip.jsonc marks doc-kit's config-loaded files as entries and lists the generated types, the vendored oxlint plugin and the dependencies knip can't trace, each with the reason. The CI lint job now runs plain npm ci, which installs the workspaces too, so knip can match c8 in their scripts to its package.
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedknip@​6.44.1931009596100

View full report

@botandbang
botandbang merged commit 7cf7f26 into main Nov 10, 2026
40 checks passed
@botandbang
botandbang deleted the bnb/knip branch November 10, 2026 19:59
@nodevu-ci nodevu-ci Bot mentioned this pull request Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant