diff --git a/packages/eslint-config-airbnb/README.md b/packages/eslint-config-airbnb/README.md index 4cf7f50b..9d4cfd85 100644 --- a/packages/eslint-config-airbnb/README.md +++ b/packages/eslint-config-airbnb/README.md @@ -11,23 +11,24 @@ We export three ESLint configurations for your usage. ### eslint-config-airbnb Our default export contains all of our ESLint rules, including EcmaScript 6+ -and React. It requires `eslint`, `eslint-plugin-react`, and `eslint-plugin-jsx-a11y`. +and React. It requires `eslint`, `eslint-plugin-import`, `eslint-plugin-react`, +and `eslint-plugin-jsx-a11y`. -1. `npm install --save-dev eslint-config-airbnb eslint-plugin-react eslint-plugin-jsx-a11y eslint` +1. `npm install --save-dev eslint-config-airbnb eslint-plugin-import eslint-plugin-react eslint-plugin-jsx-a11y eslint` 2. add `"extends": "airbnb"` to your .eslintrc ### eslint-config-airbnb/base Lints ES6+ but does not lint React. Requires `eslint`. -1. `npm install --save-dev eslint-config-airbnb eslint` +1. `npm install --save-dev eslint-config-airbnb eslint-plugin-import eslint` 2. add `"extends": "airbnb/base"` to your .eslintrc ### eslint-config-airbnb/legacy Lints ES5 and below. Only requires `eslint`. -1. `npm install --save-dev eslint-config-airbnb eslint` +1. `npm install --save-dev eslint-config-airbnb eslint-plugin-import eslint` 2. add `"extends": "airbnb/legacy"` to your .eslintrc See [Airbnb's Javascript styleguide](https://github.com/airbnb/javascript) and diff --git a/packages/eslint-config-airbnb/package.json b/packages/eslint-config-airbnb/package.json index 88d8d425..6c8a89d2 100644 --- a/packages/eslint-config-airbnb/package.json +++ b/packages/eslint-config-airbnb/package.json @@ -45,6 +45,7 @@ "babel-tape-runner": "^1.3.1", "eslint": "^2.7.0", "eslint-plugin-jsx-a11y": "^0.6.2", + "eslint-plugin-import": "^1.4.0", "eslint-plugin-react": "^4.3.0", "react": "^0.14.8", "tape": "^4.5.1", @@ -53,6 +54,7 @@ "peerDependencies": { "eslint": "^2.7.0", "eslint-plugin-jsx-a11y": "^0.6.2", + "eslint-plugin-import": "^1.4.0", "eslint-plugin-react": "^4.3.0" } } diff --git a/packages/eslint-config-airbnb/rules/es6.js b/packages/eslint-config-airbnb/rules/es6.js index 3045f4cd..7ac09522 100644 --- a/packages/eslint-config-airbnb/rules/es6.js +++ b/packages/eslint-config-airbnb/rules/es6.js @@ -11,6 +11,9 @@ module.exports = { 'objectLiteralDuplicateProperties': false } }, + 'plugins': [ + 'import' + ], 'rules': { // enforces no braces where they can be omitted // http://eslint.org/docs/rules/arrow-body-style @@ -83,6 +86,19 @@ module.exports = { 'template-curly-spacing': 2, // enforce spacing around the * in yield* expressions // http://eslint.org/docs/rules/yield-star-spacing - 'yield-star-spacing': [2, 'after'] + 'yield-star-spacing': [2, 'after'], + // disallow invalid exports, e.g. multiple defaults + // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/export.md + 'import/export': 2, + // ensure imports point to files/modules that can be resolved + // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md + 'import/no-unresolved': [2, { 'commonjs': true }] + }, + 'settings': { + 'import/resolver': { + 'node': { + 'extensions': ['.js', '.json'] + } + } } }; diff --git a/packages/eslint-config-airbnb/rules/node.js b/packages/eslint-config-airbnb/rules/node.js index 16b6f20d..2114c377 100644 --- a/packages/eslint-config-airbnb/rules/node.js +++ b/packages/eslint-config-airbnb/rules/node.js @@ -2,6 +2,9 @@ module.exports = { 'env': { 'node': true }, + 'plugins': [ + 'import' + ], 'rules': { // enforce return after a callback 'callback-return': 0, @@ -18,6 +21,16 @@ module.exports = { // restrict usage of specified node modules 'no-restricted-modules': 0, // disallow use of synchronous methods (off by default) - 'no-sync': 0 + 'no-sync': 0, + // ensure imports point to files/modules that can be resolved + // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md + 'import/no-unresolved': [2, { 'commonjs': true }] + }, + 'settings': { + 'import/resolver': { + 'node': { + 'extensions': ['.js', '.json'] + } + } } }; diff --git a/packages/eslint-config-airbnb/rules/react.js b/packages/eslint-config-airbnb/rules/react.js index a452feba..c05d575e 100644 --- a/packages/eslint-config-airbnb/rules/react.js +++ b/packages/eslint-config-airbnb/rules/react.js @@ -166,5 +166,12 @@ module.exports = { assignment: true, return: true }], + }, + 'settings': { + 'import/resolver': { + 'node': { + 'extensions': ['.js', '.jsx', '.json'] + } + } } }; diff --git a/packages/eslint-config-airbnb/test/test-base.js b/packages/eslint-config-airbnb/test/test-base.js index 24aa884c..c29e89dd 100644 --- a/packages/eslint-config-airbnb/test/test-base.js +++ b/packages/eslint-config-airbnb/test/test-base.js @@ -20,7 +20,10 @@ Object.keys(files).forEach(name => { test(`${name}: does not reference react`, t => { t.plan(2); - t.notOk(config.plugins, 'plugins is unspecified'); + // scan plugins for react and fail if it is found + const hasReactPlugin = Object.prototype.hasOwnProperty.call(config, 'plugins') && + config.plugins.indexOf('react') !== -1; + t.notOk(hasReactPlugin, 'there is no react plugin'); // scan rules for react/ and fail if any exist const reactRuleIds = Object.keys(config.rules)