From 2e047e65882e265c821822e45b31b8bf3b7e50d3 Mon Sep 17 00:00:00 2001 From: Attila Bartha Date: Sat, 7 Sep 2019 18:03:48 +0100 Subject: [PATCH] [New] `group-exports`: make aggregate module exports valid --- CHANGELOG.md | 5 +++++ docs/rules/group-exports.md | 12 ++++++++++++ package.json | 1 + src/rules/group-exports.js | 21 ++++++++++++++++++++- tests/src/rules/group-exports.js | 14 ++++++++++++++ 5 files changed, 52 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f9173017..822efcebb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ## [Unreleased] +### Added +- [`group-exports`]: make aggregate module exports valid ([#1472], thanks [@atikenny]) + ### Added - support `parseForESLint` from custom parser ([#1435], thanks [@JounQin]) @@ -604,6 +607,7 @@ for info on changes for earlier releases. [`memo-parser`]: ./memo-parser/README.md +[#1472]: https://github.com/benmosher/eslint-plugin-import/pull/1472 [#1470]: https://github.com/benmosher/eslint-plugin-import/pull/1470 [#1435]: https://github.com/benmosher/eslint-plugin-import/pull/1435 [#1425]: https://github.com/benmosher/eslint-plugin-import/pull/1425 @@ -981,3 +985,4 @@ for info on changes for earlier releases. [@sharmilajesupaul]: https://github.com/sharmilajesupaul [@lencioni]: https://github.com/lencioni [@JounQin]: https://github.com/JounQin +[@atikenny]: https://github.com/atikenny diff --git a/docs/rules/group-exports.md b/docs/rules/group-exports.md index b0d88f4a0..f61ff5306 100644 --- a/docs/rules/group-exports.md +++ b/docs/rules/group-exports.md @@ -26,6 +26,12 @@ export { } ``` +```js +// Aggregating exports -> ok +export { default as module1 } from 'module-1' +export { default as module2 } from 'module-2' +``` + ```js // A single exports assignment -> ok module.exports = { @@ -63,6 +69,12 @@ export const first = true export const second = true ``` +```js +// Aggregating exports from the same module -> not ok! +export { module1 } from 'module-1' +export { module2 } from 'module-1' +``` + ```js // Multiple exports assignments -> not ok! exports.first = true diff --git a/package.json b/package.json index ec4efc1ee..f395ffc0e 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ }, "dependencies": { "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", "contains-path": "^0.1.0", "debug": "^2.6.9", "doctrine": "1.5.0", diff --git a/src/rules/group-exports.js b/src/rules/group-exports.js index d650fff87..cd7fc992d 100644 --- a/src/rules/group-exports.js +++ b/src/rules/group-exports.js @@ -1,4 +1,6 @@ import docsUrl from '../docsUrl' +import values from 'object.values' +import flat from 'array.prototype.flat' const meta = { type: 'suggestion', @@ -46,11 +48,18 @@ function create(context) { const nodes = { modules: new Set(), commonjs: new Set(), + sources: {}, } return { ExportNamedDeclaration(node) { - nodes.modules.add(node) + if (!node.source) { + nodes.modules.add(node) + } else if (Array.isArray(nodes.sources[node.source.value])) { + nodes.sources[node.source.value].push(node) + } else { + nodes.sources[node.source.value] = [node] + } }, AssignmentExpression(node) { @@ -86,6 +95,16 @@ function create(context) { }) } + // Report multiple `aggregated exports` from the same module (ES2015 modules) + flat(values(nodes.sources) + .filter(nodesWithSource => Array.isArray(nodesWithSource) && nodesWithSource.length > 1)) + .forEach((node) => { + context.report({ + node, + message: errors[node.type], + }) + }) + // Report multiple `module.exports` assignments (CommonJS) if (nodes.commonjs.size > 1) { nodes.commonjs.forEach(node => { diff --git a/tests/src/rules/group-exports.js b/tests/src/rules/group-exports.js index 3b08997e3..9a0c2c1ba 100644 --- a/tests/src/rules/group-exports.js +++ b/tests/src/rules/group-exports.js @@ -45,6 +45,10 @@ ruleTester.run('group-exports', rule, { // test export default {} ` }), + test({ code: ` + export { default as module1 } from './module-1' + export { default as module2 } from './module-2' + ` }), test({ code: 'module.exports = {} '}), test({ code: ` module.exports = { test: true, @@ -111,6 +115,16 @@ ruleTester.run('group-exports', rule, { errors.named, ], }), + test({ + code: ` + export { method1 } from './module-1' + export { method2 } from './module-1' + `, + errors: [ + errors.named, + errors.named, + ], + }), test({ code: ` module.exports = {}