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

Commit 42ada82

Browse files
committed
feat: add no-env-in-context
1 parent acb5db2 commit 42ada82

File tree

5 files changed

+275
-10
lines changed

5 files changed

+275
-10
lines changed

docs/rules/no-env-in-context.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# nuxt/no-env-in-context
2+
3+
> disallow `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`
4+
5+
- :gear: This rule is included in `"plugin:nuxt/base"`.
6+
7+
## Rule Details
8+
9+
This rule is for preventing using `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`
10+
11+
Examples of **incorrect** code for this rule:
12+
13+
```js
14+
15+
export default {
16+
async asyncData() {
17+
if(process.server) {
18+
const foo = 'bar'
19+
}
20+
},
21+
fetch() {
22+
if(process.client) {
23+
const foo = 'bar'
24+
}
25+
}
26+
}
27+
28+
```
29+
30+
Examples of **correct** code for this rule:
31+
32+
```js
33+
34+
export default {
35+
asyncData(context) {
36+
if(context.isServer) {
37+
const foo = 'bar'
38+
}
39+
},
40+
fetch({ isClient }) {
41+
if(isClient) {
42+
const foo = 'bar'
43+
}
44+
}
45+
}
46+
47+
```
48+
49+
## :mag: Implementation
50+
51+
- [Rule source](https://github.com/nuxt/eslint-plugin-nuxt/blob/master/lib/rules/no-env-in-context.js)
52+
- [Test source](https://github.com/nuxt/eslint-plugin-nuxt/blob/master/lib/rules/__test__/no-env-in-context.test.js)

lib/configs/base.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module.exports = {
1212
es6: true
1313
},
1414
rules: {
15-
'nuxt/no-this-in-fetch-data': 'error',
16-
'nuxt/no-this-in-fetch': 'error'
15+
'nuxt/no-env-in-context': 'error',
16+
'nuxt/no-this-in-fetch-data': 'error'
1717
}
1818
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/**
2+
* @fileoverview disallow `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`
3+
* @author Xin Du <[email protected]>
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
var rule = require('../no-env-in-context')
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('no-env-in-context', rule, {
26+
27+
valid: [
28+
{
29+
filename: 'test.vue',
30+
code: `
31+
export default {
32+
async asyncData() {
33+
if(process.server) {
34+
const foo = 'bar'
35+
}
36+
},
37+
fetch() {
38+
if(process.client) {
39+
const foo = 'bar'
40+
}
41+
}
42+
}
43+
`,
44+
parserOptions
45+
}
46+
],
47+
48+
invalid: [
49+
{
50+
filename: 'test.vue',
51+
code: `
52+
export default {
53+
asyncData(context) {
54+
if(context.isServer) {
55+
const foo = 'bar'
56+
}
57+
},
58+
fetch(context) {
59+
if(context.isClient) {
60+
const foo = 'bar'
61+
}
62+
}
63+
}
64+
`,
65+
errors: [{
66+
message: 'Unexpected isServer in asyncData.',
67+
type: 'MemberExpression'
68+
}, {
69+
message: 'Unexpected isClient in fetch.',
70+
type: 'MemberExpression'
71+
}],
72+
parserOptions
73+
},
74+
{
75+
filename: 'test.vue',
76+
code: `
77+
export default {
78+
asyncData(context) {
79+
if(context['isClient']) {
80+
const foo = 'bar'
81+
}
82+
},
83+
fetch(context) {
84+
if(context['isServer']) {
85+
const foo = 'bar'
86+
}
87+
}
88+
}
89+
`,
90+
errors: [{
91+
message: 'Unexpected isClient in asyncData.',
92+
type: 'MemberExpression'
93+
}, {
94+
message: 'Unexpected isServer in fetch.',
95+
type: 'MemberExpression'
96+
}],
97+
parserOptions
98+
},
99+
{
100+
filename: 'test.vue',
101+
code: `
102+
export default {
103+
asyncData({ isClient }) {
104+
if(isClient) {
105+
const foo = 'bar'
106+
}
107+
},
108+
fetch({ isServer }) {
109+
if(isServer) {
110+
const foo = 'bar'
111+
}
112+
}
113+
}
114+
`,
115+
errors: [{
116+
message: 'Unexpected isClient in asyncData.',
117+
type: 'Property'
118+
}, {
119+
message: 'Unexpected isServer in fetch.',
120+
type: 'Property'
121+
}],
122+
parserOptions
123+
}
124+
]
125+
})

lib/rules/no-env-in-context.js

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* @fileoverview disallow `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`
3+
* @author Xin Du <[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+
docs: {
16+
description:
17+
'disallow `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`',
18+
category: 'base'
19+
},
20+
messages: {
21+
noEnv: 'Unexpected {{env}} in {{funcName}}.'
22+
}
23+
},
24+
25+
create: function (context) {
26+
// variables should be defined here
27+
const forbiddenNodes = []
28+
const options = context.options[0] || {}
29+
30+
const ENV = ['isServer', 'isClient']
31+
const HOOKS = new Set(['asyncData', 'fetch'].concat(options.methods || []))
32+
33+
// ----------------------------------------------------------------------
34+
// Public
35+
// ----------------------------------------------------------------------
36+
37+
return {
38+
MemberExpression (node) {
39+
const propertyName = node.computed ? node.property.value : node.property.name
40+
if (propertyName && ENV.includes(propertyName)) {
41+
forbiddenNodes.push({ name: propertyName, node })
42+
}
43+
},
44+
...utils.executeOnVue(context, obj => {
45+
for (const funcName of HOOKS) {
46+
const func = utils.getFunctionWithName(obj, funcName)
47+
const param = func.value.params && func.value.params[0]
48+
if (param) {
49+
if (param.type === 'ObjectPattern') {
50+
for (const prop of param.properties) {
51+
if (ENV.includes(prop.key.name)) {
52+
context.report({
53+
node: prop,
54+
messageId: 'noEnv',
55+
data: {
56+
env: prop.key.name,
57+
funcName
58+
}
59+
})
60+
}
61+
}
62+
} else {
63+
for (const { name, node: child } of forbiddenNodes) {
64+
if (utils.isInFunction(func, child)) {
65+
if (param.name === child.object.name) {
66+
context.report({
67+
node: child,
68+
messageId: 'noEnv',
69+
data: {
70+
env: name,
71+
funcName
72+
}
73+
})
74+
}
75+
}
76+
}
77+
}
78+
}
79+
}
80+
})
81+
}
82+
}
83+
}

lib/utils/index.js

+13-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ module.exports = Object.assign(
1919
item => item.value.type === 'ArrowFunctionExpression' || item.value.type === 'FunctionExpression'
2020
)
2121
},
22+
isInFunction (func, child) {
23+
if (func.value.type === 'FunctionExpression') {
24+
if (
25+
child &&
26+
child.loc.start.line >= func.value.loc.start.line &&
27+
child.loc.end.line <= func.value.loc.end.line
28+
) {
29+
return true
30+
}
31+
}
32+
},
2233
* getFunctionWithChild (rootNode, funcNames, childNodes) {
2334
const funcNodes = this.getProperties(rootNode, funcNames)
2435

@@ -27,14 +38,8 @@ module.exports = Object.assign(
2738
const funcName = utils.getStaticPropertyName(func.key)
2839
if (!funcName) continue
2940

30-
if (func.value.type === 'FunctionExpression') {
31-
if (
32-
child &&
33-
child.loc.start.line >= func.value.loc.start.line &&
34-
child.loc.end.line <= func.value.loc.end.line
35-
) {
36-
yield { name, node: child, funcName }
37-
}
41+
if (this.isInFunction(func, child)) {
42+
yield { name, node: child, func, funcName }
3843
}
3944
}
4045
}

0 commit comments

Comments
 (0)