Skip to content

Commit

Permalink
fix(prefer-use-template-ref): should check only root-level variables
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomasan1999 committed Nov 16, 2024
1 parent 16c8778 commit a0feb9e
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 57 deletions.
85 changes: 55 additions & 30 deletions lib/rules/prefer-use-template-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,42 @@

const utils = require('../utils')

/** @param expression {Expression | null} */
function expressionIsRef(expression) {
// @ts-ignore
return expression?.callee?.name === 'ref'
/**
* @typedef ScriptRef
* @type {{node: Expression, ref: string}}
*/

/**
* @param declarator {VariableDeclarator}
* @returns {ScriptRef}
* */
function convertDeclaratorToScriptRef(declarator) {
return {
// @ts-ignore
node: declarator.init,
// @ts-ignore
ref: declarator.id.name
}
}

/**
* @param body {(Statement | ModuleDeclaration)[]}
* @returns {ScriptRef[]}
* */
function getScriptRefsFromSetupFunction(body) {
/** @type {VariableDeclaration[]} */
const variableDeclarations = body.filter(
(child) => child.type === 'VariableDeclaration'
)
const variableDeclarators = variableDeclarations.map(
(declaration) => declaration.declarations[0]
)
const refDeclarators = variableDeclarators.filter(
// @ts-ignore
(declarator) => declarator.init?.callee?.name === 'ref'
)

return refDeclarators.map(convertDeclaratorToScriptRef)
}

/** @type {import("eslint").Rule.RuleModule} */
Expand All @@ -32,40 +64,33 @@ module.exports = {
/** @type Set<string> */
const templateRefs = new Set()

/**
* @typedef ScriptRef
* @type {{node: Expression, ref: string}}
*/

/**
* @type ScriptRef[] */
const scriptRefs = []

return utils.compositingVisitors(
utils.defineTemplateBodyVisitor(
context,
{
'VAttribute[directive=false]'(node) {
if (node.key.name === 'ref' && node.value?.value) {
templateRefs.add(node.value.value)
}
utils.defineTemplateBodyVisitor(context, {
'VAttribute[directive=false]'(node) {
if (node.key.name === 'ref' && node.value?.value) {
templateRefs.add(node.value.value)
}
},
{
VariableDeclarator(declarator) {
if (!expressionIsRef(declarator.init)) {
return
}
}
}),
utils.defineVueVisitor(context, {
onSetupFunctionEnter(node) {
// @ts-ignore
const newScriptRefs = getScriptRefsFromSetupFunction(node.body.body)

scriptRefs.push({
// @ts-ignore
node: declarator.init,
// @ts-ignore
ref: declarator.id.name
})
}
scriptRefs.push(...newScriptRefs)
}
}),
utils.defineScriptSetupVisitor(context, {
Program(node) {
const newScriptRefs = getScriptRefsFromSetupFunction(node.body)

scriptRefs.push(...newScriptRefs)
}
),
}),
{
'Program:exit'() {
for (const templateRef of templateRefs) {
Expand Down
82 changes: 55 additions & 27 deletions tests/lib/rules/prefer-use-template-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,61 @@ tester.run('prefer-use-template-ref', rule, {
const button = ref();
</script>
`
},
{
filename: 'ref-in-block.vue',
code: `
<template>
<div>
<ul>
<li ref="firstListItem">Morning</li>
<li ref="second">Afternoon</li>
<li>Evening</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
function getFirstListItemElement() {
const firstListItem = ref();
const nestedCallback = () => {
const second = ref();
console.log(second);
}
nestedCallback();
}
</script>
`
},
{
filename: 'ref-in-block-setup-fn.vue',
code: `
<template>
<div>
<ul>
<li ref="firstListItem">Morning</li>
<li ref="second">Afternoon</li>
<li>Evening</li>
</ul>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
name: 'ComponentWithRefInBlock',
setup() {
function getFirstListItemElement() {
const firstListItem = ref();
const nestedCallback = () => {
const second = ref();
console.log(second);
}
nestedCallback();
}
}
}
</script>
`
}
],
invalid: [
Expand Down Expand Up @@ -266,33 +321,6 @@ tester.run('prefer-use-template-ref', rule, {
}
]
},
{
filename: 'ref-in-block.vue',
code: `
<template>
<div>
<ul>
<li ref="firstListItem">Morning</li>
<li>Afternoon</li>
<li>Evening</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
function getFirstListItemElement() {
const firstListItem = ref();
}
</script>
`,
errors: [
{
messageId: 'preferUseTemplateRef',
line: 14,
column: 33
}
]
},
{
filename: 'setup-function-only-refs.vue',
code: `
Expand Down

0 comments on commit a0feb9e

Please sign in to comment.