From 1d1ec85d288e70511272e06d124606543016651c Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Sat, 10 Oct 2020 08:53:44 +0900 Subject: [PATCH] Fixed false positives when used via argument in `vue/no-unused-properties` --- lib/rules/no-unused-properties.js | 100 +++++++++++++++++++++--- tests/lib/rules/no-unused-properties.js | 89 +++++++++++++++++++++ 2 files changed, 180 insertions(+), 9 deletions(-) diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index 23fab4424..75b56a4ef 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -578,6 +578,41 @@ module.exports = { } } + /** + * @param {VueComponentPropertiesContainer} container + * @param {UsedProps} baseUseProps + */ + function processUsed(container, baseUseProps) { + for (const { usedNames, unknown } of iterateUsedProps(baseUseProps)) { + if (unknown) { + container.unknown = true + return + } + for (const name of usedNames.names()) { + container.usedNames.add(name) + } + } + } + + /** + * @param {Expression} node + * @returns {Property|null} + */ + function getParentProperty(node) { + if ( + !node.parent || + node.parent.type !== 'Property' || + node.parent.value !== node + ) { + return null + } + const property = node.parent + if (!property.parent || property.parent.type !== 'ObjectExpression') { + return null + } + return /** @type {Property} */ (property) + } + const scriptVisitor = Object.assign( {}, utils.defineVueVisitor(context, { @@ -629,6 +664,61 @@ module.exports = { container.properties.push(prop) } }, + /** @param { (FunctionExpression | ArrowFunctionExpression) & { parent: Property }} node */ + 'ObjectExpression > Property > :function[params.length>0]'( + node, + vueData + ) { + const property = getParentProperty(node) + if (!property) { + return + } + if (property.parent === vueData.node) { + if (utils.getStaticPropertyName(property) !== 'data') { + return + } + // check { data: (vm) => vm.prop } + } else { + const parentProperty = getParentProperty(property.parent) + if (!parentProperty) { + return + } + if (parentProperty.parent === vueData.node) { + if (utils.getStaticPropertyName(parentProperty) !== 'computed') { + return + } + // check { computed: { foo: (vm) => vm.prop } } + } else { + const parentParentProperty = getParentProperty( + parentProperty.parent + ) + if (!parentParentProperty) { + return + } + if (parentParentProperty.parent === vueData.node) { + if ( + utils.getStaticPropertyName(parentParentProperty) !== + 'computed' || + utils.getStaticPropertyName(property) !== 'handler' + ) { + return + } + // check { computed: { foo: { handler: (vm) => vm.prop } } } + } else { + return + } + } + } + + const paramsUsedProps = getParamsUsedProps(node) + const usedProps = /** @type {ParamUsedProps} */ (paramsUsedProps.getParam( + 0 + )) + processUsed( + getVueComponentPropertiesContainer(vueData.node), + usedProps + ) + }, onSetupFunctionEnter(node, vueData) { const container = getVueComponentPropertiesContainer(vueData.node) if (node.params[0]) { @@ -690,15 +780,7 @@ module.exports = { const container = getVueComponentPropertiesContainer(vueData.node) const usedProps = extractPatternOrThisProperties(node, context) - for (const { usedNames, unknown } of iterateUsedProps(usedProps)) { - if (unknown) { - container.unknown = true - return - } - for (const name of usedNames.names()) { - container.usedNames.add(name) - } - } + processUsed(container, usedProps) } }), { diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index dffa036f8..78e15c4f8 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -1078,6 +1078,48 @@ tester.run('no-unused-properties', rule, { `, options: [{ groups: ['props', 'data'] }] + }, + // contexts + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` } ], @@ -1574,6 +1616,53 @@ tester.run('no-unused-properties', rule, { }) `, errors: ["'foo' of property found, but never used."] + }, + + // contexts + { + filename: 'test.vue', + code: ` + + `, + errors: ["'x' of property found, but never used."] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ["'x' of property found, but never used."] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ["'x' of property found, but never used."] } ] })