From 3a7d4a32b4200bf054b572e9fc252bdf61b26a89 Mon Sep 17 00:00:00 2001 From: Jeroen Engels Date: Sat, 9 Jul 2016 15:09:27 +0200 Subject: [PATCH 1/4] `no-extraneous-dependencies`: add support/option for `peerDependencies` (#423) --- CHANGELOG.md | 4 +++ docs/rules/no-extraneous-dependencies.md | 13 ++++++++-- src/rules/no-extraneous-dependencies.js | 26 ++++++++++++------- tests/src/rules/no-extraneous-dependencies.js | 13 ++++++++++ 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 572b33d0b..8b74334c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). ## [Unreleased] +### Added +- Added an `peerDependencies` option to [`no-extraneous-dependencies`] to allow/forbid peer dependencies ([#423], [#428]). ## [1.10.3] - 2016-07-08 @@ -252,6 +254,7 @@ for info on changes for earlier releases. [`prefer-default-export`]: ./docs/rules/prefer-default-export.md [`no-restricted-paths`]: ./docs/rules/no-restricted-paths.md +[#428]: https://github.com/benmosher/eslint-plugin-import/pull/428 [#395]: https://github.com/benmosher/eslint-plugin-import/pull/395 [#371]: https://github.com/benmosher/eslint-plugin-import/pull/371 [#365]: https://github.com/benmosher/eslint-plugin-import/pull/365 @@ -285,6 +288,7 @@ for info on changes for earlier releases. [#157]: https://github.com/benmosher/eslint-plugin-import/pull/157 [#314]: https://github.com/benmosher/eslint-plugin-import/pull/314 +[#423]: https://github.com/benmosher/eslint-plugin-import/issues/423 [#415]: https://github.com/benmosher/eslint-plugin-import/issues/415 [#386]: https://github.com/benmosher/eslint-plugin-import/issues/386 [#373]: https://github.com/benmosher/eslint-plugin-import/issues/373 diff --git a/docs/rules/no-extraneous-dependencies.md b/docs/rules/no-extraneous-dependencies.md index 2504c0320..9f83d496b 100644 --- a/docs/rules/no-extraneous-dependencies.md +++ b/docs/rules/no-extraneous-dependencies.md @@ -1,6 +1,6 @@ # Forbid the use of extraneous packages -Forbid the import of external modules that are not declared in the `package.json`'s `dependencies` or `devDependencies`. +Forbid the import of external modules that are not declared in the `package.json`'s `dependencies`, `devDependencies`, `optionalDependencies` or `peerDependencies`. The closest parent `package.json` will be used. If no `package.json` is found, the rule will not lint anything. ### Options @@ -9,11 +9,12 @@ 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`. `optionalDependencies`: If set to `false`, then the rule will show an error when `optionalDependencies` are imported. Defaults to `true`. +`peerDependencies`: If set to `false`, then the rule will show an error when `peerDependencies` are imported. Defaults to `false`. You can set the options like this: ```js -"import/no-extraneous-dependencies": ["error", {"devDependencies": false, "optionalDependencies": false}] +"import/no-extraneous-dependencies": ["error", {"devDependencies": false, "optionalDependencies": false, "peerDependencies": false}] ``` @@ -38,6 +39,9 @@ Given the following `package.json`: }, "optionalDependencies": { "lodash.isarray": "^4.0.0" + }, + "peerDependencies": { + "react": ">=15.0.0 <16.0.0" } } ``` @@ -49,6 +53,8 @@ Given the following `package.json`: var _ = require('lodash'); import _ from 'lodash'; +import react from 'react'; + /* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": false}] */ import test from 'ava'; var test = require('ava'); @@ -69,6 +75,9 @@ var foo = require('./foo'); import test from 'ava'; import find from 'lodash.find'; import find from 'lodash.isarray'; + +/* 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 becbad092..55d905054 100644 --- a/src/rules/no-extraneous-dependencies.js +++ b/src/rules/no-extraneous-dependencies.js @@ -15,6 +15,7 @@ function getDependencies(context) { dependencies: packageContent.dependencies || {}, devDependencies: packageContent.devDependencies || {}, optionalDependencies: packageContent.optionalDependencies || {}, + peerDependencies: packageContent.peerDependencies || {}, } } catch (e) { return null @@ -35,7 +36,7 @@ function optDepErrorMessage(packageName) { `not optionalDependencies.` } -function reportIfMissing(context, deps, allowDevDeps, allowOptDeps, node, name) { +function reportIfMissing(context, deps, depsOptions, node, name) { if (importType(name, context) !== 'external') { return } @@ -47,20 +48,22 @@ function reportIfMissing(context, deps, allowDevDeps, allowOptDeps, node, name) const isInDeps = deps.dependencies[packageName] !== undefined const isInDevDeps = deps.devDependencies[packageName] !== undefined const isInOptDeps = deps.optionalDependencies[packageName] !== undefined + const isInPeerDeps = deps.peerDependencies[packageName] === undefined if (isInDeps || - (allowDevDeps && isInDevDeps) || - (allowOptDeps && isInOptDeps) + (depsOptions.allowDevDeps && isInDevDeps) || + (depsOptions.allowPeerDeps && isInPeerDeps) || + (depsOptions.allowOptDeps && isInOptDeps) ) { return } - if (isInDevDeps && !allowDevDeps) { + if (isInDevDeps && !depsOptions.allowDevDeps) { context.report(node, devDepErrorMessage(packageName)) return } - if (isInOptDeps && !allowOptDeps) { + if (isInOptDeps && !depsOptions.allowOptDeps) { context.report(node, optDepErrorMessage(packageName)) return } @@ -70,22 +73,26 @@ function reportIfMissing(context, deps, allowDevDeps, allowOptDeps, node, name) module.exports = function (context) { const options = context.options[0] || {} - const allowDevDeps = options.devDependencies !== false - const allowOptDeps = options.optionalDependencies !== false const deps = getDependencies(context) if (!deps) { return {} } + const depsOptions = { + allowDevDeps: options.devDependencies !== false, + allowOptDeps: options.optionalDependencies !== false, + allowPeerDeps: options.peerDependencies === true, + } + // todo: use module visitor from module-utils core return { ImportDeclaration: function (node) { - reportIfMissing(context, deps, allowDevDeps, allowOptDeps, node, node.source.value) + reportIfMissing(context, deps, depsOptions, node, node.source.value) }, CallExpression: function handleRequires(node) { if (isStaticRequire(node)) { - reportIfMissing(context, deps, allowDevDeps, allowOptDeps, node, node.arguments[0].value) + reportIfMissing(context, deps, depsOptions, node, node.arguments[0].value) } }, } @@ -97,6 +104,7 @@ module.exports.schema = [ 'properties': { 'devDependencies': { 'type': 'boolean' }, 'optionalDependencies': { 'type': 'boolean' }, + 'peerDependencies': { 'type': 'boolean' }, }, 'additionalProperties': false, }, diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js index 669446414..b62449152 100644 --- a/tests/src/rules/no-extraneous-dependencies.js +++ b/tests/src/rules/no-extraneous-dependencies.js @@ -24,6 +24,11 @@ ruleTester.run('no-extraneous-dependencies', rule, { test({ code: 'import "@scope/core"'}), test({ code: 'import "electron"', settings: { 'import/core-modules': ['electron'] } }), + test({ + code: 'import "eslint"', + options: [{peerDependencies: true}], + settings: { 'import/resolver': { node: { paths: [ path.join(__dirname, '../../files') ] } } }, + }), // 'project' type test({ @@ -84,6 +89,14 @@ ruleTester.run('no-extraneous-dependencies', rule, { message: '\'eslint\' should be listed in the project\'s dependencies, not devDependencies.', }], }), + test({ + code: 'var eslint = require("eslint")', + options: [{devDependencies: false, peerDependencies: false}], + errors: [{ + ruleId: 'no-extraneous-dependencies', + message: '\'eslint\' should be listed in the project\'s dependencies, not devDependencies.', + }], + }), test({ code: 'var eslint = require("lodash.isarray")', options: [{optionalDependencies: false}], From 72245487ec3579bac0a04bad4b7f16fe8ce0bfc4 Mon Sep 17 00:00:00 2001 From: Jeroen Engels Date: Sun, 10 Jul 2016 20:05:31 +0200 Subject: [PATCH 2/4] Set peerDependencies to true by default --- src/rules/no-extraneous-dependencies.js | 4 ++-- tests/files/package.json | 1 + tests/src/rules/no-extraneous-dependencies.js | 15 +++------------ 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/rules/no-extraneous-dependencies.js b/src/rules/no-extraneous-dependencies.js index 55d905054..059307e04 100644 --- a/src/rules/no-extraneous-dependencies.js +++ b/src/rules/no-extraneous-dependencies.js @@ -48,7 +48,7 @@ function reportIfMissing(context, deps, depsOptions, node, name) { const isInDeps = deps.dependencies[packageName] !== undefined const isInDevDeps = deps.devDependencies[packageName] !== undefined const isInOptDeps = deps.optionalDependencies[packageName] !== undefined - const isInPeerDeps = deps.peerDependencies[packageName] === undefined + const isInPeerDeps = deps.peerDependencies[packageName] !== undefined if (isInDeps || (depsOptions.allowDevDeps && isInDevDeps) || @@ -82,7 +82,7 @@ module.exports = function (context) { const depsOptions = { allowDevDeps: options.devDependencies !== false, allowOptDeps: options.optionalDependencies !== false, - allowPeerDeps: options.peerDependencies === true, + allowPeerDeps: options.peerDependencies !== false, } // todo: use module visitor from module-utils core diff --git a/tests/files/package.json b/tests/files/package.json index d0ef9601b..7aaed30f3 100644 --- a/tests/files/package.json +++ b/tests/files/package.json @@ -1,6 +1,7 @@ { "dummy": true, "devDependencies": { + "glob": "1.0.0", "eslint": "2.x" }, "peerDependencies": { diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js index b62449152..0e5e97c85 100644 --- a/tests/src/rules/no-extraneous-dependencies.js +++ b/tests/src/rules/no-extraneous-dependencies.js @@ -27,7 +27,6 @@ ruleTester.run('no-extraneous-dependencies', rule, { test({ code: 'import "eslint"', options: [{peerDependencies: true}], - settings: { 'import/resolver': { node: { paths: [ path.join(__dirname, '../../files') ] } } }, }), // 'project' type @@ -60,7 +59,7 @@ ruleTester.run('no-extraneous-dependencies', rule, { }), test({ code: 'import "eslint"', - options: [{devDependencies: false}], + options: [{devDependencies: false, peerDependencies: false}], errors: [{ ruleId: 'no-extraneous-dependencies', message: '\'eslint\' should be listed in the project\'s dependencies, not devDependencies.', @@ -82,19 +81,11 @@ ruleTester.run('no-extraneous-dependencies', rule, { }], }), test({ - code: 'var eslint = require("eslint")', + code: 'var glob = require("glob")', options: [{devDependencies: false}], errors: [{ ruleId: 'no-extraneous-dependencies', - message: '\'eslint\' should be listed in the project\'s dependencies, not devDependencies.', - }], - }), - test({ - code: 'var eslint = require("eslint")', - options: [{devDependencies: false, peerDependencies: false}], - errors: [{ - ruleId: 'no-extraneous-dependencies', - message: '\'eslint\' should be listed in the project\'s dependencies, not devDependencies.', + message: '\'glob\' should be listed in the project\'s dependencies, not devDependencies.', }], }), test({ From 3f9cec86d469d023184f85baf9490274bbb55381 Mon Sep 17 00:00:00 2001 From: Jeroen Engels Date: Sun, 10 Jul 2016 20:07:09 +0200 Subject: [PATCH 3/4] Add test case --- tests/src/rules/no-extraneous-dependencies.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js index 0e5e97c85..5d5ead1a5 100644 --- a/tests/src/rules/no-extraneous-dependencies.js +++ b/tests/src/rules/no-extraneous-dependencies.js @@ -23,6 +23,10 @@ ruleTester.run('no-extraneous-dependencies', rule, { test({ code: 'import "lodash.isarray"'}), test({ code: 'import "@scope/core"'}), + test({ code: 'import "electron"', settings: { 'import/core-modules': ['electron'] } }), + test({ + code: 'import "eslint"', + }), test({ code: 'import "electron"', settings: { 'import/core-modules': ['electron'] } }), test({ code: 'import "eslint"', From 08e2c2a72b031dd8a1d8bbfe4cb15d65d2d8b73d Mon Sep 17 00:00:00 2001 From: Jeroen Engels Date: Wed, 13 Jul 2016 13:26:48 +0200 Subject: [PATCH 4/4] Remove duplicate test --- tests/src/rules/no-extraneous-dependencies.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js index 5d5ead1a5..f0b43b09b 100644 --- a/tests/src/rules/no-extraneous-dependencies.js +++ b/tests/src/rules/no-extraneous-dependencies.js @@ -24,10 +24,7 @@ ruleTester.run('no-extraneous-dependencies', rule, { test({ code: 'import "@scope/core"'}), test({ code: 'import "electron"', settings: { 'import/core-modules': ['electron'] } }), - test({ - code: 'import "eslint"', - }), - test({ code: 'import "electron"', settings: { 'import/core-modules': ['electron'] } }), + test({ code: 'import "eslint"' }), test({ code: 'import "eslint"', options: [{peerDependencies: true}],