Skip to content

Commit

Permalink
fix(prefer-use-template-ref): add support for shallowRef (#2608)
Browse files Browse the repository at this point in the history
  • Loading branch information
ntnyq authored Nov 18, 2024
1 parent 16c8778 commit 4500389
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 13 deletions.
2 changes: 1 addition & 1 deletion docs/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ For example:
| [vue/prefer-prop-type-boolean-first](./prefer-prop-type-boolean-first.md) | enforce `Boolean` comes first in component prop types | :bulb: | :warning: |
| [vue/prefer-separate-static-class](./prefer-separate-static-class.md) | require static class names in template to be in a separate `class` attribute | :wrench: | :hammer: |
| [vue/prefer-true-attribute-shorthand](./prefer-true-attribute-shorthand.md) | require shorthand form attribute when `v-bind` value is `true` | :bulb: | :hammer: |
| [vue/prefer-use-template-ref](./prefer-use-template-ref.md) | require using `useTemplateRef` instead of `ref` for template refs | | :hammer: |
| [vue/prefer-use-template-ref](./prefer-use-template-ref.md) | require using `useTemplateRef` instead of `ref`/`shallowRef` for template refs | | :hammer: |
| [vue/require-default-export](./require-default-export.md) | require components to be the default export | | :warning: |
| [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | | :hammer: |
| [vue/require-emit-validator](./require-emit-validator.md) | require type definitions in emits | :bulb: | :hammer: |
Expand Down
18 changes: 11 additions & 7 deletions docs/rules/prefer-use-template-ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,32 @@
pageClass: rule-details
sidebarDepth: 0
title: vue/prefer-use-template-ref
description: require using `useTemplateRef` instead of `ref` for template refs
description: require using `useTemplateRef` instead of `ref`/`shallowRef` for template refs
since: v9.31.0
---

# vue/prefer-use-template-ref

> require using `useTemplateRef` instead of `ref` for template refs
> require using `useTemplateRef` instead of `ref`/`shallowRef` for template refs
## :book: Rule Details

Vue 3.5 introduced a new way of obtaining template refs via
the [`useTemplateRef()`](https://vuejs.org/guide/essentials/template-refs.html#accessing-the-refs) API.

This rule enforces using the new `useTemplateRef` function instead of `ref` for template refs.
This rule enforces using the new `useTemplateRef` function instead of `ref`/`shallowRef` for template refs.

<eslint-code-block :rules="{'vue/prefer-use-template-ref': ['error']}">

```vue
<template>
<button ref="submitRef">Submit</button>
<button ref="cancelRef">Cancel</button>
<button ref="closeRef">Close</button>
</template>
<script setup>
import { ref, useTemplateRef } from 'vue';
import { ref, shallowRef, useTemplateRef } from 'vue';
/* ✓ GOOD */
const submitRef = useTemplateRef('submitRef');
Expand All @@ -35,6 +36,7 @@ This rule enforces using the new `useTemplateRef` function instead of `ref` for
/* ✗ BAD */
const closeRef = ref();
const cancelRef = shallowRef();
</script>
```

Expand All @@ -47,14 +49,16 @@ This rule skips `ref` template function refs as these should be used to allow cu

```vue
<template>
<button :ref="ref => button = ref">Content</button>
<button :ref="ref => submitRef = ref">Submit</button>
<button :ref="ref => cancelRef = ref">Cancel</button>
</template>
<script setup>
import { ref } from 'vue';
import { ref, shallowRef } from 'vue';
/* ✓ GOOD */
const button = ref();
const submitRef = ref();
const cancelRef = shallowRef();
</script>
```

Expand Down
18 changes: 13 additions & 5 deletions lib/rules/prefer-use-template-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ const utils = require('../utils')

/** @param expression {Expression | null} */
function expressionIsRef(expression) {
// @ts-ignore
return expression?.callee?.name === 'ref'
return (
// @ts-ignore
expression?.callee?.name === 'ref' ||
// @ts-ignore
expression?.callee?.name === 'shallowRef'
)
}

/** @type {import("eslint").Rule.RuleModule} */
Expand All @@ -18,13 +22,13 @@ module.exports = {
type: 'suggestion',
docs: {
description:
'require using `useTemplateRef` instead of `ref` for template refs',
'require using `useTemplateRef` instead of `ref`/`shallowRef` for template refs',
categories: undefined,
url: 'https://eslint.vuejs.org/rules/prefer-use-template-ref.html'
},
schema: [],
messages: {
preferUseTemplateRef: "Replace 'ref' with 'useTemplateRef'."
preferUseTemplateRef: "Replace '{{name}}' with 'useTemplateRef'."
}
},
/** @param {RuleContext} context */
Expand Down Expand Up @@ -79,7 +83,11 @@ module.exports = {

context.report({
node: scriptRef.node,
messageId: 'preferUseTemplateRef'
messageId: 'preferUseTemplateRef',
data: {
// @ts-ignore
name: scriptRef.node?.callee?.name
}
})
}
}
Expand Down
40 changes: 40 additions & 0 deletions tests/lib/rules/prefer-use-template-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ tester.run('prefer-use-template-ref', rule, {
errors: [
{
messageId: 'preferUseTemplateRef',
data: {
name: 'ref'
},
line: 7,
column: 22
}
Expand All @@ -235,6 +238,9 @@ tester.run('prefer-use-template-ref', rule, {
errors: [
{
messageId: 'preferUseTemplateRef',
data: {
name: 'ref'
},
line: 9,
column: 22
}
Expand All @@ -256,11 +262,17 @@ tester.run('prefer-use-template-ref', rule, {
errors: [
{
messageId: 'preferUseTemplateRef',
data: {
name: 'ref'
},
line: 8,
column: 25
},
{
messageId: 'preferUseTemplateRef',
data: {
name: 'ref'
},
line: 9,
column: 22
}
Expand Down Expand Up @@ -288,6 +300,9 @@ tester.run('prefer-use-template-ref', rule, {
errors: [
{
messageId: 'preferUseTemplateRef',
data: {
name: 'ref'
},
line: 14,
column: 33
}
Expand All @@ -314,10 +329,35 @@ tester.run('prefer-use-template-ref', rule, {
errors: [
{
messageId: 'preferUseTemplateRef',
data: {
name: 'ref'
},
line: 12,
column: 28
}
]
},
{
filename: 'single-shallowRef.vue',
code: `
<template>
<div ref="root"/>
</template>
<script setup>
import { shallowRef } from 'vue';
const root = shallowRef();
</script>
`,
errors: [
{
messageId: 'preferUseTemplateRef',
data: {
name: 'shallowRef'
},
line: 7,
column: 22
}
]
}
]
})

0 comments on commit 4500389

Please sign in to comment.