Skip to content

Commit

Permalink
Add no-named-export + docs/tests (#1157)
Browse files Browse the repository at this point in the history
* Add `no-named-export` + docs/tests

* Fix no-named-export docs missing quotes

* Fix ruleId in no-named-export case test

* Tighten no-named-export error message
  • Loading branch information
fsmaia authored and benmosher committed Sep 9, 2018
1 parent 0764acd commit f04b7b6
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a
* Forbid unassigned imports ([`no-unassigned-import`])
* Forbid named default exports ([`no-named-default`])
* Forbid default exports ([`no-default-export`])
* Forbid named exports ([`no-named-export`])
* Forbid anonymous values as default exports ([`no-anonymous-default-export`])
* Prefer named exports to be grouped together in a single export declaration ([`group-exports`])
* Enforce a leading comment with the webpackChunkName for dynamic imports ([`dynamic-import-chunkname`])
Expand All @@ -104,6 +105,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a
[`no-anonymous-default-export`]: ./docs/rules/no-anonymous-default-export.md
[`group-exports`]: ./docs/rules/group-exports.md
[`no-default-export`]: ./docs/rules/no-default-export.md
[`no-named-export`]: ./docs/rules/no-named-export.md
[`dynamic-import-chunkname`]: ./docs/rules/dynamic-import-chunkname.md

## Installation
Expand Down
77 changes: 77 additions & 0 deletions docs/rules/no-named-export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# no-named-export

Prohibit named exports. Mostly an inverse of [`no-default-export`].

[`no-default-export`]: ./no-default-export.md

## Rule Details

The following patterns are considered warnings:

```javascript
// bad1.js

// There is only a single module export and it's a named export.
export const foo = 'foo';
```

```javascript
// bad2.js

// There is more than one named export in the module.
export const foo = 'foo';
export const bar = 'bar';
```

```javascript
// bad3.js

// There is more than one named export in the module.
const foo = 'foo';
const bar = 'bar';
export { foo, bar }
```

```javascript
// bad4.js

// There is more than one named export in the module.
export * from './other-module'
```

```javascript
// bad5.js

// There is a default and a named export.
export const foo = 'foo';
const bar = 'bar';
export default 'bar';
```

The following patterns are not warnings:

```javascript
// good1.js

// There is only a single module export and it's a default export.
export default 'bar';
```

```javascript
// good2.js

// There is only a single module export and it's a default export.
const foo = 'foo';
export { foo as default }
```

```javascript
// good3.js

// There is only a single module export and it's a default export.
export default from './other-module';
```

## When Not To Use It

If you don't care if named imports are used, or if you prefer named imports over default imports.
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const rules = {
'newline-after-import': require('./rules/newline-after-import'),
'prefer-default-export': require('./rules/prefer-default-export'),
'no-default-export': require('./rules/no-default-export'),
'no-named-export': require('./rules/no-named-export'),
'no-dynamic-require': require('./rules/no-dynamic-require'),
'unambiguous': require('./rules/unambiguous'),
'no-unassigned-import': require('./rules/no-unassigned-import'),
Expand Down
33 changes: 33 additions & 0 deletions src/rules/no-named-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import docsUrl from '../docsUrl'

module.exports = {
meta: {
docs: { url: docsUrl('no-named-export') },
},

create(context) {
// ignore non-modules
if (context.parserOptions.sourceType !== 'module') {
return {}
}

const message = 'Named exports are not allowed.'

return {
ExportAllDeclaration(node) {
context.report({node, message})
},

ExportNamedDeclaration(node) {
if (node.specifiers.length === 0) {
return context.report({node, message})
}

const someNamed = node.specifiers.some(specifier => specifier.exported.name !== 'default')
if (someNamed) {
context.report({node, message})
}
},
}
},
}
179 changes: 179 additions & 0 deletions tests/src/rules/no-named-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { RuleTester } from 'eslint'
import { test } from '../utils'

const ruleTester = new RuleTester()
, rule = require('rules/no-named-export')

ruleTester.run('no-named-export', rule, {
valid: [
test({
code: 'export default function bar() {};',
}),
test({
code: 'export { foo as default }',
}),
test({
code: 'export default from "foo.js"',
parser: 'babel-eslint',
}),

// no exports at all
test({
code: `import * as foo from './foo';`,
}),
test({
code: `import foo from './foo';`,
}),
test({
code: `import {default as foo} from './foo';`,
}),
],
invalid: [
test({
code: `
export const foo = 'foo';
export const bar = 'bar';
`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}, {
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `
export const foo = 'foo';
export default bar;`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `
export const foo = 'foo';
export function bar() {};
`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}, {
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export const foo = 'foo';`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `
const foo = 'foo';
export { foo };
`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export { foo, bar }`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export const { foo, bar } = item;`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export const { foo, bar: baz } = item;`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export const { foo: { bar, baz } } = item;`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `
export const foo = item;
export { item };
`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}, {
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export * from './foo';`,
errors: [{
ruleId: 'ExportAllDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export const { foo } = { foo: "bar" };`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export const { foo: { bar } } = { foo: { bar: "baz" } };`,
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: 'export { a, b } from "foo.js"',
parser: 'babel-eslint',
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export type UserId = number;`,
parser: 'babel-eslint',
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: 'export foo from "foo.js"',
parser: 'babel-eslint',
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
test({
code: `export Memory, { MemoryValue } from './Memory'`,
parser: 'babel-eslint',
errors: [{
ruleId: 'ExportNamedDeclaration',
message: 'Named exports are not allowed.',
}],
}),
],
})

0 comments on commit f04b7b6

Please sign in to comment.