From c40912ad374aa47f00e2c9577f39b1f37e338039 Mon Sep 17 00:00:00 2001 From: Jeroen Engels Date: Mon, 9 May 2016 11:13:43 +0200 Subject: [PATCH 1/6] `no-mutable-exports`: Handle ES7 export extensions. Fixes #317 --- src/rules/no-mutable-exports.js | 2 +- tests/src/rules/no-mutable-exports.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/rules/no-mutable-exports.js b/src/rules/no-mutable-exports.js index ba403d7155..e6173bf11c 100644 --- a/src/rules/no-mutable-exports.js +++ b/src/rules/no-mutable-exports.js @@ -31,7 +31,7 @@ module.exports = function (context) { if (node.declaration) { checkDeclaration(node.declaration) - } else { + } else if (!node.source) { for (let specifier of node.specifiers) { checkDeclarationsInScope(scope, specifier.local.name) } diff --git a/tests/src/rules/no-mutable-exports.js b/tests/src/rules/no-mutable-exports.js index 14f1ef7c77..d3874b7972 100644 --- a/tests/src/rules/no-mutable-exports.js +++ b/tests/src/rules/no-mutable-exports.js @@ -24,6 +24,10 @@ ruleTester.run('no-mutable-exports', rule, { test({ code: 'class Counter {}\nexport { Counter as Count }'}), test({ code: 'class Counter {}\nexport default Counter'}), test({ code: 'class Counter {}\nexport { Counter as default }'}), + test({ + parser: 'babel-eslint', + code: 'export Something from "./something";', + }), ], invalid: [ test({ From 4d80295721d3a223c277c0dc804ce2268f4a3e66 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Mon, 9 May 2016 06:51:56 -0400 Subject: [PATCH 2/6] changelog note for #317 + #322 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ead5df2889..12c699911c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). +## [Unreleased] +### Fixed +- ignore namespace / ES7 re-exports in [`no-mutable-exports`]. ([#317], fixed by [#322]. thanks [@borisyankov] + [@jfmengels]) + ## [1.7.0] - 2016-05-06 ### Added - [`newline-after-import`], new rule. ([#245], thanks [@singles]) @@ -201,6 +205,7 @@ for info on changes for earlier releases. [`newline-after-import`]: ./docs/rules/newline-after-import.md [`no-mutable-exports`]: ./docs/rules/no-mutable-exports.md +[#322]: https://github.com/benmosher/eslint-plugin-import/pull/322 [#298]: https://github.com/benmosher/eslint-plugin-import/pull/298 [#297]: https://github.com/benmosher/eslint-plugin-import/pull/297 [#296]: https://github.com/benmosher/eslint-plugin-import/pull/296 @@ -223,6 +228,7 @@ for info on changes for earlier releases. [#164]: https://github.com/benmosher/eslint-plugin-import/pull/164 [#157]: https://github.com/benmosher/eslint-plugin-import/pull/157 +[#317]: https://github.com/benmosher/eslint-plugin-import/issues/317 [#286]: https://github.com/benmosher/eslint-plugin-import/issues/286 [#281]: https://github.com/benmosher/eslint-plugin-import/issues/281 [#272]: https://github.com/benmosher/eslint-plugin-import/issues/272 @@ -274,3 +280,4 @@ for info on changes for earlier releases. [@strawbrary]: https://github.com/strawbrary [@SimenB]: https://github.com/SimenB [@josh]: https://github.com/josh +[@borisyankov]: https://github.com/borisyankov From cf45512a1bc3fc476745269fee54713dc4a4ea71 Mon Sep 17 00:00:00 2001 From: "Gavri (Gabriel) Guy" Date: Thu, 5 May 2016 11:48:36 -0400 Subject: [PATCH 3/6] Add `prefer-default-export` rule --- CHANGELOG.md | 6 +++ README.md | 1 + docs/rules/prefer-default-export.md | 51 ++++++++++++++++++++++++ src/index.js | 1 + src/rules/prefer-default-export.js | 31 ++++++++++++++ tests/src/rules/prefer-default-export.js | 48 ++++++++++++++++++++++ 6 files changed, 138 insertions(+) create mode 100644 docs/rules/prefer-default-export.md create mode 100644 src/rules/prefer-default-export.js create mode 100644 tests/src/rules/prefer-default-export.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 12c699911c..cef8d8e53f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). ## [Unreleased] +### Added +- [`prefer-default-export`], new rule. ([#308], thanks [@gavriguy]) + ### Fixed - ignore namespace / ES7 re-exports in [`no-mutable-exports`]. ([#317], fixed by [#322]. thanks [@borisyankov] + [@jfmengels]) @@ -204,8 +207,10 @@ for info on changes for earlier releases. [`named`]: ./docs/rules/named.md [`newline-after-import`]: ./docs/rules/newline-after-import.md [`no-mutable-exports`]: ./docs/rules/no-mutable-exports.md +[`prefer-default-export`]: ./docs/rules/prefer-default-export.md [#322]: https://github.com/benmosher/eslint-plugin-import/pull/322 +[#308]: https://github.com/benmosher/eslint-plugin-import/pull/308 [#298]: https://github.com/benmosher/eslint-plugin-import/pull/298 [#297]: https://github.com/benmosher/eslint-plugin-import/pull/297 [#296]: https://github.com/benmosher/eslint-plugin-import/pull/296 @@ -281,3 +286,4 @@ for info on changes for earlier releases. [@SimenB]: https://github.com/SimenB [@josh]: https://github.com/josh [@borisyankov]: https://github.com/borisyankov +[@gavriguy]: https://github.com/gavriguy diff --git a/README.md b/README.md index bf530fb995..fc15ac7cf5 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a [`extensions`]: ./docs/rules/extensions.md [`order`]: ./docs/rules/order.md [`newline-after-import`]: ./docs/rules/newline-after-import.md +[`prefer-default-export`]: ./docs/rules/prefer-default-export.md ## Installation diff --git a/docs/rules/prefer-default-export.md b/docs/rules/prefer-default-export.md new file mode 100644 index 0000000000..892abfa38a --- /dev/null +++ b/docs/rules/prefer-default-export.md @@ -0,0 +1,51 @@ +# prefer-default-export + +When there is only a single export from a module prefer using default export over named export. + +## Rule Details + +The following patterns are considered warnings: + +```javascript +// bad.js + +// There is only a single module export and its a named export. +export const foo = 'foo'; + +``` + +The following patterns are not warnings: + +```javascript +// good1.js + +// There is a default export. +export const foo = 'foo'; +const bar = 'bar'; +export default 'bar'; +``` + +```javascript +// good2.js + +// There is more thank one named exports in the module. +export const foo = 'foo'; +export const bar = 'bar'; +``` + +```javascript +// good3.js + +// There is more thank one named exports in the module +const foo = 'foo'; +const bar = 'bar'; +export { foo, bar } +``` + +```javascript +// good4.js + +// There is a default export. +const foo = 'foo'; +export { foo as default } +``` diff --git a/src/index.js b/src/index.js index 0d1eb15cfa..f9da72a223 100644 --- a/src/index.js +++ b/src/index.js @@ -19,6 +19,7 @@ export const rules = { 'no-nodejs-modules': require('./rules/no-nodejs-modules'), 'order': require('./rules/order'), 'newline-after-import': require('./rules/newline-after-import'), + 'prefer-default-export': require('./rules/prefer-default-export'), // metadata-based 'no-deprecated': require('./rules/no-deprecated'), diff --git a/src/rules/prefer-default-export.js b/src/rules/prefer-default-export.js new file mode 100644 index 0000000000..871cd8187c --- /dev/null +++ b/src/rules/prefer-default-export.js @@ -0,0 +1,31 @@ +'use strict' + +module.exports = function(context) { + let namedExportCount = 0 + let specifierExportCount = 0 + let hasDefaultExport = false + let namedExportNode = null + return { + 'ExportSpecifier': function(node) { + if (node.exported.name === 'default') { + hasDefaultExport = true + } else { + specifierExportCount++ + namedExportNode = node + } + }, + 'ExportNamedDeclaration': function(node) { + namedExportCount++ + namedExportNode = node + }, + 'ExportDefaultDeclaration': function() { + hasDefaultExport = true + }, + + 'Program:exit': function() { + if (namedExportCount === 1 && specifierExportCount < 2 && !hasDefaultExport) { + context.report(namedExportNode, 'Prefer default export.') + } + }, + } +} diff --git a/tests/src/rules/prefer-default-export.js b/tests/src/rules/prefer-default-export.js new file mode 100644 index 0000000000..c3827eeba2 --- /dev/null +++ b/tests/src/rules/prefer-default-export.js @@ -0,0 +1,48 @@ +import { test } from '../utils' + +import { RuleTester } from 'eslint' + +const ruleTester = new RuleTester() + , rule = require('rules/prefer-default-export') + +ruleTester.run('prefer-default-export', rule, { + valid: [ + test({ + code: ` + export const foo = 'foo'; + export const bar = 'bar';`, + }), + test({ + code: ` + export const foo = 'foo'; + export default bar;`, + }), + test({ + code: ` + export { foo, bar }`, + }), + test({ + code: ` + export { foo as default }`, + }), + ], + invalid: [ + test({ + code: ` + export const foo = 'foo';`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Prefer default export.', + }], + }), + test({ + code: ` + const foo = 'foo'; + export { foo };`, + errors: [{ + ruleId: 'ExportNamedDeclaration', + message: 'Prefer default export.', + }], + }), + ], +}) From f8301ea3e788b4e718747d0ff8a72db3b4820bd8 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Mon, 9 May 2016 07:02:06 -0400 Subject: [PATCH 4/6] added prefer-default-export to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fc15ac7cf5..37bdd861e7 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a * Ensure consistent use of file extension within the import path ([`extensions`]) * Enforce a convention in module import order ([`order`]) * Enforce a newline after import statements ([`newline-after-import`]) +* Prefer a default export if module exports a single name ([`prefer-default-export`]) [`imports-first`]: ./docs/rules/imports-first.md [`no-duplicates`]: ./docs/rules/no-duplicates.md From 90fefa3deb0853b4ab286eb07179fba62f4275c6 Mon Sep 17 00:00:00 2001 From: Jeroen Engels Date: Mon, 9 May 2016 15:36:09 +0200 Subject: [PATCH 5/6] `no-extraneous-dependencies`: Handle scoped packages. Fixes #316 (#324) --- CHANGELOG.md | 6 ++++-- src/rules/no-extraneous-dependencies.js | 5 ++++- tests/files/package.json | 1 + tests/src/rules/no-extraneous-dependencies.js | 17 ++++++++++++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cef8d8e53f..4cb0ce9dc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel - [`prefer-default-export`], new rule. ([#308], thanks [@gavriguy]) ### Fixed -- ignore namespace / ES7 re-exports in [`no-mutable-exports`]. ([#317], fixed by [#322]. thanks [@borisyankov] + [@jfmengels]) +- Ignore namespace / ES7 re-exports in [`no-mutable-exports`]. ([#317], fixed by [#322]. thanks [@borisyankov] + [@jfmengels]) +- Make [`no-extraneous-dependencies`] handle scoped packages ([#316], thanks [@jfmengels]) ## [1.7.0] - 2016-05-06 ### Added @@ -18,7 +19,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel - add [`no-mutable-exports`] rule ([#290], thanks [@josh]) - [`import/extensions` setting]: a whitelist of file extensions to parse as modules and search for `export`s. If unspecified, all extensions are considered valid (for now). - In v2, this will likely default to `['.js', MODULE_EXT]`,. ([#297], to fix [#267]) + In v2, this will likely default to `['.js', MODULE_EXT]`. ([#297], to fix [#267]) ### Fixed - [`extensions`]: fallback to source path for extension enforcement if imported @@ -210,6 +211,7 @@ for info on changes for earlier releases. [`prefer-default-export`]: ./docs/rules/prefer-default-export.md [#322]: https://github.com/benmosher/eslint-plugin-import/pull/322 +[#316]: https://github.com/benmosher/eslint-plugin-import/pull/316 [#308]: https://github.com/benmosher/eslint-plugin-import/pull/308 [#298]: https://github.com/benmosher/eslint-plugin-import/pull/298 [#297]: https://github.com/benmosher/eslint-plugin-import/pull/297 diff --git a/src/rules/no-extraneous-dependencies.js b/src/rules/no-extraneous-dependencies.js index 8f571fe2a0..becbad0926 100644 --- a/src/rules/no-extraneous-dependencies.js +++ b/src/rules/no-extraneous-dependencies.js @@ -39,7 +39,10 @@ function reportIfMissing(context, deps, allowDevDeps, allowOptDeps, node, name) if (importType(name, context) !== 'external') { return } - const packageName = name.split('/')[0] + const splitName = name.split('/') + const packageName = splitName[0][0] === '@' + ? splitName.slice(0, 2).join('/') + : splitName[0] const isInDeps = deps.dependencies[packageName] !== undefined const isInDevDeps = deps.devDependencies[packageName] !== undefined diff --git a/tests/files/package.json b/tests/files/package.json index 3e2bd0fa09..d0ef9601b4 100644 --- a/tests/files/package.json +++ b/tests/files/package.json @@ -7,6 +7,7 @@ "eslint": "2.x" }, "dependencies": { + "@scope/core": "^1.0.0", "lodash.cond": "^4.3.0", "pkg-up": "^1.0.0" }, diff --git a/tests/src/rules/no-extraneous-dependencies.js b/tests/src/rules/no-extraneous-dependencies.js index 7335e1fd36..e849880094 100644 --- a/tests/src/rules/no-extraneous-dependencies.js +++ b/tests/src/rules/no-extraneous-dependencies.js @@ -21,11 +21,12 @@ ruleTester.run('no-extraneous-dependencies', rule, { test({ code: 'import "fs"'}), test({ code: 'import "./foo"'}), test({ code: 'import "lodash.isarray"'}), + test({ code: 'import "@scope/core"'}), // 'project' type test({ code: 'import "importType"', - settings: { "import/resolver": { node: { paths: [ path.join(__dirname, '../../files') ] } } }, + settings: { 'import/resolver': { node: { paths: [ path.join(__dirname, '../../files') ] } } }, }), ], invalid: [ @@ -36,6 +37,20 @@ ruleTester.run('no-extraneous-dependencies', rule, { message: '\'not-a-dependency\' should be listed in the project\'s dependencies. Run \'npm i -S not-a-dependency\' to add it', }], }), + test({ + code: 'var donthaveit = require("@scope/donthaveit")', + errors: [{ + ruleId: 'no-extraneous-dependencies', + message: '\'@scope/donthaveit\' should be listed in the project\'s dependencies. Run \'npm i -S @scope/donthaveit\' to add it', + }], + }), + test({ + code: 'var donthaveit = require("@scope/donthaveit/lib/foo")', + errors: [{ + ruleId: 'no-extraneous-dependencies', + message: '\'@scope/donthaveit\' should be listed in the project\'s dependencies. Run \'npm i -S @scope/donthaveit\' to add it', + }], + }), test({ code: 'import "eslint"', options: [{devDependencies: false}], From e04981707d53879c2c0ee681a45e8ca13bdd4000 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Wed, 11 May 2016 07:40:11 -0400 Subject: [PATCH 6/6] v1.8.0 --- CHANGELOG.md | 5 +++-- package.json | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb0ce9dc6..46699d7ceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com). -## [Unreleased] +## [1.8.0] - 2016-05-11 ### Added - [`prefer-default-export`], new rule. ([#308], thanks [@gavriguy]) @@ -252,7 +252,8 @@ for info on changes for earlier releases. [#119]: https://github.com/benmosher/eslint-plugin-import/issues/119 [#89]: https://github.com/benmosher/eslint-plugin-import/issues/89 -[Unreleased]: https://github.com/benmosher/eslint-plugin-import/compare/v1.7.0...HEAD +[Unreleased]: https://github.com/benmosher/eslint-plugin-import/compare/v1.8.0...HEAD +[1.8.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.7.0...v1.8.0 [1.7.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.6.1...v1.7.0 [1.6.1]: https://github.com/benmosher/eslint-plugin-import/compare/v1.6.0...v1.6.1 [1.6.0]: https://github.com/benmosher/eslint-plugin-import/compare/v1.5.0...1.6.0 diff --git a/package.json b/package.json index 5492aff554..774a5a5118 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-import", - "version": "1.7.0", + "version": "1.8.0", "description": "Import with sanity.", "main": "lib/index.js", "directories": {