Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit61611ca

Browse files
committed
Add new vue/require-mayberef-unwrap rule
1 parent3d9e15e commit61611ca

File tree

5 files changed

+657
-0
lines changed

5 files changed

+657
-0
lines changed

‎docs/rules/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ Rules in this category are enabled for all presets provided by eslint-plugin-vue
9797
|[vue/no-watch-after-await]| disallow asynchronously registered`watch`||:three::hammer:|
9898
|[vue/prefer-import-from-vue]| enforce import from 'vue' instead of import from '@vue/*'|:wrench:|:three::hammer:|
9999
|[vue/require-component-is]| require`v-bind:is` of`<component>` elements||:three::two::warning:|
100+
|[vue/require-mayberef-unwrap]| require`MaybeRef` values to be unwrapped with`unref()` before using in conditions|:bulb:|:three::warning:|
100101
|[vue/require-prop-type-constructor]| require prop type to be a constructor|:wrench:|:three::two::hammer:|
101102
|[vue/require-render-return]| enforce render function to always return value||:three::two::warning:|
102103
|[vue/require-slots-as-functions]| enforce properties of`$slots` to be used as a function||:three::warning:|
@@ -564,6 +565,7 @@ The following rules extend the rules provided by ESLint itself and apply them to
564565
[vue/require-explicit-slots]:./require-explicit-slots.md
565566
[vue/require-expose]:./require-expose.md
566567
[vue/require-macro-variable-name]:./require-macro-variable-name.md
568+
[vue/require-mayberef-unwrap]:./require-mayberef-unwrap.md
567569
[vue/require-name-property]:./require-name-property.md
568570
[vue/require-prop-comment]:./require-prop-comment.md
569571
[vue/require-prop-type-constructor]:./require-prop-type-constructor.md

‎docs/rules/require-mayberef-unwrap.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
pageClass:rule-details
3+
sidebarDepth:0
4+
title:vue/require-mayberef-unwrap
5+
description:require `MaybeRef` values to be unwrapped with `unref()` before using in conditions
6+
---
7+
8+
#vue/require-mayberef-unwrap
9+
10+
>require`MaybeRef` values to be unwrapped with`unref()` before using in conditions
11+
12+
-:gear: This rule is included in all of`"plugin:vue/essential"`,`*.configs["flat/essential"]`,`"plugin:vue/strongly-recommended"`,`*.configs["flat/strongly-recommended"]`,`"plugin:vue/recommended"` and`*.configs["flat/recommended"]`.
13+
-:bulb: Some problems reported by this rule are manually fixable by editor[suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
14+
15+
##:book: Rule Details
16+
17+
`MaybeRef<T>` and`MaybeRefOrGetter<T>` are TypeScript utility types provided by Vue.
18+
They allow a value to be either a plain value**or** a`Ref<T>`. When such a variable is used in a boolean context you must first unwrap it with`unref()` so that the actual inner value is evaluated.
19+
This rule reports (and can auto-fix) places where a`MaybeRef*` value is used directly in a conditional expression, logical expression, unary operator, etc.
20+
21+
<eslint-code-blockfix:rules="{'vue/require-mayberef-unwrap': ['error']}">
22+
23+
```vue
24+
<script setup lang="ts">
25+
import { ref, unref, type MaybeRef } from 'vue'
26+
27+
const maybeRef: MaybeRef<boolean> = ref(false)
28+
29+
/* ✓ GOOD */
30+
if (unref(maybeRef)) {
31+
console.log('good')
32+
}
33+
const result = unref(maybeRef) ? 'true' : 'false'
34+
35+
/* ✗ BAD */
36+
if (maybeRef) {
37+
console.log('bad')
38+
}
39+
const alt = maybeRef ? 'true' : 'false'
40+
</script>
41+
```
42+
43+
</eslint-code-block>
44+
45+
###What is considered**incorrect** ?
46+
47+
The following patterns are**incorrect**:
48+
49+
```ts
50+
// Condition without unref
51+
if (maybeRef) {}
52+
53+
// Ternary operator
54+
const result=maybeRef?'a':'b'
55+
56+
// Logical expressions
57+
const value=maybeRef||'fallback'
58+
59+
// Unary operators
60+
const negated=!maybeRef
61+
62+
// Type queries & wrappers
63+
const t=typeofmaybeRef
64+
const b=Boolean(maybeRef)
65+
```
66+
67+
###What is considered**correct** ?
68+
69+
```ts
70+
if (unref(maybeRef)) {}
71+
const result=unref(maybeRef)?'a':'b'
72+
```
73+
74+
##:wrench: Options
75+
76+
Nothing.
77+
78+
##:books: Further Reading
79+
80+
-[Guide – Reactivity –`unref`](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#unref)
81+
-[API –`MaybeRef`](https://vuejs.org/api/utility-types.html#mayberef)
82+
-[API –`MaybeRefOrGetter`](https://vuejs.org/api/utility-types.html#maybereforgetter)
83+
84+
##:rocket: Version
85+
86+
This rule will be introduced in a future release of eslint-plugin-vue.
87+
88+
##:mag: Implementation
89+
90+
-[Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/require-mayberef-unwrap.js)
91+
-[Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/require-mayberef-unwrap.js)

‎lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ const plugin = {
223223
'require-explicit-slots':require('./rules/require-explicit-slots'),
224224
'require-expose':require('./rules/require-expose'),
225225
'require-macro-variable-name':require('./rules/require-macro-variable-name'),
226+
'require-mayberef-unwrap':require('./rules/require-mayberef-unwrap'),
226227
'require-name-property':require('./rules/require-name-property'),
227228
'require-prop-comment':require('./rules/require-prop-comment'),
228229
'require-prop-type-constructor':require('./rules/require-prop-type-constructor'),

‎lib/rules/require-mayberef-unwrap.js

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/**
2+
*@author 2nofa11
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const{ findVariable}=require('@eslint-community/eslint-utils')
8+
constutils=require('../utils')
9+
10+
/**
11+
* Check TypeScript type node for MaybeRef/MaybeRefOrGetter
12+
*@param {import('@typescript-eslint/types').TSESTree.TypeNode | undefined} typeNode
13+
*@returns {boolean}
14+
*/
15+
functionisMaybeRefTypeNode(typeNode){
16+
if(!typeNode)returnfalse
17+
if(
18+
typeNode.type==='TSTypeReference'&&
19+
typeNode.typeName&&
20+
typeNode.typeName.type==='Identifier'
21+
){
22+
return(
23+
typeNode.typeName.name==='MaybeRef'||
24+
typeNode.typeName.name==='MaybeRefOrGetter'
25+
)
26+
}
27+
if(typeNode.type==='TSUnionType'){
28+
returntypeNode.types.some((t)=>isMaybeRefTypeNode(t))
29+
}
30+
returnfalse
31+
}
32+
33+
module.exports={
34+
meta:{
35+
type:'problem',
36+
docs:{
37+
description:
38+
'require `MaybeRef` values to be unwrapped with `unref()` before using in conditions',
39+
categories:undefined,
40+
url:'https://eslint.vuejs.org/rules/require-mayberef-unwrap.html'
41+
},
42+
fixable:null,
43+
hasSuggestions:true,
44+
schema:[],
45+
messages:{
46+
requireUnref:
47+
'MaybeRef should be unwrapped with `unref()` before using in conditions. Use `unref({{name}})` instead.',
48+
wrapWithUnref:'Wrap with unref().'
49+
}
50+
},
51+
/**@param {RuleContext} context */
52+
create(context){
53+
/**
54+
* Determine if identifier should be considered MaybeRef
55+
*@param {Identifier} node
56+
*/
57+
functionisMaybeRef(node){
58+
constvariable=findVariable(utils.getScope(context,node),node)
59+
constid=variable?.defs[0]?.node?.id
60+
if(id?.type==='Identifier'&&id.typeAnnotation){
61+
returnisMaybeRefTypeNode(id.typeAnnotation.typeAnnotation)
62+
}
63+
returnfalse
64+
}
65+
66+
/**
67+
* Reports if the identifier is a MaybeRef type
68+
*@param {Identifier} node
69+
*/
70+
functionreportIfMaybeRef(node){
71+
if(!isMaybeRef(node))return
72+
73+
constsourceCode=context.getSourceCode()
74+
context.report({
75+
node,
76+
messageId:'requireUnref',
77+
data:{name:node.name},
78+
suggest:[
79+
{
80+
messageId:'wrapWithUnref',
81+
/**@param {*} fixer */
82+
fix(fixer){
83+
returnfixer.replaceText(
84+
node,
85+
`unref(${sourceCode.getText(node)})`
86+
)
87+
}
88+
}
89+
]
90+
})
91+
}
92+
93+
return{
94+
// if (maybeRef)
95+
/**@param {Identifier} node */
96+
'IfStatement>Identifier'(node){
97+
reportIfMaybeRef(node)
98+
},
99+
// maybeRef ? x : y
100+
/**@param {Identifier & {parent: ConditionalExpression}} node */
101+
'ConditionalExpression>Identifier'(node){
102+
if(node.parent.test===node){
103+
reportIfMaybeRef(node)
104+
}
105+
},
106+
// !maybeRef, +maybeRef, -maybeRef, ~maybeRef, typeof maybeRef
107+
/**@param {Identifier} node */
108+
'UnaryExpression>Identifier'(node){
109+
reportIfMaybeRef(node)
110+
},
111+
// maybeRef || other, maybeRef && other, maybeRef ?? other
112+
/**@param {Identifier & {parent: LogicalExpression}} node */
113+
'LogicalExpression>Identifier'(node){
114+
reportIfMaybeRef(node)
115+
},
116+
// maybeRef == x, maybeRef != x, maybeRef === x, maybeRef !== x
117+
/**@param {Identifier} node */
118+
'BinaryExpression>Identifier'(node){
119+
reportIfMaybeRef(node)
120+
},
121+
// Boolean(maybeRef), String(maybeRef)
122+
/**@param {Identifier} node */
123+
'CallExpression>Identifier'(node){
124+
if(
125+
node.parent&&
126+
node.parent.type==='CallExpression'&&
127+
node.parent.callee&&
128+
node.parent.callee.type==='Identifier'&&
129+
['Boolean','String'].includes(node.parent.callee.name)&&
130+
node.parent.arguments[0]===node
131+
){
132+
reportIfMaybeRef(node)
133+
}
134+
}
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp