Skip to content

Commit 62f749b

Browse files
committed
feat: ignore attribute binding except string literal
1 parent cd0dc00 commit 62f749b

File tree

2 files changed

+80
-22
lines changed

2 files changed

+80
-22
lines changed

lib/rules/require-explicit-slots.js

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,21 @@ function getSlotsName(node) {
3535
return null
3636
}
3737

38+
/**
39+
* @param {VElement} node
40+
* @return {VAttribute | VDirective | undefined}
41+
*/
42+
function getSlotNameNode(node) {
43+
return node.startTag.attributes.find(
44+
(node) =>
45+
(!node.directive && node.key.name === 'name') ||
46+
(node.directive &&
47+
node.key.name.name === 'bind' &&
48+
node.key.argument?.type === 'VIdentifier' &&
49+
node.key.argument?.name === 'name')
50+
)
51+
}
52+
3853
module.exports = {
3954
meta: {
4055
type: 'problem',
@@ -68,6 +83,19 @@ module.exports = {
6883
}
6984
const slotsDefined = new Set()
7085

86+
/**
87+
* @param {VElement} node
88+
* @param {string | undefined} slotName
89+
*/
90+
function reportMissingSlot(node, slotName) {
91+
if (!slotsDefined.has(slotName)) {
92+
context.report({
93+
node,
94+
messageId: 'requireExplicitSlots'
95+
})
96+
}
97+
}
98+
7199
return utils.compositingVisitors(
72100
utils.defineScriptSetupVisitor(context, {
73101
onDefineSlotsEnter(node) {
@@ -139,32 +167,26 @@ module.exports = {
139167
utils.defineTemplateBodyVisitor(context, {
140168
/** @param {VElement} node */
141169
"VElement[name='slot']"(node) {
142-
const nameNode = node.startTag.attributes.find(
143-
(node) =>
144-
(!node.directive && node.key.name === 'name') ||
145-
(node.directive &&
146-
node.key.name.name === 'bind' &&
147-
node.key.argument?.type === 'VIdentifier' &&
148-
node.key.argument?.name === 'name')
149-
)
170+
const nameNode = getSlotNameNode(node)
150171

151-
/** @type {string | undefined} */
152-
let slotName
172+
// if no slot name is declared, default to 'default'
153173
if (!nameNode) {
154-
// If no slot name is declared, default to 'default'
155-
slotName = 'default'
156-
} else if (nameNode.directive) {
157-
// ignore attribute binding
174+
reportMissingSlot(node, 'default')
158175
return
159-
} else {
160-
slotName = nameNode.value?.value
161176
}
162177

163-
if (!slotsDefined.has(slotName)) {
164-
context.report({
165-
node,
166-
messageId: 'requireExplicitSlots'
167-
})
178+
if (nameNode.directive) {
179+
const expression = nameNode.value?.expression
180+
// ignore attribute binding except string literal
181+
if (!expression || !utils.isStringLiteral(expression)) {
182+
return
183+
}
184+
185+
const name = utils.getStringLiteralValue(expression) || undefined
186+
reportMissingSlot(node, name)
187+
} else {
188+
// check and report if slot name is declared or is undefined
189+
reportMissingSlot(node, nameNode.value?.value)
168190
}
169191
}
170192
})

tests/lib/rules/require-explicit-slots.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,29 @@ tester.run('require-explicit-slots', rule, {
161161
}
162162
}
163163
},
164-
// ignore attribute binding
164+
// attribute binding
165165
{
166166
filename: 'test.vue',
167167
code: `
168168
<template>
169169
<div>
170170
<slot :name="'foo'"></slot>
171+
<slot :name="\`bar\`"></slot>
172+
</div>
173+
</template>
174+
<script setup lang="ts">
175+
defineSlots<{
176+
foo(props: { msg: string }): any
177+
bar(props: { msg: string }): any
178+
}>()
179+
</script>`
180+
},
181+
{
182+
filename: 'test.vue',
183+
code: `
184+
<template>
185+
<div>
186+
<slot :name="bar"></slot>
171187
</div>
172188
</template>
173189
<script setup lang="ts">
@@ -306,6 +322,26 @@ tester.run('require-explicit-slots', rule, {
306322
}
307323
]
308324
},
325+
{
326+
// ignore attribute binding except string literal
327+
filename: 'test.vue',
328+
code: `
329+
<template>
330+
<div>
331+
<slot :name="'foo'"></slot>
332+
</div>
333+
</template>
334+
<script setup lang="ts">
335+
defineSlots<{
336+
default(props: { msg: string }): any
337+
}>()
338+
</script>`,
339+
errors: [
340+
{
341+
message: 'Slots must be explicitly defined.'
342+
}
343+
]
344+
},
309345
{
310346
filename: 'test.vue',
311347
code: `

0 commit comments

Comments
 (0)