From 33c1027ddc237853d08ebe7f31afd4de83610673 Mon Sep 17 00:00:00 2001 From: Zamiell <5511220+Zamiell@users.noreply.github.com> Date: Sat, 31 Aug 2024 10:29:21 -0400 Subject: [PATCH 1/7] feat: whitelist --- docs/rules/no-extraneous-dependencies.md | 24 +++++++++++++++++++----- src/rules/no-extraneous-dependencies.ts | 10 +++++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/rules/no-extraneous-dependencies.md b/docs/rules/no-extraneous-dependencies.md index 99068aaaa..a16e9844f 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 f91324bae..da1957a58 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: string[], ) { // Do not report when importing types unless option is enabled if ( @@ -292,6 +293,10 @@ function reportIfMissing( const packageName = realPackageName || importPackageName + if (whitelist.includes(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 = @@ -405,10 +411,12 @@ export = createRule<[Options?], MessageId>({ verifyTypeImports: !!options.includeTypes, } + const whitelist = options.whitelist ?? []; + return { ...moduleVisitor( (source, node) => { - reportIfMissing(context, deps, depsOptions, node, source.value) + reportIfMissing(context, deps, depsOptions, node, source.value, whitelist) }, { commonjs: true }, ), From 5315a9690662ed826755ac1b5bcffb29cd38127a Mon Sep 17 00:00:00 2001 From: Zamiell <5511220+Zamiell@users.noreply.github.com> Date: Sat, 31 Aug 2024 10:37:01 -0400 Subject: [PATCH 2/7] chore: changeset --- .changeset/light-apples-rhyme.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/light-apples-rhyme.md diff --git a/.changeset/light-apples-rhyme.md b/.changeset/light-apples-rhyme.md new file mode 100644 index 000000000..b6a135dda --- /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" From e4661a99f517b0cb76c35d3d3ede6b59354f29d7 Mon Sep 17 00:00:00 2001 From: James <5511220+Zamiell@users.noreply.github.com> Date: Sat, 31 Aug 2024 12:55:48 -0400 Subject: [PATCH 3/7] Update no-extraneous-dependencies.ts --- src/rules/no-extraneous-dependencies.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rules/no-extraneous-dependencies.ts b/src/rules/no-extraneous-dependencies.ts index da1957a58..f6f30c78e 100644 --- a/src/rules/no-extraneous-dependencies.ts +++ b/src/rules/no-extraneous-dependencies.ts @@ -294,7 +294,7 @@ function reportIfMissing( const packageName = realPackageName || importPackageName if (whitelist.includes(packageName)) { - return; + return } if (declarationStatus.isInDevDeps && !depsOptions.allowDevDeps) { @@ -411,7 +411,7 @@ export = createRule<[Options?], MessageId>({ verifyTypeImports: !!options.includeTypes, } - const whitelist = options.whitelist ?? []; + const whitelist = options.whitelist ?? [] return { ...moduleVisitor( From f258a4b2529881e7320639f32c00fb01a5d9e098 Mon Sep 17 00:00:00 2001 From: James <5511220+Zamiell@users.noreply.github.com> Date: Sat, 31 Aug 2024 12:56:22 -0400 Subject: [PATCH 4/7] Update no-extraneous-dependencies.ts --- src/rules/no-extraneous-dependencies.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/rules/no-extraneous-dependencies.ts b/src/rules/no-extraneous-dependencies.ts index f6f30c78e..b928c5246 100644 --- a/src/rules/no-extraneous-dependencies.ts +++ b/src/rules/no-extraneous-dependencies.ts @@ -416,7 +416,14 @@ export = createRule<[Options?], MessageId>({ return { ...moduleVisitor( (source, node) => { - reportIfMissing(context, deps, depsOptions, node, source.value, whitelist) + reportIfMissing( + context, + deps, + depsOptions, + node, + source.value, + whitelist, + ) }, { commonjs: true }, ), From 847dfabcb1defa0b7afc23b15c129f0547444d6a Mon Sep 17 00:00:00 2001 From: SukkaW Date: Sun, 1 Sep 2024 12:27:09 +0800 Subject: [PATCH 5/7] perf: use set over array --- src/rules/no-extraneous-dependencies.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/rules/no-extraneous-dependencies.ts b/src/rules/no-extraneous-dependencies.ts index b928c5246..6b907c51e 100644 --- a/src/rules/no-extraneous-dependencies.ts +++ b/src/rules/no-extraneous-dependencies.ts @@ -215,7 +215,7 @@ function reportIfMissing( depsOptions: DepsOptions, node: TSESTree.Node, name: string, - whitelist: string[], + whitelist: Set | undefined, ) { // Do not report when importing types unless option is enabled if ( @@ -293,7 +293,7 @@ function reportIfMissing( const packageName = realPackageName || importPackageName - if (whitelist.includes(packageName)) { + if (whitelist?.has(packageName)) { return } @@ -411,8 +411,6 @@ export = createRule<[Options?], MessageId>({ verifyTypeImports: !!options.includeTypes, } - const whitelist = options.whitelist ?? [] - return { ...moduleVisitor( (source, node) => { @@ -422,7 +420,7 @@ export = createRule<[Options?], MessageId>({ depsOptions, node, source.value, - whitelist, + options.whitelist ? new Set(options.whitelist) : undefined, ) }, { commonjs: true }, From 11625e5ccb7adbe80c4fae0a761f65d6c655031b Mon Sep 17 00:00:00 2001 From: Zamiell <5511220+Zamiell@users.noreply.github.com> Date: Sun, 1 Sep 2024 07:52:17 -0400 Subject: [PATCH 6/7] feat: add whitelist test --- src/rules/no-extraneous-dependencies.ts | 1 + test/rules/no-extraneous-dependencies.spec.ts | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/rules/no-extraneous-dependencies.ts b/src/rules/no-extraneous-dependencies.ts index 6b907c51e..4046c4d6c 100644 --- a/src/rules/no-extraneous-dependencies.ts +++ b/src/rules/no-extraneous-dependencies.ts @@ -376,6 +376,7 @@ export = createRule<[Options?], MessageId>({ packageDir: { type: ['string', 'array'] }, includeInternal: { type: ['boolean'] }, includeTypes: { type: ['boolean'] }, + whitelist: { type: ['array'] }, }, additionalProperties: false, }, diff --git a/test/rules/no-extraneous-dependencies.spec.ts b/test/rules/no-extraneous-dependencies.spec.ts index dc7d5fbb4..4c13739a9 100644 --- a/test/rules/no-extraneous-dependencies.spec.ts +++ b/test/rules/no-extraneous-dependencies.spec.ts @@ -220,6 +220,12 @@ 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({ From 40fcc997720d508d8d96fcf03a13e823ef86ff0b Mon Sep 17 00:00:00 2001 From: SukkaW Date: Wed, 4 Sep 2024 19:30:22 +0800 Subject: [PATCH 7/7] chore: make lint happy --- test/rules/no-extraneous-dependencies.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/rules/no-extraneous-dependencies.spec.ts b/test/rules/no-extraneous-dependencies.spec.ts index 4c13739a9..aa0f0ee73 100644 --- a/test/rules/no-extraneous-dependencies.spec.ts +++ b/test/rules/no-extraneous-dependencies.spec.ts @@ -224,7 +224,9 @@ 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"] }], + options: [ + { packageDir: packageDirMonoRepoRoot, whitelist: ['not-a-dependency'] }, + ], }), ], invalid: [