Skip to content

Commit

Permalink
[New] no-extraneous-dependencies: added includeTypes option to vali…
Browse files Browse the repository at this point in the history
…date type imports

Fixes #2542
  • Loading branch information
bdwain committed Sep 4, 2022
1 parent 74f39d9 commit 395e26b
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
- [`no-anonymous-default-export`]: add `allowNew` option ([#2505], thanks [@DamienCassou])
- [`order`]: Add `distinctGroup` option ([#2395], thanks [@hyperupcall])
- [`no-extraneous-dependencies`]: Add `includeInternal` option ([#2541], thanks [@bdwain])
- [`no-extraneous-dependencies`]: Add `includeTypes` option ([#2543], thanks [@bdwain])

### Fixed
- [`order`]: move nested imports closer to main import entry ([#2396], thanks [@pri1311])
Expand Down
10 changes: 7 additions & 3 deletions docs/rules/no-extraneous-dependencies.md
@@ -1,7 +1,7 @@
# import/no-extraneous-dependencies: Forbid the use of extraneous packages

Forbid the import of external modules that are not declared in the `package.json`'s `dependencies`, `devDependencies`, `optionalDependencies`, `peerDependencies`, or `bundledDependencies`.
The closest parent `package.json` will be used. If no `package.json` is found, the rule will not lint anything. This behavior can be changed with the rule option `packageDir`. Normally ignores imports of modules marked internal, but this can be changed with the rule option `includeInternal`.
The closest parent `package.json` will be used. If no `package.json` is found, the rule will not lint anything. This behavior can be changed with the rule option `packageDir`. Normally ignores imports of modules marked internal, but this can be changed with the rule option `includeInternal`. Type imports can be verified by specifying `includeTypes`.

Modules have to be installed for this rule to work.

Expand Down Expand Up @@ -31,10 +31,10 @@ 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 matches a single glob in the array, and `false` otherwise.

There is a boolean option called `includeInternal`, which enables the checking of internal modules, which are otherwise ignored by this rule.
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/no-extraneous-dependencies": ["error", {"includeInternal": true}]
"import/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.
Expand Down Expand Up @@ -109,6 +109,9 @@ var foo = require('"@generated/foo"');
/* eslint import/no-extraneous-dependencies: ["error", {"includeInternal": true}] */
import foo from './foo';
var foo = require('./foo');

/* eslint import/no-extraneous-dependencies: ["error", {"includeTypes": true}] */
import type { MyType } from 'foo';
```


Expand All @@ -123,6 +126,7 @@ import test from 'ava';
import find from 'lodash.find';
import isArray from 'lodash.isarray';
import foo from '"@generated/foo"';
import type { MyType } from 'foo';

/* eslint import/no-extraneous-dependencies: ["error", {"peerDependencies": true}] */
import react from 'react';
Expand Down
8 changes: 5 additions & 3 deletions src/rules/no-extraneous-dependencies.js
Expand Up @@ -175,10 +175,10 @@ function checkDependencyDeclaration(deps, packageName, declarationStatus) {
}

function reportIfMissing(context, deps, depsOptions, node, name) {
// Do not report when importing types
// Do not report when importing types unless option is enabled
if (
node.importKind === 'type' ||
node.importKind === 'typeof'
!depsOptions.verifyTypeImports &&
(node.importKind === 'type' || node.importKind === 'typeof')
) {
return;
}
Expand Down Expand Up @@ -267,6 +267,7 @@ module.exports = {
'bundledDependencies': { 'type': ['boolean', 'array'] },
'packageDir': { 'type': ['string', 'array'] },
'includeInternal': { 'type': ['boolean'] },
'includeTypes': { 'type': ['boolean'] },
},
'additionalProperties': false,
},
Expand All @@ -284,6 +285,7 @@ module.exports = {
allowPeerDeps: testConfig(options.peerDependencies, filename) !== false,
allowBundledDeps: testConfig(options.bundledDependencies, filename) !== false,
verifyInternalDeps: !!options.includeInternal,
verifyTypeImports: !!options.includeTypes,
};

return moduleVisitor((source, node) => {
Expand Down
21 changes: 21 additions & 0 deletions tests/src/rules/no-extraneous-dependencies.js
Expand Up @@ -435,6 +435,18 @@ describe('TypeScript', () => {
message: "'a' should be listed in the project's dependencies, not devDependencies.",
}],
}, parserConfig)),

test(Object.assign({
code: 'import type T from "a";',
options: [{
packageDir: packageDirWithTypescriptDevDependencies,
devDependencies: false,
includeTypes: true,
}],
errors: [{
message: "'a' should be listed in the project's dependencies, not devDependencies.",
}],
}, parserConfig)),
],
});
});
Expand All @@ -454,5 +466,14 @@ typescriptRuleTester.run('no-extraneous-dependencies typescript type imports', r
}),
],
invalid: [
test({
code: 'import type { MyType } from "not-a-dependency";',
options: [{ includeTypes: true }],
filename: testFilePath('./no-unused-modules/typescript/file-ts-a.ts'),
parser: parsers.BABEL_OLD,
errors: [{
message: `'not-a-dependency' should be listed in the project's dependencies. Run 'npm i -S not-a-dependency' to add it`,
}],
}),
],
});

0 comments on commit 395e26b

Please sign in to comment.