Back to Biomejs

noUndeclaredDependencies

src/content/docs/linter/rules/no-undeclared-dependencies.mdx

latest8.2 KB
Original Source

import { Tabs, TabItem } from '@astrojs/starlight/components';

<Tabs> <TabItem label="JavaScript (and super languages)" icon="seti:javascript"> :::note This rule belongs to the project domain. This means that its activation will activate the Biome Scanner to scan the files of your project. Read more about it in the [documentation page](/linter/domains#project) ::: ## Summary - Rule available since: `v1.6.0` - Diagnostic Category: [`lint/correctness/noUndeclaredDependencies`](/reference/diagnostics#diagnostic-category) - This rule isn't recommended, so you need to enable it. - This rule doesn't have a fix. - The default severity of this rule is [**error**](/reference/diagnostics#error). - This rule belongs to the following domains: - [`project`](/linter/domains#project) - Sources: - Same as [`import/no-extraneous-dependencies`](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md)

How to configure

json
{
	"linter": {
		"rules": {
			"correctness": {
				"noUndeclaredDependencies": "error"
			}
		}
	}
}

Description

Disallow the use of dependencies that aren't specified in the package.json.

Indirect dependencies will trigger the rule because they aren't declared in the package.json. This means that if the package @org/foo has a dependency on lodash, and then you use import "lodash" somewhere in your project, the rule will trigger a diagnostic for this import.

The rule is meant to catch those dependencies that aren't declared inside the closest package.json, and isn't meant to detect dependencies declared in other manifest files, e.g. the root package.json in a monorepo setting.

The rule ignores imports that are not valid package names. This includes internal imports that start with # and @/ and imports with a protocol such as node:, bun:, jsr:, https:.

To ensure that Visual Studio Code uses relative imports when it automatically imports a variable, you may set javascript.preferences.importModuleSpecifier and typescript.preferences.importModuleSpecifier to relative.

Examples

Invalid

json
{
  "dependencies": {}
}
js
import "vite";
<pre class="language-text"><code class="language-text"><a href="file:///index.js">/index.js</a>:1:8 <a href="https://biomejs.dev/linter/rules/no-undeclared-dependencies">lint/correctness/noUndeclaredDependencies</a> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ <strong><span style="color: Tomato;">✖</span></strong> <span style="color: Tomato;">Dependency </span><span style="color: Tomato;"><strong>vite</strong></span><span style="color: Tomato;"> isn't specified in </span><span style="color: Tomato;"><strong>/package.json</strong></span><span style="color: Tomato;">.</span> <strong><span style="color: Tomato;">&gt;</span></strong> <strong>1 │ </strong>import &quot;vite&quot;; <strong> │ </strong> <strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong> <strong>2 │ </strong> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">This could lead to errors.</span> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">Add the dependency in your manifest.</span> </code></pre>

Valid

json
{
  "dependencies": {
    "vite": "*"
  }
}
js
import "vite"; // package is correctly declared

import assert from "node:assert"; // Node imports don't need declaration

import { A } from "./local.js"; // relative imports don't trigger the rule
import { B } from "#alias"; // same goes for aliases

Options

This rule supports the following options:

  • devDependencies: If set to false, then the rule will show an error when devDependencies are imported. Defaults to true.
  • peerDependencies: If set to false, then the rule will show an error when peerDependencies are imported. Defaults to true.
  • optionalDependencies: If set to false, then the rule will show an error when optionalDependencies are imported. Defaults to true.

You can set the options like this:

json
{
	"linter": {
		"rules": {
			"correctness": {
				"noUndeclaredDependencies": {
					"options": {
						"devDependencies": false,
						"peerDependencies": false,
						"optionalDependencies": false
					}
				}
			}
		}
	}
}

You can also use an array of globs instead of literal booleans. When using an array of globs, the setting will be set to true (no errors reported) if the name of the file being linted (i.e. not the imported file/module) matches a single glob in the array, and false otherwise.

Example using the devDependencies option

In this example, only test files can use dependencies in the devDependencies section. dependencies, peerDependencies, and optionalDependencies are always available.

json
{
	"linter": {
		"rules": {
			"correctness": {
				"noUndeclaredDependencies": {
					"options": {
						"devDependencies": [
							"**/tests/*.test.js",
							"**/tests/*.spec.js"
						]
					}
				}
			}
		}
	}
}

json
{
  "devDependencies": {
    "vite": "*"
  }
}
js
// cannot import from a non-test file
import "vite";
<pre class="language-text"><code class="language-text"><a href="file:///src/index.js">/src/index.js</a>:2:8 <a href="https://biomejs.dev/linter/rules/no-undeclared-dependencies">lint/correctness/noUndeclaredDependencies</a> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ <strong><span style="color: Tomato;">✖</span></strong> <span style="color: Tomato;">Dependency </span><span style="color: Tomato;"><strong>vite</strong></span><span style="color: Tomato;"> isn't specified in </span><span style="color: Tomato;"><strong>/package.json</strong></span><span style="color: Tomato;">.</span> <strong>1 │ </strong>// cannot import from a non-test file <strong><span style="color: Tomato;">&gt;</span></strong> <strong>2 │ </strong>import &quot;vite&quot;; <strong> │ </strong> <strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong><strong><span style="color: Tomato;">^</span></strong> <strong>3 │ </strong> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;"><strong>vite</strong></span><span style="color: lightgreen;"> is part of your </span><span style="color: lightgreen;"><strong>devDependencies</strong></span><span style="color: lightgreen;">, but it's not intended to be used in this file.</span> <strong><span style="color: lightgreen;">ℹ</span></strong> <span style="color: lightgreen;">You may want to consider moving it to the </span><span style="color: lightgreen;"><strong>dependencies</strong></span><span style="color: lightgreen;"> section.</span> </code></pre>
js
// this works, because the file matches a glob from the options
import "vite";
</TabItem> </Tabs>