Skip to content
This repository was archived by the owner on Mar 19, 2024. It is now read-only.

Commit 7d0926f

Browse files
authoredNov 18, 2019
feat(rule): add require-func-head in recommended (#62)
2 parents 8826a46 + 79403a0 commit 7d0926f

File tree

7 files changed

+182
-3
lines changed

7 files changed

+182
-3
lines changed
 

‎README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,5 @@ Include all the below rules, as well as all priority rules in above categories,
102102

103103
| | Rule ID | Description |
104104
|:---|:--------|:------------|
105-
| :wrench: | [nuxt/no-timing-in-fetch-data](./docs/rules/no-timing-in-fetch-data.md) | Disallow `setTimeout/setInterval` in `asyncData/fetch` |
105+
| | [nuxt/no-timing-in-fetch-data](./docs/rules/no-timing-in-fetch-data.md) | Disallow `setTimeout/setInterval` in `asyncData/fetch` |
106+
| | [nuxt/require-func-head](./docs/rules/require-func-head.md) | Enforce `head` property in component to be a function. |

‎docs/rules/require-func-head.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# nuxt/require-func-head
2+
3+
> enforce `head` property in component to be a function.
4+
5+
- :gear: This rule is included in `"plugin:nuxt/recommended"`.
6+
7+
## Rule Details
8+
9+
This rule is enforcing `head` property in component to be a function.
10+
11+
Examples of **incorrect** code for this rule:
12+
13+
```js
14+
15+
export default {
16+
head: {
17+
title: "My page"
18+
}
19+
}
20+
21+
```
22+
23+
Examples of **correct** code for this rule:
24+
25+
```js
26+
27+
export default {
28+
head() {
29+
return {
30+
title: "My page"
31+
}
32+
}
33+
}
34+
35+
```
36+
37+
## :mag: Implementation
38+
39+
- [Rule source](../../lib/rules/require-func-head.js)
40+
- [Test source](../../lib/rules/__tests__/require-func-head.test.js)

‎lib/configs/recommended.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module.exports = {
22
extends: require.resolve('./base.js'),
33
rules: {
4-
'nuxt/no-timing-in-fetch-data': 'error'
4+
'nuxt/no-timing-in-fetch-data': 'error',
5+
'nuxt/require-func-head': 'error'
56
}
67
}

‎lib/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ module.exports = {
55
'no-globals-in-created': require('./rules/no-globals-in-created'),
66
'no-this-in-fetch-data': require('./rules/no-this-in-fetch-data'),
77
'no-timing-in-fetch-data': require('./rules/no-timing-in-fetch-data'),
8-
'no-cjs-in-config': require('./rules/no-cjs-in-config')
8+
'no-cjs-in-config': require('./rules/no-cjs-in-config'),
9+
'require-func-head': require('./rules/require-func-head')
910
},
1011
configs: {
1112
base: require('./configs/base'),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* @fileoverview disallow `setTimeout/setInterval` in `asyncData/fetch`
3+
* @author Xin Du <clark.duxin@gmail.com>
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
var rule = require('../require-func-head')
12+
13+
var RuleTester = require('eslint').RuleTester
14+
15+
const parserOptions = {
16+
ecmaVersion: 2018,
17+
sourceType: 'module'
18+
}
19+
20+
// ------------------------------------------------------------------------------
21+
// Tests
22+
// ------------------------------------------------------------------------------
23+
24+
var ruleTester = new RuleTester()
25+
ruleTester.run('require-func-head', rule, {
26+
27+
valid: [
28+
{
29+
filename: 'test.vue',
30+
code: `
31+
export default {
32+
head() {
33+
return {
34+
title: "My page"
35+
}
36+
}
37+
}
38+
`,
39+
parserOptions
40+
}
41+
],
42+
43+
invalid: [
44+
{
45+
filename: 'test.vue',
46+
code: `
47+
export default {
48+
head: {
49+
title: "My page"
50+
}
51+
}
52+
`,
53+
errors: [{
54+
message: '`head` property in component must be a function.',
55+
type: 'Property'
56+
}],
57+
parserOptions
58+
}
59+
]
60+
})

‎lib/rules/require-func-head.js

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @fileoverview enforce component's head property to be a function.
3+
* @author Xin Du <clark.duxin@gmail.com>
4+
*/
5+
'use strict'
6+
7+
const utils = require('../utils')
8+
9+
// ------------------------------------------------------------------------------
10+
// Rule Definition
11+
// ------------------------------------------------------------------------------
12+
13+
module.exports = {
14+
meta: {
15+
docs: {
16+
description: "enforce component's head property to be a function",
17+
category: 'recommended'
18+
},
19+
fixable: 'code',
20+
messages: {
21+
head: '`head` property in component must be a function.'
22+
}
23+
},
24+
25+
create (context) {
26+
const sourceCode = context.getSourceCode()
27+
28+
return utils.executeOnVueComponent(context, (obj) => {
29+
obj.properties
30+
.filter(p =>
31+
p.type === 'Property' &&
32+
p.key.type === 'Identifier' &&
33+
p.key.name === 'head' &&
34+
p.value.type !== 'FunctionExpression' &&
35+
p.value.type !== 'ArrowFunctionExpression' &&
36+
p.value.type !== 'Identifier'
37+
)
38+
.forEach(p => {
39+
context.report({
40+
node: p,
41+
messageId: 'head',
42+
fix (fixer) {
43+
const tokens = utils.getFirstAndLastTokens(p.value, sourceCode)
44+
45+
return [
46+
fixer.insertTextBefore(tokens.first, 'function() {\nreturn '),
47+
fixer.insertTextAfter(tokens.last, ';\n}')
48+
]
49+
}
50+
})
51+
})
52+
})
53+
}
54+
}

‎lib/utils/index.js

+22
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,28 @@ module.exports = Object.assign(
4343
}
4444
}
4545
}
46+
},
47+
isOpenParen (token) {
48+
return token.type === 'Punctuator' && token.value === '('
49+
},
50+
isCloseParen (token) {
51+
return token.type === 'Punctuator' && token.value === ')'
52+
},
53+
getFirstAndLastTokens (node, sourceCode) {
54+
let first = sourceCode.getFirstToken(node)
55+
let last = sourceCode.getLastToken(node)
56+
57+
// If the value enclosed by parentheses, update the 'first' and 'last' by the parentheses.
58+
while (true) {
59+
const prev = sourceCode.getTokenBefore(first)
60+
const next = sourceCode.getTokenAfter(last)
61+
if (this.isOpenParen(prev) && this.isCloseParen(next)) {
62+
first = prev
63+
last = next
64+
} else {
65+
return { first, last }
66+
}
67+
}
4668
}
4769
},
4870
utils

0 commit comments

Comments
 (0)
This repository has been archived.