diff --git a/CHANGELOG.md b/CHANGELOG.md index e96ef5f3f..0924d9e9d 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 +- Add [`no-named-default`] rule: style-guide rule to report use of unnecessarily named default imports + ### Fixed - [`prefer-default-export`] handles re-exported default exports ([#609]) - Fix crash when using `newline-after-import` with decorators ([#592]) diff --git a/README.md b/README.md index 45170bded..1215b1b2d 100644 --- a/README.md +++ b/README.md @@ -85,8 +85,9 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a * 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`]) -* Limit the maximum number of dependencies a module can have. ([`max-dependencies`]) -* Forbid unassigned imports. ([`no-unassigned-import`]) +* Limit the maximum number of dependencies a module can have ([`max-dependencies`]) +* Forbid unassigned imports ([`no-unassigned-import`]) +* Forbid named default exports ([`no-named-default`]) [`first`]: ./docs/rules/first.md [`no-duplicates`]: ./docs/rules/no-duplicates.md @@ -97,6 +98,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a [`prefer-default-export`]: ./docs/rules/prefer-default-export.md [`max-dependencies`]: ./docs/rules/max-dependencies.md [`no-unassigned-import`]: ./docs/rules/no-unassigned-import.md +[`no-named-default`]: ./docs/rules/no-named-default.md ## Installation diff --git a/docs/rules/no-named-default.md b/docs/rules/no-named-default.md new file mode 100644 index 000000000..651ca6143 --- /dev/null +++ b/docs/rules/no-named-default.md @@ -0,0 +1,27 @@ +# no-named-default + +Reports use of a default export as a locally named import. + +Rationale: the syntax exists to import default exports expressively, let's use it. + +## Rule Details + +Given: +```js +// foo.js +export default 'foo'; +export const bar = 'baz'; +``` + +...these would be valid: +```js +import foo from './foo.js'; +import foo, { bar } from './foo.js'; +``` + +...and these would be reported: +```js +// message: Using exported name 'bar' as identifier for default export. +import { default as foo } from './foo.js'; +import { default as foo, bar } from './foo.js'; +``` diff --git a/src/index.js b/src/index.js index 68fd8855e..cc6a31512 100644 --- a/src/index.js +++ b/src/index.js @@ -10,6 +10,7 @@ export const rules = { 'no-restricted-paths': require('./rules/no-restricted-paths'), 'no-internal-modules': require('./rules/no-internal-modules'), + 'no-named-default': require('./rules/no-named-default'), 'no-named-as-default': require('./rules/no-named-as-default'), 'no-named-as-default-member': require('./rules/no-named-as-default-member'), diff --git a/src/rules/no-named-default.js b/src/rules/no-named-default.js new file mode 100644 index 000000000..3185157f3 --- /dev/null +++ b/src/rules/no-named-default.js @@ -0,0 +1,19 @@ +module.exports = { + meta: { + docs: {}, + }, + + create: function (context) { + return { + 'ImportDeclaration': function (node) { + node.specifiers.forEach(function (im) { + if (im.type === 'ImportSpecifier' && im.imported.name === 'default') { + context.report({ + node: im.local, + message: `Use default import syntax to import \'${im.local.name}\'.` }) + } + }) + }, + } + }, +} diff --git a/tests/src/rules/no-named-default.js b/tests/src/rules/no-named-default.js new file mode 100644 index 000000000..8ca26f860 --- /dev/null +++ b/tests/src/rules/no-named-default.js @@ -0,0 +1,39 @@ +import { test, SYNTAX_CASES } from '../utils' +import { RuleTester } from 'eslint' + +const ruleTester = new RuleTester() + , rule = require('rules/no-named-default') + +ruleTester.run('no-named-default', rule, { + valid: [ + test({code: 'import bar from "./bar";'}), + test({code: 'import bar, { foo } from "./bar";'}), + + ...SYNTAX_CASES, + ], + + invalid: [ + test({ + code: 'import { default } from "./bar";', + errors: [{ + message: 'Use default import syntax to import \'default\'.', + type: 'Identifier', + }], + parser: 'babel-eslint', + }), + test({ + code: 'import { default as bar } from "./bar";', + errors: [{ + message: 'Use default import syntax to import \'bar\'.', + type: 'Identifier', + }], + }), + test({ + code: 'import { foo, default as bar } from "./bar";', + errors: [{ + message: 'Use default import syntax to import \'bar\'.', + type: 'Identifier', + }], + }), + ], +})