Skip to content

Commit 76f835a

Browse files
feat(no-this-in-before-router-enter): create rule (#1506)
* feat(no-this-in-before-router-enter): create rule * Update lib/rules/no-this-in-before-route-enter.js Co-authored-by: Yosuke Ota <[email protected]> * Update docs/rules/no-this-in-before-route-enter.md Co-authored-by: Yosuke Ota <[email protected]> * feat(no-this-in-before-router-enter): create rule Update lib/rules/no-this-in-before-route-enter.js Co-authored-by: Yosuke Ota <[email protected]> Update docs/rules/no-this-in-before-route-enter.md Co-authored-by: Yosuke Ota <[email protected]> * (feat): update test assertions for no-this-in-before-route-enter rule * (feat): update docs for no-this-in-before-route-enter Co-authored-by: Yosuke Ota <[email protected]>
1 parent ea6f9f0 commit 76f835a

File tree

5 files changed

+398
-0
lines changed

5 files changed

+398
-0
lines changed

docs/rules/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ For example:
313313
| [vue/no-restricted-v-bind](./no-restricted-v-bind.md) | disallow specific argument in `v-bind` | |
314314
| [vue/no-static-inline-styles](./no-static-inline-styles.md) | disallow static inline `style` attributes | |
315315
| [vue/no-template-target-blank](./no-template-target-blank.md) | disallow target="_blank" attribute without rel="noopener noreferrer" | |
316+
| [vue/no-this-in-before-route-enter](./no-this-in-before-route-enter.md) | disallow this usage in a beforeRouteEnter method | |
316317
| [vue/no-unregistered-components](./no-unregistered-components.md) | disallow using components that are not registered inside templates | |
317318
| [vue/no-unsupported-features](./no-unsupported-features.md) | disallow unsupported Vue.js syntax on the specified version | :wrench: |
318319
| [vue/no-unused-properties](./no-unused-properties.md) | disallow unused properties | |
+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/no-this-in-before-route-enter
5+
description: disallow this usage in a beforeRouteEnter method
6+
---
7+
# vue/no-this-in-before-route-enter
8+
9+
> disallow this usage in a beforeRouteEnter method
10+
11+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
12+
13+
## Rule Details
14+
15+
Because lack of `this` in the `beforeRouteEnter` [(docs)](https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards). This behavior isn't obvious, so it's pretty easy to make a `TypeError`. Especially during some refactor.
16+
17+
Bad:
18+
19+
<eslint-code-block :rules="{'vue/no-this-in-before-route-enter': ['error']}">
20+
21+
```vue
22+
<script>
23+
export default {
24+
beforeRouteEnter() {
25+
this.method(); // Uncaught TypeError: Cannot read property 'method' of undefined
26+
}
27+
}
28+
</script>
29+
```
30+
31+
</eslint-code-block>
32+
33+
Bad:
34+
35+
<eslint-code-block :rules="{'vue/no-this-in-before-route-enter': ['error']}">
36+
37+
```vue
38+
<script>
39+
export default {
40+
beforeRouteEnter() {
41+
this.attribute = 42;
42+
}
43+
}
44+
</script>
45+
```
46+
47+
</eslint-code-block>
48+
49+
Bad:
50+
51+
<eslint-code-block :rules="{'vue/no-this-in-before-route-enter': ['error']}">
52+
53+
```vue
54+
<script>
55+
export default {
56+
beforeRouteEnter() {
57+
if (this.value === 42) {
58+
59+
}
60+
}
61+
}
62+
</script>
63+
```
64+
65+
</eslint-code-block>
66+
67+
68+
Bad:
69+
70+
<eslint-code-block :rules="{'vue/no-this-in-before-route-enter': ['error']}">
71+
72+
```vue
73+
<script>
74+
export default {
75+
beforeRouteEnter() {
76+
this.attribute = this.method();
77+
}
78+
}
79+
</script>
80+
```
81+
82+
</eslint-code-block>
83+
84+
Good:
85+
86+
<eslint-code-block :rules="{'vue/no-this-in-before-route-enter': ['error']}">
87+
88+
```vue
89+
<script>
90+
export default {
91+
beforeRouteEnter() {
92+
// anything without this
93+
}
94+
}
95+
</script>
96+
```
97+
98+
</eslint-code-block>
99+
100+
### Options
101+
102+
Nothing.
103+
104+
## When Not To Use It
105+
106+
When [vue-router](https://router.vuejs.org/) is not installed.
107+
108+
## Further Reading
109+
110+
[vue-router - in-component-guards](https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards)
111+
112+
## :mag: Implementation
113+
114+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-this-in-before-route-enter.js)
115+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-this-in-before-route-enter.js)

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ module.exports = {
113113
'no-template-shadow': require('./rules/no-template-shadow'),
114114
'no-template-target-blank': require('./rules/no-template-target-blank'),
115115
'no-textarea-mustache': require('./rules/no-textarea-mustache'),
116+
'no-this-in-before-route-enter': require('./rules/no-this-in-before-route-enter'),
116117
'no-unregistered-components': require('./rules/no-unregistered-components'),
117118
'no-unsupported-features': require('./rules/no-unsupported-features'),
118119
'no-unused-components': require('./rules/no-unused-components'),
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* @fileoverview Don't use this in a beforeRouteEnter method
3+
* @author Przemyslaw Jan Beigert
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const utils = require('../utils')
12+
13+
// ------------------------------------------------------------------------------
14+
// Rule Definition
15+
// ------------------------------------------------------------------------------
16+
17+
module.exports = {
18+
meta: {
19+
type: 'problem',
20+
docs: {
21+
description: 'disallow this usage in a beforeRouteEnter method',
22+
categories: null,
23+
url: 'https://eslint.vuejs.org/rules/no-this-in-before-route-enter.html'
24+
},
25+
fixable: null,
26+
schema: [],
27+
messages: {
28+
disallow:
29+
"'beforeRouteEnter' does NOT have access to `this` component instance. https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards."
30+
}
31+
},
32+
/** @param {RuleContext} context */
33+
create(context) {
34+
/**
35+
* @typedef {object} ScopeStack
36+
* @property {ScopeStack | null} upper
37+
* @property {FunctionExpression | FunctionDeclaration} node
38+
* @property {boolean} beforeRouteEnter
39+
*/
40+
/** @type {Set<FunctionExpression>} */
41+
const beforeRouteEnterFunctions = new Set()
42+
/** @type {ScopeStack | null} */
43+
let scopeStack = null
44+
45+
/**
46+
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
47+
*/
48+
function onFunctionEnter(node) {
49+
if (node.type === 'ArrowFunctionExpression') {
50+
return
51+
}
52+
scopeStack = {
53+
upper: scopeStack,
54+
node,
55+
beforeRouteEnter: beforeRouteEnterFunctions.has(
56+
/** @type {never} */ (node)
57+
)
58+
}
59+
}
60+
61+
/**
62+
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
63+
*/
64+
function onFunctionExit(node) {
65+
if (scopeStack && scopeStack.node === node) {
66+
scopeStack = scopeStack.upper
67+
}
68+
}
69+
return utils.defineVueVisitor(context, {
70+
onVueObjectEnter(node) {
71+
const beforeRouteEnter = utils.findProperty(node, 'beforeRouteEnter')
72+
if (
73+
beforeRouteEnter &&
74+
beforeRouteEnter.value.type === 'FunctionExpression'
75+
) {
76+
beforeRouteEnterFunctions.add(beforeRouteEnter.value)
77+
}
78+
},
79+
':function': onFunctionEnter,
80+
':function:exit': onFunctionExit,
81+
ThisExpression(node) {
82+
if (scopeStack && scopeStack.beforeRouteEnter) {
83+
context.report({
84+
node,
85+
messageId: 'disallow'
86+
})
87+
}
88+
}
89+
})
90+
}
91+
}

0 commit comments

Comments
 (0)