diff --git a/CHANGELOG.md b/CHANGELOG.md index dd858a3af..3351937a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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]) diff --git a/docs/rules/no-extraneous-dependencies.md b/docs/rules/no-extraneous-dependencies.md index 4d9f035d2..70c08809c 100644 --- a/docs/rules/no-extraneous-dependencies.md +++ b/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. @@ -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. @@ -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'; ``` @@ -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'; diff --git a/src/rules/no-extraneous-dependencies.js b/src/rules/no-extraneous-dependencies.js index 2e8b7fece..65c396e67 100644 --- a/src/rules/no-extraneous-dependencies.js +++ b/src/rules/no-extraneous-dependencies.js @@ -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; } @@ -267,6 +267,7 @@ module.exports = { 'bundledDependencies': { 'type': ['boolean', 'array'] }, 'packageDir': { 'type': ['string', 'array'] }, 'includeInternal': { 'type': ['boolean'] }, + 'includeTypes': { 'type': ['boolean'] }, }, 'additionalProperties': false, }, @@ -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) => { diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js index 364921db3..c1018a914 100644 --- a/tests/src/rules/no-extraneous-dependencies.js +++ b/tests/src/rules/no-extraneous-dependencies.js @@ -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)), ], }); }); @@ -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`, + }], + }), ], });