From 3815686d28880ffa4811c05a856255fb17b6c17e Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Sun, 19 Jul 2020 17:15:16 +0900 Subject: [PATCH] Fix false positives for watch handler methods in `vue/no-unused-properties` rule --- lib/rules/no-unused-properties.js | 34 ++++++++++++++++-- lib/utils/index.js | 10 ++++-- tests/lib/rules/no-unused-properties.js | 47 +++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index f7f30dc84..23fab4424 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -583,19 +583,47 @@ module.exports = { utils.defineVueVisitor(context, { onVueObjectEnter(node) { const container = getVueComponentPropertiesContainer(node) - const watcherNames = new Set() + const watcherUsedProperties = new Set() for (const watcher of utils.iterateProperties( node, new Set([GROUP_WATCHER]) )) { + // Process `watch: { foo /* <- this */ () {} }` let path for (const seg of watcher.name.split('.')) { path = path ? `${path}.${seg}` : seg - watcherNames.add(path) + watcherUsedProperties.add(path) + } + + // Process `watch: { x: 'foo' /* <- this */ }` + if (watcher.type === 'object') { + const property = watcher.property + if (property.kind === 'init') { + /** @type {Expression | null} */ + let handlerValueNode = null + if (property.value.type === 'ObjectExpression') { + const handler = utils.findProperty(property.value, 'handler') + if (handler) { + handlerValueNode = handler.value + } + } else { + handlerValueNode = property.value + } + if ( + handlerValueNode && + (handlerValueNode.type === 'Literal' || + handlerValueNode.type === 'TemplateLiteral') + ) { + const name = utils.getStringLiteralValue(handlerValueNode) + if (name != null) { + watcherUsedProperties.add(name) + } + } + } } } for (const prop of utils.iterateProperties(node, groups)) { - if (watcherNames.has(prop.name)) { + if (watcherUsedProperties.has(prop.name)) { continue } container.properties.push(prop) diff --git a/lib/utils/index.js b/lib/utils/index.js index 130530526..8bee58a55 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -83,7 +83,7 @@ /** * @typedef { 'props' | 'data' | 'computed' | 'setup' | 'watch' | 'methods' } GroupName * @typedef { { type: 'array', name: string, groupName: GroupName, node: Literal | TemplateLiteral } } ComponentArrayPropertyData - * @typedef { { type: 'object', name: string, groupName: GroupName, node: Identifier | Literal | TemplateLiteral } } ComponentObjectPropertyData + * @typedef { { type: 'object', name: string, groupName: GroupName, node: Identifier | Literal | TemplateLiteral, property: Property } } ComponentObjectPropertyData * @typedef { ComponentArrayPropertyData | ComponentObjectPropertyData } ComponentPropertyData */ /** @@ -1117,7 +1117,13 @@ module.exports = { continue } } - yield { type: 'object', name, groupName, node: key } + yield { + type: 'object', + name, + groupName, + node: key, + property: item + } } } } diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index 4319d14fc..dffa036f8 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -1031,6 +1031,53 @@ tester.run('no-unused-properties', rule, { } }) ` + }, + // handlers + { + filename: 'test.vue', + code: ` + + `, + options: [{ groups: ['props', 'methods'] }] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ groups: ['props', 'data'] }] } ],