Skip to content

Commit

Permalink
Add no-anonymous-default-export rule
Browse files Browse the repository at this point in the history
  • Loading branch information
duncanbeevers committed Jan 6, 2017
1 parent c975742 commit 5a8d6ef
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
- [`no-anonymous-default-export`] rule: report anonymous default exports.

### Changed
- [`no-extraneous-dependencies`]: use `read-pkg-up` to simplify finding + loading `package.json` ([#680], thanks [@wtgtybhertgeghgtwtg])

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a
* 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`])
* Forbid anonymous values as default exports ([`no-anonymous-default-export`])

[`first`]: ./docs/rules/first.md
[`no-duplicates`]: ./docs/rules/no-duplicates.md
Expand All @@ -87,6 +88,7 @@ This plugin intends to support linting of ES2015+ (ES6+) import/export syntax, a
[`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
[`no-anonymous-default-export`]: ./docs/rules/no-anonymous-default-export.md

## Installation

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

Reports if a module's default export is unnamed. This includes several types of unnamed data types; literals, object expressions, anonymous functions, arrow functions, and anonymous class declarations.

Ensuring that default exports are named helps improve the grepability of the codebase by encouraging the re-use of the same identifier for the module's default export at its declaration site and at its import sites.

By default, all types of anonymous default exports are forbidden, but each type can be selectively allowed using options.

## Rule Details

### Fail
```js
export default 123

export default {}

export default function () {}

export default () => {}

export default class {}
```

### Pass
```js
const foo = 123
export default foo

export default function foo() {}

/*eslint no-anonymous-default-export: [2, "allow-literal"]*/
export default 123

/*eslint no-anonymous-default-export: [2, "object-expression"]*/
export default {}

/*eslint no-anonymous-default-export: [2, "allow-anonymous-function-declaration"]*/
export default function () {}

/*eslint no-anonymous-default-export: [2, "allow-arrow-function-expression"]*/
export default () => {}

/*eslint no-anonymous-default-export: [2, "allow-anonymous-class-declaration"]*/
export default class {}
```
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const rules = {
'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'),
'no-anonymous-default-export': require('./rules/no-anonymous-default-export'),

'no-commonjs': require('./rules/no-commonjs'),
'no-amd': require('./rules/no-amd'),
Expand Down
61 changes: 61 additions & 0 deletions src/rules/no-anonymous-default-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* @fileoverview Rule to disallow anonymous default exports.
* @author Duncan Beevers
*/

module.exports = {
meta: {},

create: function (context) {

const forbid = (option) => !~context.options.indexOf('allow-' + option)

return {
'ExportDefaultDeclaration': (node) => {
const type = node.declaration.type
const noID = !node.declaration.id

if (type === 'Literal' && forbid('literal')) {
context.report({
node: node,
message: 'Unexpected default export of literal',
})
return
}

if (type === 'ObjectExpression' && forbid('object-expression')) {
context.report({
node: node,
message: 'Unexpected default export of object expression',
})
return
}

if (type === 'FunctionDeclaration' && noID && forbid('anonymous-function-declaration')) {
context.report({
node: node,
message: 'Unexpected default export of anonymous function',
})
return
}

if (type === 'ArrowFunctionExpression' && forbid('arrow-function-expression')) {
context.report({
node: node,
message: 'Unexpected default export of arrow function',
})
return
}

if (type === 'ClassDeclaration' && noID && forbid('anonymous-class-declaration')) {
context.report({
node: node,
message: 'Unexpected default export of anonymous class',
})
return
}
},
}

},
}
30 changes: 30 additions & 0 deletions tests/src/rules/no-anonymous-default-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { test, SYNTAX_CASES } from '../utils'

import { RuleTester } from 'eslint'

var ruleTester = new RuleTester()
var rule = require('rules/no-anonymous-default-export')

ruleTester.run('no-anonymous-default-export', rule, {
valid: [
test({ code: 'const foo = 123\nexport default foo' }),
test({ code: 'export default function foo() {}'}),
test({ code: 'export default class MyClass {}'}),

test({ code: 'export default 123', options: ['allow-literal'] }),
test({ code: 'export default {}', options: ['allow-object-expression'] }),
test({ code: 'export default class {}', options: ['allow-anonymous-class-declaration'] }),
test({ code: 'export default function() {}', options: ['allow-anonymous-function-declaration'] }),
test({ code: 'export default () => {}', options: ['allow-arrow-function-expression'] }),

...SYNTAX_CASES,
],

invalid: [
test({ code: 'export default 123', errors: [{ message: 'Unexpected default export of literal' }] }),
test({ code: 'export default {}', errors: [{ message: 'Unexpected default export of object expression' }] }),
test({ code: 'export default class {}', errors: [{ message: 'Unexpected default export of anonymous class' }] }),
test({ code: 'export default function() {}', errors: [{ message: 'Unexpected default export of anonymous function' }] }),
test({ code: 'export default () => {}', errors: [{ message: 'Unexpected default export of arrow function' }] }),
],
})

0 comments on commit 5a8d6ef

Please sign in to comment.