Skip to content

Commit fd4b062

Browse files
privatenumbermichalsnik
authored andcommitted
⭐️New: Add vue/require-direct-export rule (#581)
* require-direct-export rule * Added it to entry file and category * Fixed rule doc issues * Update require-direct-export
1 parent ebd07e6 commit fd4b062

File tree

6 files changed

+154
-2
lines changed

6 files changed

+154
-2
lines changed

Diff for: docs/rules/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ For example:
145145
| [vue/key-spacing](./key-spacing.md) | enforce consistent spacing between keys and values in object literal properties | :wrench: |
146146
| [vue/match-component-file-name](./match-component-file-name.md) | require component name property to match its file name | |
147147
| [vue/object-curly-spacing](./object-curly-spacing.md) | enforce consistent spacing inside braces | :wrench: |
148+
| [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | |
148149
| [vue/script-indent](./script-indent.md) | enforce consistent indentation in `<script>` | :wrench: |
149150
| [vue/space-infix-ops](./space-infix-ops.md) | require spacing around infix operators | :wrench: |
150151
| [vue/space-unary-ops](./space-unary-ops.md) | enforce consistent spacing before or after unary operators | :wrench: |

Diff for: docs/rules/require-direct-export.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/require-direct-export
5+
description: require the component to be directly exported
6+
---
7+
# vue/require-direct-export
8+
> require the component to be directly exported
9+
10+
## Rule Details
11+
12+
This rule aims to require that the component object be directly exported.
13+
14+
:-1: Examples of **incorrect** code:
15+
16+
```js
17+
const ComponentA = {
18+
name: 'ComponentA',
19+
data() {
20+
return {
21+
state: 1
22+
}
23+
}
24+
}
25+
26+
export default ComponentA
27+
```
28+
29+
:+1: Examples of **correct** code:
30+
31+
```js
32+
export default {
33+
name: 'ComponentA',
34+
data() {
35+
return {
36+
state: 1
37+
}
38+
}
39+
}
40+
```
41+
42+
## :mag: Implementation
43+
44+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/require-direct-export.js)
45+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/require-direct-export.js)

Diff for: lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ module.exports = {
4848
'prop-name-casing': require('./rules/prop-name-casing'),
4949
'require-component-is': require('./rules/require-component-is'),
5050
'require-default-prop': require('./rules/require-default-prop'),
51+
'require-direct-export': require('./rules/require-direct-export'),
5152
'require-prop-type-constructor': require('./rules/require-prop-type-constructor'),
5253
'require-prop-types': require('./rules/require-prop-types'),
5354
'require-render-return': require('./rules/require-render-return'),

Diff for: lib/rules/require-direct-export.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @fileoverview require the component to be directly exported
3+
* @author Hiroki Osame <[email protected]>
4+
*/
5+
'use strict'
6+
7+
const utils = require('../utils')
8+
9+
// ------------------------------------------------------------------------------
10+
// Rule Definition
11+
// ------------------------------------------------------------------------------
12+
13+
module.exports = {
14+
meta: {
15+
type: 'suggestion',
16+
docs: {
17+
description: 'require the component to be directly exported',
18+
category: undefined,
19+
url: 'https://eslint.vuejs.org/rules/require-direct-export.html'
20+
},
21+
fixable: null, // or "code" or "whitespace"
22+
schema: []
23+
},
24+
25+
create (context) {
26+
const filePath = context.getFilename()
27+
28+
return {
29+
'ExportDefaultDeclaration:exit' (node) {
30+
if (!utils.isVueFile(filePath)) return
31+
32+
const isObjectExpression = (
33+
node.type === 'ExportDefaultDeclaration' &&
34+
node.declaration.type === 'ObjectExpression'
35+
)
36+
37+
if (!isObjectExpression) {
38+
context.report({
39+
node,
40+
message: `Expected the component literal to be directly exported.`
41+
})
42+
}
43+
}
44+
}
45+
}
46+
}

Diff for: lib/utils/index.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,10 @@ module.exports = {
536536
})
537537
},
538538

539+
isVueFile (path) {
540+
return path.endsWith('.vue') || path.endsWith('.jsx')
541+
},
542+
539543
/**
540544
* Check whether the given node is a Vue component based
541545
* on the filename and default export type
@@ -545,8 +549,7 @@ module.exports = {
545549
* @returns {boolean}
546550
*/
547551
isVueComponentFile (node, path) {
548-
const isVueFile = path.endsWith('.vue') || path.endsWith('.jsx')
549-
return isVueFile &&
552+
return this.isVueFile(path) &&
550553
node.type === 'ExportDefaultDeclaration' &&
551554
node.declaration.type === 'ObjectExpression'
552555
},

Diff for: tests/lib/rules/require-direct-export.js

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* @fileoverview require the component to be directly exported
3+
* @author Hiroki Osame <[email protected]>
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const rule = require('../../../lib/rules/require-direct-export')
12+
const RuleTester = require('eslint').RuleTester
13+
14+
const parserOptions = {
15+
ecmaVersion: 2018,
16+
sourceType: 'module',
17+
ecmaFeatures: { jsx: true }
18+
}
19+
20+
// ------------------------------------------------------------------------------
21+
// Tests
22+
// ------------------------------------------------------------------------------
23+
24+
const ruleTester = new RuleTester()
25+
ruleTester.run('require-direct-export', rule, {
26+
27+
valid: [
28+
{
29+
filename: 'test.vue',
30+
code: ''
31+
},
32+
{
33+
filename: 'test.vue',
34+
code: `
35+
export default {}
36+
`,
37+
parserOptions
38+
}
39+
],
40+
41+
invalid: [
42+
43+
{
44+
filename: 'test.vue',
45+
code: `
46+
const A = {};
47+
export default A`,
48+
parserOptions,
49+
errors: [{
50+
message: 'Expected the component literal to be directly exported.',
51+
type: 'ExportDefaultDeclaration',
52+
line: 3
53+
}]
54+
}
55+
]
56+
})

0 commit comments

Comments
 (0)