Skip to content

Commit 1b3c085

Browse files
committed
Add options to no-this-in-template.
fixes vuejs#148
1 parent b25be73 commit 1b3c085

File tree

4 files changed

+175
-59
lines changed

4 files changed

+175
-59
lines changed

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

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
# Disallow usage of `this` in template. (no-this-in-template)
2-
3-
This rule reports expresions that contain `this` keyword in expressions
1+
# enforce usage of `this` in template. (no-this-in-template)
42

53
## :book: Rule Details
64

@@ -22,4 +20,52 @@ This rule reports expresions that contain `this` keyword in expressions
2220

2321
## :wrench: Options
2422

25-
Nothing.
23+
Default is set to `never`.
24+
25+
```
26+
'vue/no-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+
```

docs/rules/require-render-return.md

Lines changed: 1 addition & 1 deletion
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

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

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* @fileoverview Disallow usage of `this` in template.
2+
* @fileoverview enforce usage of `this` in template.
33
* @author Armano
44
*/
55
'use strict'
@@ -17,12 +17,16 @@ const utils = require('../utils')
1717
module.exports = {
1818
meta: {
1919
docs: {
20-
description: 'Disallow usage of `this` in template.',
20+
description: 'enforce usage of `this` in template.',
2121
category: 'Best Practices',
2222
recommended: false
2323
},
2424
fixable: null,
25-
schema: []
25+
schema: [
26+
{
27+
enum: ['always', 'never']
28+
}
29+
]
2630
},
2731

2832
/**
@@ -32,15 +36,63 @@ module.exports = {
3236
* @returns {Object} AST event handlers.
3337
*/
3438
create (context) {
35-
utils.registerTemplateBodyVisitor(context, {
36-
'VExpressionContainer ThisExpression' (node) {
37-
context.report({
38-
node,
39-
loc: node.loc,
40-
message: "Unexpected usage of 'this'."
41-
})
39+
const options = context.options[0] !== 'always' ? 'never' : 'always'
40+
let scope = {
41+
parent: null,
42+
nodes: []
43+
}
44+
45+
function validateNever () {
46+
return {
47+
'VExpressionContainer ThisExpression' (node) {
48+
if (options === 'never') {
49+
context.report({
50+
node,
51+
loc: node.loc,
52+
message: "Unexpected usage of 'this'."
53+
})
54+
}
55+
}
4256
}
43-
})
57+
}
58+
59+
function validateAlways () {
60+
return {
61+
'VExpressionContainer' (node) {
62+
if (node.references && options === 'always') {
63+
for (const reference of node.references) {
64+
if (!scope.nodes.some(node => node.name === reference.id.name)) {
65+
context.report({
66+
node: reference.id,
67+
loc: reference.id.loc,
68+
message: "Expected 'this'."
69+
})
70+
}
71+
}
72+
}
73+
},
74+
VElement (node) {
75+
scope = {
76+
parent: scope,
77+
nodes: scope.nodes.slice() // make copy
78+
}
79+
if (node.variables) {
80+
for (const variable of node.variables) {
81+
const varNode = variable.id
82+
const name = varNode.name
83+
if (!scope.nodes.some(node => node.name === name)) { // Prevent adding duplicates
84+
scope.nodes.push(varNode)
85+
}
86+
}
87+
}
88+
},
89+
'VElement:exit' (node) {
90+
scope = scope.parent
91+
}
92+
}
93+
}
94+
95+
utils.registerTemplateBodyVisitor(context, options === 'never' ? validateNever() : validateAlways())
4496

4597
return {}
4698
}
Lines changed: 61 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* @fileoverview Disallow usage of `this` in template.
2+
* @fileoverview enforce usage of `this` in template.
33
* @author Armano
44
*/
55
'use strict'
@@ -21,59 +21,77 @@ const ruleTester = new RuleTester({
2121
parserOptions: { ecmaVersion: 2015 }
2222
})
2323

24-
ruleTester.run('no-this-in-template', rule, {
25-
valid: [
26-
'',
27-
'<template></template>',
28-
'<template><div></div></template>',
29-
'<template><div>{{ foo.bar }}</div></template>',
30-
'<template><div v-for="foo in bar">{{ foo }}</div></template>',
31-
'<template><div v-if="foo">{{ foo }}</div></template>',
32-
'<template><div :class="foo">{{ foo }}</div></template>',
33-
'<template><div :class="{this: foo}">{{ foo }}</div></template>'
34-
],
35-
invalid: [
24+
function createValidTests (prefix, options) {
25+
return [
3626
{
37-
code: '<template><div>{{ this.foo }}</div></template>',
38-
errors: [{
39-
message: "Unexpected usage of 'this'.",
40-
type: 'ThisExpression'
41-
}]
27+
code: `<template><div>{{ ${prefix}foo.bar }}</div></template><!-- ${options.join('')} -->`,
28+
options
4229
},
4330
{
44-
code: '<template><div :class="this.foo"></div></template>',
45-
errors: [{
46-
message: "Unexpected usage of 'this'.",
47-
type: 'ThisExpression'
48-
}]
31+
code: `<template><div v-for="foo in ${prefix}bar">{{ foo }}</div></template><!-- ${options.join('')} -->`,
32+
options
4933
},
5034
{
51-
code: '<template><div :class="{foo: this.foo}"></div></template>',
52-
errors: [{
53-
message: "Unexpected usage of 'this'.",
54-
type: 'ThisExpression'
55-
}]
35+
code: `<template><div v-if="${prefix}foo">{{ ${prefix}foo }}</div></template><!-- ${options.join('')} -->`,
36+
options
5637
},
5738
{
58-
code: '<template><div :class="{foo: this.foo()}"></div></template>',
59-
errors: [{
60-
message: "Unexpected usage of 'this'.",
61-
type: 'ThisExpression'
62-
}]
39+
code: `<template><div :class="${prefix}foo">{{ ${prefix}foo }}</div></template><!-- ${options.join('')} -->`,
40+
options
6341
},
6442
{
65-
code: '<template><div v-if="this.foo"></div></template>',
66-
errors: [{
67-
message: "Unexpected usage of 'this'.",
68-
type: 'ThisExpression'
69-
}]
43+
code: `<template><div :class="{this: ${prefix}foo}">{{ ${prefix}foo }}</div></template><!-- ${options.join('')} -->`,
44+
options
7045
},
7146
{
72-
code: '<template><div v-for="foo in this.bar"></div></template>',
73-
errors: [{
74-
message: "Unexpected usage of 'this'.",
75-
type: 'ThisExpression'
76-
}]
47+
code: `<template><div v-for="bar in ${prefix}foo" v-if="bar">{{ bar }}</div></template><!-- ${options.join('')} -->`,
48+
options
7749
}
7850
]
51+
}
52+
53+
function createInvalidTests (prefix, options, message, type) {
54+
return [
55+
{
56+
code: `<template><div>{{ ${prefix}foo }}</div></template><!-- ${options.join('')} -->`,
57+
errors: [{ message, type }],
58+
options
59+
},
60+
{
61+
code: `<template><div :class="${prefix}foo"></div></template><!-- ${options.join('')} -->`,
62+
errors: [{ message, type }],
63+
options
64+
},
65+
{
66+
code: `<template><div :class="{foo: ${prefix}foo}"></div></template><!-- ${options.join('')} -->`,
67+
errors: [{ message, type }],
68+
options
69+
},
70+
{
71+
code: `<template><div :class="{foo: ${prefix}foo()}"></div></template><!-- ${options.join('')} -->`,
72+
errors: [{ message, type }],
73+
options
74+
},
75+
{
76+
code: `<template><div v-if="${prefix}foo"></div></template><!-- ${options.join('')} -->`,
77+
errors: [{ message, type }],
78+
options
79+
},
80+
{
81+
code: `<template><div v-for="foo in ${prefix}bar"></div></template><!-- ${options.join('')} -->`,
82+
errors: [{ message, type }],
83+
options
84+
}
85+
]
86+
}
87+
88+
ruleTester.run('no-this-in-template', rule, {
89+
valid: ['', '<template></template>', '<template><div></div></template>']
90+
.concat(createValidTests('', []))
91+
.concat(createValidTests('', ['never']))
92+
.concat(createValidTests('this.', ['always'])),
93+
invalid: []
94+
.concat(createInvalidTests('this.', [], "Unexpected usage of 'this'.", 'ThisExpression'))
95+
.concat(createInvalidTests('this.', ['never'], "Unexpected usage of 'this'.", 'ThisExpression'))
96+
.concat(createInvalidTests('', ['always'], "Expected 'this'.", 'Identifier'))
7997
})

0 commit comments

Comments
 (0)