Skip to content

Commit

Permalink
Merge 5e143b2 into 813a116
Browse files Browse the repository at this point in the history
  • Loading branch information
schmidsi committed Sep 17, 2019
2 parents 813a116 + 5e143b2 commit b625117
Show file tree
Hide file tree
Showing 16 changed files with 74 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -10,6 +10,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel

### Added
- support `parseForESLint` from custom parser ([#1435], thanks [@JounQin])
- [`no-extraneous-dependencies`]: Implement support for [bundledDependencies](https://npm.github.io/using-pkgs-docs/package-json/types/bundleddependencies.html) ([#1436], thanks [@schmidsi]))

### Fixed
- `default`: make error message less confusing ([#1470], thanks [@golopot])
Expand Down Expand Up @@ -609,6 +610,7 @@ for info on changes for earlier releases.

[#1472]: https://github.com/benmosher/eslint-plugin-import/pull/1472
[#1470]: https://github.com/benmosher/eslint-plugin-import/pull/1470
[#1436]: https://github.com/benmosher/eslint-plugin-import/pull/1436
[#1435]: https://github.com/benmosher/eslint-plugin-import/pull/1435
[#1425]: https://github.com/benmosher/eslint-plugin-import/pull/1425
[#1419]: https://github.com/benmosher/eslint-plugin-import/pull/1419
Expand Down Expand Up @@ -986,3 +988,4 @@ for info on changes for earlier releases.
[@lencioni]: https://github.com/lencioni
[@JounQin]: https://github.com/JounQin
[@atikenny]: https://github.com/atikenny
[@schmidsi]: https://github.com/schmidsi
14 changes: 12 additions & 2 deletions docs/rules/no-extraneous-dependencies.md
@@ -1,6 +1,6 @@
# 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` or `peerDependencies`.
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 behaviour can be changed with the rule option `packageDir`.

Modules have to be installed for this rule to work.
Expand All @@ -15,6 +15,8 @@ This rule supports the following options:

`peerDependencies`: If set to `false`, then the rule will show an error when `peerDependencies` are imported. Defaults to `false`.

`bundledDependencies`: If set to `false`, then the rule will show an error when `bundledDependencies` are imported. Defaults to `true`.

You can set the options like this:

```js
Expand Down Expand Up @@ -70,7 +72,10 @@ Given the following `package.json`:
},
"peerDependencies": {
"react": ">=15.0.0 <16.0.0"
}
},
"bundledDependencies": [
"@generated/foo",
]
}
```

Expand All @@ -90,6 +95,10 @@ var test = require('ava');
/* eslint import/no-extraneous-dependencies: ["error", {"optionalDependencies": false}] */
import isArray from 'lodash.isarray';
var isArray = require('lodash.isarray');

/* eslint import/no-extraneous-dependencies: ["error", {"bundledDependencies": false}] */
import foo from '"@generated/foo"';
var foo = require('"@generated/foo"');
```


Expand All @@ -103,6 +112,7 @@ var foo = require('./foo');
import test from 'ava';
import find from 'lodash.find';
import isArray from 'lodash.isarray';
import foo from '"@generated/foo"';

/* eslint import/no-extraneous-dependencies: ["error", {"peerDependencies": true}] */
import react from 'react';
Expand Down
15 changes: 14 additions & 1 deletion src/rules/no-extraneous-dependencies.js
Expand Up @@ -11,12 +11,19 @@ function hasKeys(obj = {}) {
return Object.keys(obj).length > 0
}

function arrayOrKeys(arrayOrObject) {
return Array.isArray(arrayOrObject) ? arrayOrObject : Object.keys(arrayOrObject)
}

function extractDepFields(pkg) {
return {
dependencies: pkg.dependencies || {},
devDependencies: pkg.devDependencies || {},
optionalDependencies: pkg.optionalDependencies || {},
peerDependencies: pkg.peerDependencies || {},
// BundledDeps should be in the form of an array, but object notation is also supported by
// `npm`, so we convert it to an array if it is an object
bundledDependencies: arrayOrKeys(pkg.bundleDependencies || pkg.bundledDependencies || [])
}
}

Expand All @@ -28,6 +35,7 @@ function getDependencies(context, packageDir) {
devDependencies: {},
optionalDependencies: {},
peerDependencies: {},
bundledDependencies: [],
}

if (packageDir && packageDir.length > 0) {
Expand Down Expand Up @@ -63,6 +71,7 @@ function getDependencies(context, packageDir) {
packageContent.devDependencies,
packageContent.optionalDependencies,
packageContent.peerDependencies,
packageContent.bundledDependencies,
].some(hasKeys)) {
return null
}
Expand Down Expand Up @@ -121,11 +130,13 @@ function reportIfMissing(context, deps, depsOptions, node, name) {
const isInDevDeps = deps.devDependencies[packageName] !== undefined
const isInOptDeps = deps.optionalDependencies[packageName] !== undefined
const isInPeerDeps = deps.peerDependencies[packageName] !== undefined
const isInBundledDeps = deps.bundledDependencies.indexOf(packageName) !== -1

if (isInDeps ||
(depsOptions.allowDevDeps && isInDevDeps) ||
(depsOptions.allowPeerDeps && isInPeerDeps) ||
(depsOptions.allowOptDeps && isInOptDeps)
(depsOptions.allowOptDeps && isInOptDeps) ||
(depsOptions.allowBundledDeps && isInBundledDeps)
) {
return
}
Expand Down Expand Up @@ -169,6 +180,7 @@ module.exports = {
'devDependencies': { 'type': ['boolean', 'array'] },
'optionalDependencies': { 'type': ['boolean', 'array'] },
'peerDependencies': { 'type': ['boolean', 'array'] },
'bundledDependencies': { 'type': ['boolean', 'array'] },
'packageDir': { 'type': ['string', 'array'] },
},
'additionalProperties': false,
Expand All @@ -185,6 +197,7 @@ module.exports = {
allowDevDeps: testConfig(options.devDependencies, filename) !== false,
allowOptDeps: testConfig(options.optionalDependencies, filename) !== false,
allowPeerDeps: testConfig(options.peerDependencies, filename) !== false,
allowBundledDeps: testConfig(options.bundledDependencies, filename) !== false,
}

// todo: use module visitor from module-utils core
Expand Down
Empty file.
Empty file.
@@ -0,0 +1,4 @@
{
"dummy": true,
"bundleDependencies": ["@generated/foo"]
}
Empty file.
Empty file.
4 changes: 4 additions & 0 deletions tests/files/bundled-dependencies/as-object/package.json
@@ -0,0 +1,4 @@
{
"dummy": true,
"bundledDependencies": {"@generated/foo": "latest"}
}
Empty file.
Empty file.
5 changes: 5 additions & 0 deletions tests/files/bundled-dependencies/race-condition/package.json
@@ -0,0 +1,5 @@
{
"dummy": true,
"bundledDependencies": {"@generated/bar": "latest"},
"bundleDependencies": ["@generated/foo"]
}
Empty file.
Empty file.
3 changes: 2 additions & 1 deletion tests/files/package.json
Expand Up @@ -15,5 +15,6 @@
},
"optionalDependencies": {
"lodash.isarray": "^4.0.0"
}
},
"bundledDependencies": ["@generated/foo"]
}
30 changes: 30 additions & 0 deletions tests/src/rules/no-extraneous-dependencies.js
Expand Up @@ -18,6 +18,9 @@ const packageDirWithFlowTyped = path.join(__dirname, '../../files/with-flow-type
const packageDirMonoRepoRoot = path.join(__dirname, '../../files/monorepo')
const packageDirMonoRepoWithNested = path.join(__dirname, '../../files/monorepo/packages/nested-package')
const packageDirWithEmpty = path.join(__dirname, '../../files/empty')
const packageDirBundleDeps = path.join(__dirname, '../../files/bundled-dependencies/as-array-bundle-deps')
const packageDirBundledDepsAsObject = path.join(__dirname, '../../files/bundled-dependencies/as-object')
const packageDirBundledDepsRaceCondition = path.join(__dirname, '../../files/bundled-dependencies/race-condition')

ruleTester.run('no-extraneous-dependencies', rule, {
valid: [
Expand Down Expand Up @@ -106,6 +109,19 @@ ruleTester.run('no-extraneous-dependencies', rule, {
code: 'import rightpad from "right-pad";',
options: [{packageDir: [packageDirMonoRepoRoot, packageDirMonoRepoWithNested]}],
}),
test({ code: 'import foo from "@generated/foo"'}),
test({
code: 'import foo from "@generated/foo"',
options: [{packageDir: packageDirBundleDeps}],
}),
test({
code: 'import foo from "@generated/foo"',
options: [{packageDir: packageDirBundledDepsAsObject}],
}),
test({
code: 'import foo from "@generated/foo"',
options: [{packageDir: packageDirBundledDepsRaceCondition}],
}),
],
invalid: [
test({
Expand Down Expand Up @@ -289,5 +305,19 @@ ruleTester.run('no-extraneous-dependencies', rule, {
message: "'react' should be listed in the project's dependencies. Run 'npm i -S react' to add it",
}],
}),
test({
code: 'import bar from "@generated/bar"',
errors: ["'@generated/bar' should be listed in the project's dependencies. Run 'npm i -S @generated/bar' to add it"],
}),
test({
code: 'import foo from "@generated/foo"',
options: [{bundledDependencies: false}],
errors: ["'@generated/foo' should be listed in the project's dependencies. Run 'npm i -S @generated/foo' to add it"],
}),
test({
code: 'import bar from "@generated/bar"',
options: [{packageDir: packageDirBundledDepsRaceCondition}],
errors: ["'@generated/bar' should be listed in the project's dependencies. Run 'npm i -S @generated/bar' to add it"],
}),
],
})

0 comments on commit b625117

Please sign in to comment.