Skip to content

Commit a73f5e2

Browse files
armano2mysticatea
authored andcommitted
Rename and add options to this-in-template. (vuejs#163)
* Add options to `no-this-in-template`. fixes vuejs#148 * Add few more advanced tests * Rename `no-this-in-template` to `this-in-template` * Add more edge cases * Do not remove `this.` when word is reserved * Add checks for *array like* accesed properties withc can't be converted to properties
1 parent a6feec3 commit a73f5e2

9 files changed

+376
-153
lines changed

docs/rules/no-this-in-template.md

-25
This file was deleted.

docs/rules/require-render-return.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Enforces render function to always return value (require-render-return)
22

3-
This rule aims to enforce render function to allways return value
3+
This rule aims to enforce render function to always return value
44

55
## :book: Rule Details
66

docs/rules/this-in-template.md

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# enforce usage of `this` in template. (this-in-template)
2+
3+
## :book: Rule Details
4+
5+
:-1: Examples of **incorrect** code for this rule:
6+
7+
```html
8+
<template>
9+
<a :href="this.link">{{this.text}}</a>
10+
</template>
11+
```
12+
13+
:+1: Examples of **correct** code for this rule:
14+
15+
```html
16+
<template>
17+
<a :href="link">{{text}}</a>
18+
</template>
19+
```
20+
21+
## :wrench: Options
22+
23+
Default is set to `never`.
24+
25+
```
26+
'vue/this-in-template': [2, 'always'|'never']
27+
```
28+
29+
### `"always"` - Always use `this` while accessing properties from vue
30+
31+
:+1: Examples of **correct** code`:
32+
33+
```html
34+
<template>
35+
<div :class="{'show': this.showFoo}">
36+
{{ this.foo }}
37+
</div>
38+
</template>
39+
```
40+
41+
:-1: Examples of **incorrect** code`:
42+
43+
```html
44+
<template>
45+
<div :class="{'show': showFoo}">
46+
{{ foo }}
47+
</div>
48+
</template>
49+
```
50+
51+
### `"never"` - Never use expresions that contain `this` keyword in expressions
52+
53+
:+1: Examples of **correct** code`:
54+
55+
```html
56+
<template>
57+
<div :class="{'show': this.showFoo}">
58+
{{ this.foo }}
59+
</div>
60+
</template>
61+
```
62+
63+
:-1: Examples of **incorrect** code`:
64+
65+
```html
66+
<template>
67+
<div :class="{'show': showFoo}">
68+
{{ foo }}
69+
</div>
70+
</template>
71+
```

lib/rules/no-this-in-template.js

-47
This file was deleted.

lib/rules/this-in-template.js

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* @fileoverview enforce usage of `this` in template.
3+
* @author Armano
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const utils = require('../utils')
12+
const RESERVED_NAMES = new Set(require('../utils/js-reserved.json'))
13+
14+
// ------------------------------------------------------------------------------
15+
// Rule Definition
16+
// ------------------------------------------------------------------------------
17+
18+
module.exports = {
19+
meta: {
20+
docs: {
21+
description: 'enforce usage of `this` in template.',
22+
category: 'Best Practices',
23+
recommended: false
24+
},
25+
fixable: null,
26+
schema: [
27+
{
28+
enum: ['always', 'never']
29+
}
30+
]
31+
},
32+
33+
/**
34+
* Creates AST event handlers for this-in-template.
35+
*
36+
* @param {RuleContext} context - The rule context.
37+
* @returns {Object} AST event handlers.
38+
*/
39+
create (context) {
40+
const options = context.options[0] !== 'always' ? 'never' : 'always'
41+
let scope = {
42+
parent: null,
43+
nodes: []
44+
}
45+
46+
utils.registerTemplateBodyVisitor(context, Object.assign({
47+
VElement (node) {
48+
scope = {
49+
parent: scope,
50+
nodes: scope.nodes.slice() // make copy
51+
}
52+
if (node.variables) {
53+
for (const variable of node.variables) {
54+
const varNode = variable.id
55+
const name = varNode.name
56+
if (!scope.nodes.some(node => node.name === name)) { // Prevent adding duplicates
57+
scope.nodes.push(varNode)
58+
}
59+
}
60+
}
61+
},
62+
'VElement:exit' (node) {
63+
scope = scope.parent
64+
}
65+
}, options === 'never'
66+
? {
67+
'VExpressionContainer MemberExpression > ThisExpression' (node) {
68+
const propertyName = utils.getStaticPropertyName(node.parent.property)
69+
if (!propertyName ||
70+
scope.nodes.some(el => el.name === propertyName) ||
71+
RESERVED_NAMES.has(propertyName) || // this.class | this['class']
72+
/^[0-9].*$|[^a-zA-Z0-9_]/.test(propertyName) // this['0aaaa'] | this['foo-bar bas']
73+
) {
74+
return
75+
}
76+
77+
context.report({
78+
node,
79+
loc: node.loc,
80+
message: "Unexpected usage of 'this'."
81+
})
82+
}
83+
}
84+
: {
85+
'VExpressionContainer' (node) {
86+
if (node.references) {
87+
for (const reference of node.references) {
88+
if (!scope.nodes.some(el => el.name === reference.id.name)) {
89+
context.report({
90+
node: reference.id,
91+
loc: reference.id.loc,
92+
message: "Expected 'this'."
93+
})
94+
}
95+
}
96+
}
97+
}
98+
}
99+
))
100+
101+
return {}
102+
}
103+
}

lib/utils/js-reserved.json

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[
2+
"abstract", "arguments", "await", "boolean",
3+
"break", "byte", "case", "catch",
4+
"char", "class", "const", "continue",
5+
"debugger", "default", "delete", "do",
6+
"double", "else", "enum", "eval",
7+
"export", "extends", "false", "final",
8+
"finally", "float", "for", "function",
9+
"goto", "if", "implements", "import",
10+
"in", "instanceof", "int", "interface",
11+
"let", "long", "native", "new",
12+
"null", "package", "private", "protected",
13+
"public", "return", "short", "static",
14+
"super", "switch", "synchronized", "this",
15+
"throw", "throws", "transient", "true",
16+
"try", "typeof", "var", "void",
17+
"volatile", "while", "with", "yield"
18+
]

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
},
4646
"dependencies": {
4747
"requireindex": "^1.1.0",
48-
"vue-eslint-parser": "2.0.0-beta.7"
48+
"vue-eslint-parser": "2.0.0-beta.10"
4949
},
5050
"devDependencies": {
5151
"@types/node": "^4.2.16",

tests/lib/rules/no-this-in-template.js

-79
This file was deleted.

0 commit comments

Comments
 (0)