Skip to content

Commit

Permalink
no-extraneous-dependencies: add support/option for `peerDependencie…
Browse files Browse the repository at this point in the history
…s` (#423)
  • Loading branch information
jfmengels committed Jul 13, 2016
1 parent 9fc3351 commit 3a7d4a3
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
13 changes: 11 additions & 2 deletions docs/rules/no-extraneous-dependencies.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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}]
```


Expand All @@ -38,6 +39,9 @@ Given the following `package.json`:
},
"optionalDependencies": {
"lodash.isarray": "^4.0.0"
},
"peerDependencies": {
"react": ">=15.0.0 <16.0.0"
}
}
```
Expand All @@ -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');
Expand All @@ -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';
```


Expand Down
26 changes: 17 additions & 9 deletions src/rules/no-extraneous-dependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function getDependencies(context) {
dependencies: packageContent.dependencies || {},
devDependencies: packageContent.devDependencies || {},
optionalDependencies: packageContent.optionalDependencies || {},
peerDependencies: packageContent.peerDependencies || {},
}
} catch (e) {
return null
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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)
}
},
}
Expand All @@ -97,6 +104,7 @@ module.exports.schema = [
'properties': {
'devDependencies': { 'type': 'boolean' },
'optionalDependencies': { 'type': 'boolean' },
'peerDependencies': { 'type': 'boolean' },
},
'additionalProperties': false,
},
Expand Down
13 changes: 13 additions & 0 deletions tests/src/rules/no-extraneous-dependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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}],
Expand Down

0 comments on commit 3a7d4a3

Please sign in to comment.