feat: add dev-dependency-in-production rule#1740
Merged
BartWaardenburg merged 2 commits intoJul 5, 2026
Merged
Conversation
d56747d to
4d21402
Compare
Flag a package in devDependencies that is imported by production (non-test, non-config) source code via a runtime/value import, so it can be promoted to dependencies. A production-only install (pnpm install --prod) omits devDependencies, so such an import breaks at runtime. This is the promote-side mirror of the existing test-only-dependency and type-only-dependency rules. Detection reuses the prod-vs-test file partition and the per-import value/type accounting already used by the sibling rules: - flag only when a production file has a runtime (value) import - do not flag type-only production imports (erased at build time) - do not flag imports that come only from test/config files - skip workspace packages, known tooling (@types/*, typescript, ...), ignoreDependencies entries, and packages also declared in dependencies / peerDependencies / optionalDependencies Default severity warn; gated by the dev-dependencies-in-production rule key; suppress a package with ignoreDependencies. Wired through human, JSON, SARIF, Code Climate, compact, and markdown output, fallow explain, the LSP diagnostic surface, the GitHub Action / GitLab CI jq summaries, the VS Code extension, regression baselines, and the generated contracts. Adds a fixture, integration test, and unit tests covering the flag and each abstain path.
Filter parity: clear dev_dependencies_in_production in the --unused-deps clear arm and the --file scoping path like every sibling dependency kind, and render devDependenciesInProduction in the TOML regression baseline so a saved fallow.toml baseline does not report a phantom regression. Detection: only count imports from files reachable from a RUNTIME entry point (repo tooling like scripts/, benchmarks/, and rollup-config chains is not production evidence), skip files owned by a workspace package (root-manifest scope; a hoisted root devDep declared in the workspace's own dependencies is not a misplacement), and keep the rule active in production mode where its signal is cleanest. Surfaces: align jq summary labels with the registry label (drift gate), add the kind to the action drift-guard fallback table, the VS Code status bar registry, and the @fallow/node typings; drop the never-released prod-usage-of-dev-dependency alias; strip the CHANGELOG em-dash and document the runtime-reachability semantics and known limitations.
4d21402 to
fc979d7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a new
dev-dependency-in-productionrule: a package indevDependenciesthat is imported by production (non-test, non-config) source code via a runtime/value import is flagged so it can be promoted todependencies. It is the promote-side mirror of the existingtest-only-dependencyandtype-only-dependencyrules.Detection (
crates/core/src/analyze/unused_deps.rs::find_dev_dependencies_in_production) reuses the existing prod-vs-test file partition and the per-import value/type accounting the sibling detectors already rely on:type-only-dependency);test-only-dependency's job);@types/*,typescript, …),ignoreDependenciesentries, and packages also declared independencies/peerDependencies/optionalDependencies.Default severity
warn; rule keydev-dependencies-in-production; suppress a package viaignoreDependencies. Wired through the full analyzer contract per the analyzer-authoring guide:IssueKind+issue_metarows,RulesConfig, theDevDependencyInProductionstruct +Findingwrapper +move-to-prodaction, human / JSON / SARIF / Code Climate / compact / markdown output,fallow explain, the LSP diagnostic, regression baselines, the GitHub Action + GitLab CI jq summaries, the VS Code extension, and all generated contracts (schema.json, output schema, npm registry/capabilities, TS types, SKILL.md).Why
Closes #1738.
Fallow catches dependency demotion drift but not promotion drift. A devDependency value-imported from production code passes silently today —
unlisted-dependencydoesn't fire because the package is listed, just under the wrong section — yetpnpm install --prodomits it and the import breaks at runtime.Repro before this change:
After: the same project reports
dev-dependency-in-productionforyamland exits 1 under--fail-on-issues, while a type-only import or a test-only import stays silent.Test plan
cargo test --workspace,cargo clippy --workspace --all-targets -- -D warnings,cargo fmt --all -- --check— green.tests/fixtures/dev-dep-in-prod+crates/core/tests/integration_test/dev_dep_in_prod.rs) proving the value-import flag and the type-only / test-only / prod-dependency abstains end to end viafallow_core::analyze.crates/core/src/analyze/unused_deps_tests/dev_dep_in_prod.rs) covering the flag plus each abstain path (type-only, test-only, ignored, workspace, known-tooling, peer-dependency).npm run generate:contracts:check,action/tests/run.sh(415 passed),ci/tests/run.sh(317 passed), and the VS Code vitest suite (615 passed) all pass.Note: this rule checks the root
package.jsonagainst the project-wide import graph, matching the existingtest-only/type-onlydetectors; true per-workspace attribution is a shared follow-up across all three dependency-family rules.Just a first pass, I didn't see anything against AI-aided contributions in CONTRIBUTING.md – happy to close this or for more knowledgeable contributors to update if a more expert human contribution is desired.