diff --git a/.changeset/light-apples-rhyme.md b/.changeset/light-apples-rhyme.md new file mode 100644 index 00000000..b6a135dd --- /dev/null +++ b/.changeset/light-apples-rhyme.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-import-x": minor +--- + +Add new option "whitelist" for rule "no-extraneous-dependencies" diff --git a/docs/rules/no-extraneous-dependencies.md b/docs/rules/no-extraneous-dependencies.md index 99068aaa..a16e9844 100644 --- a/docs/rules/no-extraneous-dependencies.md +++ b/docs/rules/no-extraneous-dependencies.md @@ -9,7 +9,7 @@ Modules have to be installed for this rule to work. ## Options -This rule supports the following options: +### Dependency Options `devDependencies`: If set to `false`, then the rule will show an error when `devDependencies` are imported. Defaults to `true`. Type imports are ignored by default. @@ -34,27 +34,41 @@ 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. +### Other Options + +#### `includeInternal` & `includeTypes` + There are 2 boolean options to opt into checking extra imports that are normally ignored: `includeInternal`, which enables the checking of internal modules, and `includeTypes`, which enables checking of type imports in TypeScript. ```js "import-x/no-extraneous-dependencies": ["error", {"includeInternal": true, "includeTypes": true}] ``` -Also there is one more option called `packageDir`, this option is to specify the path to the folder containing package.json. +#### `packageDir` + +The `packageDir` option is to specify the path to the folder containing package.json. If provided as a relative path string, will be computed relative to the current working directory at linter execution time. If this is not ideal (does not work with some editor integrations), consider using `__dirname` to provide a path relative to your configuration. ```js -"import-x/no-extraneous-dependencies": ["error", {"packageDir": './some-dir/'}] +"import-x/no-extraneous-dependencies": ["error", {"packageDir": "./some-dir/"}] // or -"import-x/no-extraneous-dependencies": ["error", {"packageDir": path.join(__dirname, 'some-dir')}] +"import-x/no-extraneous-dependencies": ["error", {"packageDir": path.join(__dirname, "some-dir")}] ``` It may also be an array of multiple paths, to support monorepos or other novel project folder layouts: ```js -"import-x/no-extraneous-dependencies": ["error", {"packageDir": ['./some-dir/', './root-pkg']}] +"import-x/no-extraneous-dependencies": ["error", {"packageDir": ["./some-dir/", "./root-pkg"]}] +``` + +#### `whitelist` + +The `whitelist` option is an optional string array to specify the names of packages that this rule should ignore. + +```js +"import-x/no-extraneous-dependencies": ["error", {"whitelist": ["foo", "bar"]}] ``` ## Rule Details diff --git a/src/rules/no-extraneous-dependencies.ts b/src/rules/no-extraneous-dependencies.ts index f91324ba..4046c4d6 100644 --- a/src/rules/no-extraneous-dependencies.ts +++ b/src/rules/no-extraneous-dependencies.ts @@ -215,6 +215,7 @@ function reportIfMissing( depsOptions: DepsOptions, node: TSESTree.Node, name: string, + whitelist: Set | undefined, ) { // Do not report when importing types unless option is enabled if ( @@ -292,6 +293,10 @@ function reportIfMissing( const packageName = realPackageName || importPackageName + if (whitelist?.has(packageName)) { + return + } + if (declarationStatus.isInDevDeps && !depsOptions.allowDevDeps) { context.report({ node, @@ -342,6 +347,7 @@ type Options = { bundledDependencies?: boolean includeInternal?: boolean includeTypes?: boolean + whitelist?: string[] } type MessageId = @@ -370,6 +376,7 @@ export = createRule<[Options?], MessageId>({ packageDir: { type: ['string', 'array'] }, includeInternal: { type: ['boolean'] }, includeTypes: { type: ['boolean'] }, + whitelist: { type: ['array'] }, }, additionalProperties: false, }, @@ -408,7 +415,14 @@ export = createRule<[Options?], MessageId>({ return { ...moduleVisitor( (source, node) => { - reportIfMissing(context, deps, depsOptions, node, source.value) + reportIfMissing( + context, + deps, + depsOptions, + node, + source.value, + options.whitelist ? new Set(options.whitelist) : undefined, + ) }, { commonjs: true }, ), diff --git a/test/rules/no-extraneous-dependencies.spec.ts b/test/rules/no-extraneous-dependencies.spec.ts index dc7d5fbb..aa0f0ee7 100644 --- a/test/rules/no-extraneous-dependencies.spec.ts +++ b/test/rules/no-extraneous-dependencies.spec.ts @@ -220,6 +220,14 @@ ruleTester.run('no-extraneous-dependencies', rule, { }, }, }), + + test({ + code: 'import "not-a-dependency"', + filename: path.join(packageDirMonoRepoRoot, 'foo.js'), + options: [ + { packageDir: packageDirMonoRepoRoot, whitelist: ['not-a-dependency'] }, + ], + }), ], invalid: [ test({