diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index be18224ed..9a38c2a75 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -12,9 +12,27 @@ const utils = require('../utils') const eslintUtils = require('eslint-utils') /** - * @typedef {import('../utils').ComponentPropertyData} ComponentPropertyData + * @typedef {import('../utils').GroupName} GroupName * @typedef {import('../utils').VueObjectData} VueObjectData */ + +/** + * @typedef {object} ComponentObjectPropertyData + * @property {string} name + * @property {GroupName} groupName + * @property {'object'} type + * @property {ASTNode} node + * @property {Property} property + * + * @typedef {object} ComponentNonObjectPropertyData + * @property {string} name + * @property {GroupName} groupName + * @property {'array' | 'type'} type + * @property {ASTNode} node + * + * @typedef { ComponentNonObjectPropertyData | ComponentObjectPropertyData } ComponentPropertyData + */ + /** * @typedef {object} TemplatePropertiesContainer * @property {UsedProperties} usedProperties @@ -256,7 +274,7 @@ class ParamsUsedProperties { return param } if (this.node.params[index]) { - return (this.params[index] = extractParamProperties( + return (this.params[index] = extractParamOrVerProperties( this.node.params[index], this.context )) @@ -270,7 +288,7 @@ class ParamsUsedProperties { * @param {RuleContext} context * @returns {UsedProperties} */ -function extractParamProperties(node, context) { +function extractParamOrVerProperties(node, context) { const result = new UsedProperties() while (node.type === 'AssignmentPattern') { @@ -826,7 +844,58 @@ module.exports = { } const scriptVisitor = utils.compositingVisitors( - {}, + utils.defineScriptSetupVisitor(context, { + onDefinePropsEnter(node, props) { + if (!groups.has('props')) { + return + } + const container = getVueComponentPropertiesContainer(node) + + for (const prop of props) { + if (!prop.propName) { + continue + } + if (prop.type === 'object') { + container.properties.push({ + type: prop.type, + name: prop.propName, + groupName: 'props', + node: prop.key, + property: prop.node + }) + } else { + container.properties.push({ + type: prop.type, + name: prop.propName, + groupName: 'props', + node: prop.key + }) + } + } + let target = node + if ( + target.parent && + target.parent.type === 'CallExpression' && + target.parent.arguments[0] === target && + target.parent.callee.type === 'Identifier' && + target.parent.callee.name === 'withDefaults' + ) { + target = target.parent + } + + if ( + !target.parent || + target.parent.type !== 'VariableDeclarator' || + target.parent.init !== target + ) { + return + } + + const pattern = target.parent.id + const usedProps = extractParamOrVerProperties(pattern, context) + container.usedPropertiesForProps.merge(usedProps) + } + }), utils.defineVueVisitor(context, { onVueObjectEnter(node) { const container = getVueComponentPropertiesContainer(node) diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index e52a4bbf4..f9d61e4b0 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -2400,6 +2400,18 @@ tester.run('no-unused-properties', rule, { "'a' of data found, but never used.", "'b' of data found, but never used." ] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ["'c' of property found, but never used."] } ] })