From 01cf10e697bab477d11b7c6b0406e01c2e00c284 Mon Sep 17 00:00:00 2001 From: waynzh Date: Tue, 6 Feb 2024 17:42:51 +0800 Subject: [PATCH 1/4] fix: recognize slot names enclosed in quotes --- lib/rules/require-explicit-slots.js | 40 +++++++++++++++++++---- tests/lib/rules/require-explicit-slots.js | 29 +++++++++++++++- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/lib/rules/require-explicit-slots.js b/lib/rules/require-explicit-slots.js index ed2d2edb9..c99be0f84 100644 --- a/lib/rules/require-explicit-slots.js +++ b/lib/rules/require-explicit-slots.js @@ -8,8 +8,31 @@ const utils = require('../utils') /** * @typedef {import('@typescript-eslint/types').TSESTree.TypeNode} TypeNode + * @typedef {import('@typescript-eslint/types').TSESTree.TypeElement} TypeElement */ +/** + * + * @param {TypeElement} node + */ +function getSlotsName(node) { + if ( + node.type === 'TSMethodSignature' || + node.type === 'TSPropertySignature' + ) { + const key = node.key + if (key.type === 'Literal') { + return typeof key.value === 'string' ? key.value : null + } + + if (key.type === 'Identifier') { + return key.name + } + } + + return null +} + module.exports = { meta: { type: 'problem', @@ -34,9 +57,9 @@ module.exports = { if (!documentFragment) { return {} } - const scripts = documentFragment.children.filter( - (element) => utils.isVElement(element) && element.name === 'script' - ) + const scripts = documentFragment.children + .filter(utils.isVElement) + .filter((element) => element.name === 'script') if (scripts.every((script) => !utils.hasAttribute(script, 'lang', 'ts'))) { return {} } @@ -54,7 +77,9 @@ module.exports = { if (param.type === 'TSTypeLiteral') { for (const memberNode of param.members) { - const slotName = memberNode.key.name + const slotName = getSlotsName(memberNode) + if (!slotName) continue + if (slotsDefined.has(slotName)) { context.report({ node: memberNode, @@ -75,6 +100,7 @@ module.exports = { if (!slotsProperty) return const slotsTypeHelper = + slotsProperty.value.type === 'TSAsExpression' && slotsProperty.value.typeAnnotation?.typeName.name === 'SlotsType' && slotsProperty.value.typeAnnotation if (!slotsTypeHelper) return @@ -90,7 +116,9 @@ module.exports = { if (param.type === 'TSTypeLiteral') { for (const memberNode of param.members) { - const slotName = memberNode.key.name + const slotName = getSlotsName(memberNode) + if (!slotName) continue + if (slotsDefined.has(slotName)) { context.report({ node: memberNode, @@ -111,7 +139,7 @@ module.exports = { const slotNameAttr = utils.getAttribute(node, 'name') - if (slotNameAttr) { + if (slotNameAttr?.value) { slotName = slotNameAttr.value.value } diff --git a/tests/lib/rules/require-explicit-slots.js b/tests/lib/rules/require-explicit-slots.js index 91ce0ce0b..993267142 100644 --- a/tests/lib/rules/require-explicit-slots.js +++ b/tests/lib/rules/require-explicit-slots.js @@ -62,7 +62,34 @@ tester.run('require-explicit-slots', rule, { }>() ` }, - + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, { filename: 'test.vue', code: ` From e9cd995077e4847c5ff4b9723e4301a1d5e6d930 Mon Sep 17 00:00:00 2001 From: waynzh Date: Tue, 6 Feb 2024 19:07:57 +0800 Subject: [PATCH 2/4] docs: update docs --- docs/rules/require-explicit-slots.md | 2 +- lib/rules/require-explicit-slots.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rules/require-explicit-slots.md b/docs/rules/require-explicit-slots.md index bffd1e3e8..7b05724db 100644 --- a/docs/rules/require-explicit-slots.md +++ b/docs/rules/require-explicit-slots.md @@ -11,7 +11,7 @@ since: v9.21.0 ## :book: Rule Details -This rule enforces all slots used in the template to be defined once either in the `script setup` block with the [`defineSlots`](https://vuejs.org/api/sfc-script-setup.html) macro, or with the [`slots property`](https://vuejs.org/api/options-rendering.html#slots) in the Options API. +This rule enforces all slots used in the template to be defined once either in the `script setup` block with the [`defineSlots`](https://vuejs.org/api/sfc-script-setup.html#defineslots) macro, or with the [`slots property`](https://vuejs.org/api/options-rendering.html#slots) in the Options API. diff --git a/lib/rules/require-explicit-slots.js b/lib/rules/require-explicit-slots.js index c99be0f84..d118662b8 100644 --- a/lib/rules/require-explicit-slots.js +++ b/lib/rules/require-explicit-slots.js @@ -12,8 +12,8 @@ const utils = require('../utils') */ /** - * * @param {TypeElement} node + * @return {string | null} */ function getSlotsName(node) { if ( From 0a0dbb183bdb04a1fb10b605ad805414c6165956 Mon Sep 17 00:00:00 2001 From: waynzh Date: Tue, 6 Feb 2024 20:06:04 +0800 Subject: [PATCH 3/4] test: update tests --- tests/lib/rules/require-explicit-slots.js | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/lib/rules/require-explicit-slots.js b/tests/lib/rules/require-explicit-slots.js index 993267142..ebbc28818 100644 --- a/tests/lib/rules/require-explicit-slots.js +++ b/tests/lib/rules/require-explicit-slots.js @@ -230,6 +230,44 @@ tester.run('require-explicit-slots', rule, { } ] }, + { + filename: 'test.vue', + code: ` + + `, + errors: [ + { + message: 'Slots must be explicitly defined.' + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: [ + { + message: 'Slots must be explicitly defined.' + } + ] + }, { filename: 'test.vue', code: ` From d5c39edde6f78a0fc156fe6fa95205d485d54b37 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 6 Feb 2024 21:18:13 +0800 Subject: [PATCH 4/4] Update lib/rules/require-explicit-slots.js Co-authored-by: Flo Edelmann --- lib/rules/require-explicit-slots.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/rules/require-explicit-slots.js b/lib/rules/require-explicit-slots.js index d118662b8..aab09c494 100644 --- a/lib/rules/require-explicit-slots.js +++ b/lib/rules/require-explicit-slots.js @@ -17,17 +17,19 @@ const utils = require('../utils') */ function getSlotsName(node) { if ( - node.type === 'TSMethodSignature' || - node.type === 'TSPropertySignature' + node.type !== 'TSMethodSignature' && + node.type !== 'TSPropertySignature' ) { - const key = node.key - if (key.type === 'Literal') { - return typeof key.value === 'string' ? key.value : null - } + return null + } - if (key.type === 'Identifier') { - return key.name - } + const key = node.key + if (key.type === 'Literal') { + return typeof key.value === 'string' ? key.value : null + } + + if (key.type === 'Identifier') { + return key.name } return null