Skip to content

Commit 47ade60

Browse files
authored
Add vue/no-deprecated-props-default-this rule (#1302)
* Add `vue/no-deprecated-props-default-this` rule * update comments
1 parent 1acb37d commit 47ade60

File tree

6 files changed

+367
-0
lines changed

6 files changed

+367
-0
lines changed

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
5050
| [vue/no-deprecated-functional-template](./no-deprecated-functional-template.md) | disallow using deprecated the `functional` template (in Vue.js 3.0.0+) | |
5151
| [vue/no-deprecated-html-element-is](./no-deprecated-html-element-is.md) | disallow using deprecated the `is` attribute on HTML elements (in Vue.js 3.0.0+) | |
5252
| [vue/no-deprecated-inline-template](./no-deprecated-inline-template.md) | disallow using deprecated `inline-template` attribute (in Vue.js 3.0.0+) | |
53+
| [vue/no-deprecated-props-default-this](./no-deprecated-props-default-this.md) | disallow props default function `this` access | |
5354
| [vue/no-deprecated-scope-attribute](./no-deprecated-scope-attribute.md) | disallow deprecated `scope` attribute (in Vue.js 2.5.0+) | :wrench: |
5455
| [vue/no-deprecated-slot-attribute](./no-deprecated-slot-attribute.md) | disallow deprecated `slot` attribute (in Vue.js 2.6.0+) | :wrench: |
5556
| [vue/no-deprecated-slot-scope-attribute](./no-deprecated-slot-scope-attribute.md) | disallow deprecated `slot-scope` attribute (in Vue.js 2.6.0+) | :wrench: |
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/no-deprecated-props-default-this
5+
description: disallow props default function `this` access
6+
---
7+
# vue/no-deprecated-props-default-this
8+
> disallow props default function `this` access
9+
10+
- :gear: This rule is included in all of `"plugin:vue/vue3-essential"`, `"plugin:vue/vue3-strongly-recommended"` and `"plugin:vue/vue3-recommended"`.
11+
12+
## :book: Rule Details
13+
14+
This rule reports the use of `this` within the props default value factory functions.
15+
In Vue.js 3.0.0+, props default value factory functions no longer have access to `this`.
16+
17+
See [Migration Guide - Props Default Function `this` Access](https://v3.vuejs.org/guide/migration/props-default-this.html) for more details.
18+
19+
<eslint-code-block :rules="{'vue/no-deprecated-props-default-this': ['error']}">
20+
21+
```vue
22+
<script>
23+
export default {
24+
props: {
25+
a: String,
26+
b: {
27+
default () {
28+
/* ✗ BAD */
29+
return this.a
30+
}
31+
}
32+
}
33+
}
34+
</script>
35+
```
36+
37+
</eslint-code-block>
38+
39+
<eslint-code-block :rules="{'vue/no-deprecated-props-default-this': ['error']}">
40+
41+
```vue
42+
<script>
43+
export default {
44+
props: {
45+
a: String,
46+
b: {
47+
default (props) {
48+
/* ✓ GOOD */
49+
return props.a
50+
}
51+
}
52+
}
53+
}
54+
</script>
55+
```
56+
57+
</eslint-code-block>
58+
59+
## :wrench: Options
60+
61+
Nothing.
62+
63+
## :books: Further Reading
64+
65+
- [Migration Guide - Props Default Function `this` Access](https://v3.vuejs.org/guide/migration/props-default-this.html)
66+
67+
## :mag: Implementation
68+
69+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-deprecated-props-default-this.js)
70+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-deprecated-props-default-this.js)

lib/configs/vue3-essential.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module.exports = {
1818
'vue/no-deprecated-functional-template': 'error',
1919
'vue/no-deprecated-html-element-is': 'error',
2020
'vue/no-deprecated-inline-template': 'error',
21+
'vue/no-deprecated-props-default-this': 'error',
2122
'vue/no-deprecated-scope-attribute': 'error',
2223
'vue/no-deprecated-slot-attribute': 'error',
2324
'vue/no-deprecated-slot-scope-attribute': 'error',

lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ module.exports = {
5959
'no-deprecated-functional-template': require('./rules/no-deprecated-functional-template'),
6060
'no-deprecated-html-element-is': require('./rules/no-deprecated-html-element-is'),
6161
'no-deprecated-inline-template': require('./rules/no-deprecated-inline-template'),
62+
'no-deprecated-props-default-this': require('./rules/no-deprecated-props-default-this'),
6263
'no-deprecated-scope-attribute': require('./rules/no-deprecated-scope-attribute'),
6364
'no-deprecated-slot-attribute': require('./rules/no-deprecated-slot-attribute'),
6465
'no-deprecated-slot-scope-attribute': require('./rules/no-deprecated-slot-scope-attribute'),
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* @author Yosuke Ota
3+
* See LICENSE file in root directory for full license.
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 props default function `this` access',
22+
categories: ['vue3-essential'],
23+
url:
24+
'https://eslint.vuejs.org/rules/no-deprecated-props-default-this.html'
25+
},
26+
fixable: null,
27+
schema: [],
28+
messages: {
29+
deprecated:
30+
'Props default value factory functions no longer have access to `this`.'
31+
}
32+
},
33+
/** @param {RuleContext} context */
34+
create(context) {
35+
/**
36+
* @typedef {object} ScopeStack
37+
* @property {ScopeStack | null} upper
38+
* @property {FunctionExpression | FunctionDeclaration} node
39+
* @property {boolean} propDefault
40+
*/
41+
/** @type {Set<FunctionExpression>} */
42+
const propsDefault = new Set()
43+
/** @type {ScopeStack | null} */
44+
let scopeStack = null
45+
46+
/**
47+
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
48+
*/
49+
function onFunctionEnter(node) {
50+
if (node.type === 'ArrowFunctionExpression') {
51+
return
52+
}
53+
if (scopeStack) {
54+
scopeStack = {
55+
upper: scopeStack,
56+
node,
57+
propDefault: false
58+
}
59+
} else if (node.type === 'FunctionExpression' && propsDefault.has(node)) {
60+
scopeStack = {
61+
upper: scopeStack,
62+
node,
63+
propDefault: true
64+
}
65+
}
66+
}
67+
68+
/**
69+
* @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node
70+
*/
71+
function onFunctionExit(node) {
72+
if (scopeStack && scopeStack.node === node) {
73+
scopeStack = scopeStack.upper
74+
}
75+
}
76+
return utils.defineVueVisitor(context, {
77+
onVueObjectEnter(node) {
78+
for (const prop of utils.getComponentProps(node)) {
79+
if (prop.type !== 'object') {
80+
continue
81+
}
82+
if (prop.value.type !== 'ObjectExpression') {
83+
continue
84+
}
85+
const def = utils.findProperty(prop.value, 'default')
86+
if (!def) {
87+
continue
88+
}
89+
if (def.value.type !== 'FunctionExpression') {
90+
continue
91+
}
92+
propsDefault.add(def.value)
93+
}
94+
},
95+
':function': onFunctionEnter,
96+
':function:exit': onFunctionExit,
97+
ThisExpression(node) {
98+
if (scopeStack && scopeStack.propDefault) {
99+
context.report({
100+
node,
101+
messageId: 'deprecated'
102+
})
103+
}
104+
}
105+
})
106+
}
107+
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/**
2+
* @author Yosuke Ota
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const rule = require('../../../lib/rules/no-deprecated-props-default-this')
12+
const RuleTester = require('eslint').RuleTester
13+
14+
// ------------------------------------------------------------------------------
15+
// Tests
16+
// ------------------------------------------------------------------------------
17+
18+
const ruleTester = new RuleTester({
19+
parser: require.resolve('vue-eslint-parser'),
20+
parserOptions: { ecmaVersion: 2020, sourceType: 'module' }
21+
})
22+
23+
ruleTester.run('no-deprecated-props-default-this', rule, {
24+
valid: [
25+
{
26+
filename: 'test.vue',
27+
code: `
28+
<template><div /></template>
29+
<script>
30+
export default {
31+
props: {
32+
a: String,
33+
b: {
34+
default (props) {
35+
return props.a
36+
}
37+
}
38+
}
39+
}
40+
</script>
41+
`
42+
},
43+
{
44+
filename: 'test.vue',
45+
code: `
46+
<template><div /></template>
47+
<script>
48+
export default {
49+
props: {
50+
a: String,
51+
b: {
52+
default: () => {
53+
return this.a
54+
}
55+
}
56+
}
57+
}
58+
</script>
59+
`
60+
},
61+
{
62+
filename: 'test.vue',
63+
code: `
64+
<template><div /></template>
65+
<script>
66+
export default {
67+
props: {
68+
a: String,
69+
b: {
70+
default () {
71+
return function () {
72+
return this.a
73+
}
74+
}
75+
}
76+
}
77+
}
78+
</script>
79+
`,
80+
errors: [{}, {}]
81+
},
82+
{
83+
filename: 'test.vue',
84+
code: `
85+
<template><div /></template>
86+
<script>
87+
const Foo = {
88+
props: {
89+
a: String,
90+
b: {
91+
default () {
92+
return this.a
93+
}
94+
}
95+
}
96+
}
97+
</script>
98+
`
99+
}
100+
],
101+
102+
invalid: [
103+
{
104+
filename: 'test.vue',
105+
code: `
106+
<template><div /></template>
107+
<script>
108+
export default {
109+
props: {
110+
a: String,
111+
b: {
112+
default () {
113+
return this.a
114+
}
115+
}
116+
}
117+
}
118+
</script>
119+
`,
120+
errors: [
121+
{
122+
message:
123+
'Props default value factory functions no longer have access to `this`.',
124+
line: 9,
125+
column: 24,
126+
endLine: 9,
127+
endColumn: 28
128+
}
129+
]
130+
},
131+
{
132+
filename: 'test.vue',
133+
code: `
134+
<template><div /></template>
135+
<script>
136+
export default {
137+
props: {
138+
a: String,
139+
b: {
140+
default () {
141+
return () => this.a
142+
}
143+
}
144+
}
145+
}
146+
</script>
147+
`,
148+
errors: [
149+
{
150+
message:
151+
'Props default value factory functions no longer have access to `this`.',
152+
line: 9,
153+
column: 30,
154+
endLine: 9,
155+
endColumn: 34
156+
}
157+
]
158+
},
159+
{
160+
filename: 'test.vue',
161+
code: `
162+
<template><div /></template>
163+
<script>
164+
export default {
165+
props: {
166+
a: String,
167+
b: {
168+
default () {
169+
return this.a
170+
}
171+
},
172+
c: {
173+
default () {
174+
return this.a
175+
}
176+
}
177+
}
178+
}
179+
</script>
180+
`,
181+
errors: [
182+
'Props default value factory functions no longer have access to `this`.',
183+
'Props default value factory functions no longer have access to `this`.'
184+
]
185+
}
186+
]
187+
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy