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

Commit

Permalink
feat: add no-env-in-context
Browse files Browse the repository at this point in the history
  • Loading branch information
clarkdo committed Dec 10, 2018
1 parent 1e1b331 commit 71b09e9
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 10 deletions.
52 changes: 52 additions & 0 deletions docs/rules/no-env-in-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# nuxt/no-env-in-context

> disallow `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`
- :gear: This rule is included in `"plugin:nuxt/base"`.

## Rule Details

This rule is for preventing using `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`

Examples of **incorrect** code for this rule:

```js

export default {
async asyncData() {
if(process.server) {
const foo = 'bar'
}
},
fetch() {
if(process.client) {
const foo = 'bar'
}
}
}

```

Examples of **correct** code for this rule:

```js

export default {
asyncData(context) {
if(context.isServer) {
const foo = 'bar'
}
},
fetch({ isClient }) {
if(isClient) {
const foo = 'bar'
}
}
}

```

## :mag: Implementation

- [Rule source](https://github.com/nuxt/eslint-plugin-nuxt/blob/master/lib/rules/no-env-in-context.js)
- [Test source](https://github.com/nuxt/eslint-plugin-nuxt/blob/master/lib/rules/__test__/no-env-in-context.test.js)
4 changes: 2 additions & 2 deletions lib/configs/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
es6: true
},
rules: {
'nuxt/no-this-in-fetch-data': 'error',
'nuxt/no-this-in-fetch': 'error'
'nuxt/no-env-in-context': 'error',
'nuxt/no-this-in-fetch-data': 'error'
}
}
125 changes: 125 additions & 0 deletions lib/rules/__test__/no-env-in-context.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/**
* @fileoverview disallow `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`
* @author Xin Du <clark.duxin@gmail.com>
*/
'use strict'

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

var rule = require('../no-env-in-context')

var RuleTester = require('eslint').RuleTester

const parserOptions = {
ecmaVersion: 2018,
sourceType: 'module'
}

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

var ruleTester = new RuleTester()
ruleTester.run('no-env-in-context', rule, {

valid: [
{
filename: 'test.vue',
code: `
export default {
async asyncData() {
if(process.server) {
const foo = 'bar'
}
},
fetch() {
if(process.client) {
const foo = 'bar'
}
}
}
`,
parserOptions
}
],

invalid: [
{
filename: 'test.vue',
code: `
export default {
asyncData(context) {
if(context.isServer) {
const foo = 'bar'
}
},
fetch(context) {
if(context.isClient) {
const foo = 'bar'
}
}
}
`,
errors: [{
message: 'Unexpected isServer in asyncData.',
type: 'MemberExpression'
}, {
message: 'Unexpected isClient in fetch.',
type: 'MemberExpression'
}],
parserOptions
},
{
filename: 'test.vue',
code: `
export default {
asyncData(context) {
if(context['isClient']) {
const foo = 'bar'
}
},
fetch(context) {
if(context['isServer']) {
const foo = 'bar'
}
}
}
`,
errors: [{
message: 'Unexpected isClient in asyncData.',
type: 'MemberExpression'
}, {
message: 'Unexpected isServer in fetch.',
type: 'MemberExpression'
}],
parserOptions
},
{
filename: 'test.vue',
code: `
export default {
asyncData({ isClient }) {
if(isClient) {
const foo = 'bar'
}
},
fetch({ isServer }) {
if(isServer) {
const foo = 'bar'
}
}
}
`,
errors: [{
message: 'Unexpected isClient in asyncData.',
type: 'Property'
}, {
message: 'Unexpected isServer in fetch.',
type: 'Property'
}],
parserOptions
}
]
})
83 changes: 83 additions & 0 deletions lib/rules/no-env-in-context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* @fileoverview disallow `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`
* @author Xin Du <clark.duxin@gmail.com>
*/
'use strict'

const utils = require('../utils')

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = {
meta: {
docs: {
description:
'disallow `context.isServer/context.isClient` in `asyncData/fetch/nuxtServerInit`',
category: 'base'
},
messages: {
noEnv: 'Unexpected {{env}} in {{funcName}}.'
}
},

create: function (context) {
// variables should be defined here
const forbiddenNodes = []
const options = context.options[0] || {}

const ENV = ['isServer', 'isClient']
const HOOKS = new Set(['asyncData', 'fetch'].concat(options.methods || []))

// ----------------------------------------------------------------------
// Public
// ----------------------------------------------------------------------

return {
MemberExpression (node) {
const propertyName = node.computed ? node.property.value : node.property.name
if (propertyName && ENV.includes(propertyName)) {
forbiddenNodes.push({ name: propertyName, node })
}
},
...utils.executeOnVue(context, obj => {
for (const funcName of HOOKS) {
const func = utils.getFunctionWithName(obj, funcName)
const param = func.value.params && func.value.params[0]
if (param) {
if (param.type === 'ObjectPattern') {
for (const prop of param.properties) {
if (ENV.includes(prop.key.name)) {
context.report({
node: prop,
messageId: 'noEnv',
data: {
env: prop.key.name,
funcName
}
})
}
}
} else {
for (const { name, node: child } of forbiddenNodes) {
if (utils.isInFunction(func, child)) {
if (param.name === child.object.name) {
context.report({
node: child,
messageId: 'noEnv',
data: {
env: name,
funcName
}
})
}
}
}
}
}
}
})
}
}
}
21 changes: 13 additions & 8 deletions lib/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ module.exports = Object.assign(
item => item.value.type === 'ArrowFunctionExpression' || item.value.type === 'FunctionExpression'
)
},
isInFunction (func, child) {
if (func.value.type === 'FunctionExpression') {
if (
child &&
child.loc.start.line >= func.value.loc.start.line &&
child.loc.end.line <= func.value.loc.end.line
) {
return true
}
}
},
* getFunctionWithChild (rootNode, funcNames, childNodes) {
const funcNodes = this.getProperties(rootNode, funcNames)

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

if (func.value.type === 'FunctionExpression') {
if (
child &&
child.loc.start.line >= func.value.loc.start.line &&
child.loc.end.line <= func.value.loc.end.line
) {
yield { name, node: child, funcName }
}
if (this.isInFunction(func, child)) {
yield { name, node: child, func, funcName }
}
}
}
Expand Down

0 comments on commit 71b09e9

Please sign in to comment.