diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index 7eb7eb75d..b15cf5a85 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -233,6 +233,8 @@ module.exports = { const deepData = Boolean(options.deepData) const ignorePublicMembers = Boolean(options.ignorePublicMembers) const unreferencedOptions = new Set(options.unreferencedOptions || []) + /** @type {null | Pattern} */ + let propsReferencePattern = null const propertyReferenceExtractor = definePropertyReferenceExtractor( context, @@ -332,8 +334,9 @@ module.exports = { for (const property of container.properties) { if ( - property.groupName === 'props' && - propertyReferencesForProps.hasProperty(property.name) + (property.groupName === 'props' && + propertyReferencesForProps.hasProperty(property.name)) || + propertyReferences.hasProperty('$props') ) { // used props continue @@ -369,6 +372,7 @@ module.exports = { } continue } + context.report({ node: property.node, messageId: 'unused', @@ -450,9 +454,9 @@ module.exports = { return } - const pattern = target.parent.id + propsReferencePattern = target.parent.id const propertyReferences = - propertyReferenceExtractor.extractFromPattern(pattern) + propertyReferenceExtractor.extractFromPattern(propsReferencePattern) container.propertyReferencesForProps.push(propertyReferences) }, onDefineModelEnter(node, model) { @@ -709,9 +713,26 @@ module.exports = { * @param {VExpressionContainer} node */ VExpressionContainer(node) { - templatePropertiesContainer.propertyReferences.push( + const property = propertyReferenceExtractor.extractFromVExpressionContainer(node) - ) + + templatePropertiesContainer.propertyReferences.push(property) + + if (!propsReferencePattern) { + return + } + + // props.prop in template + for (const key of property.allProperties().keys()) { + if ( + propsReferencePattern.type === 'Identifier' && + propsReferencePattern.name === key + ) { + templatePropertiesContainer.propertyReferences.push( + property.getNest(key) + ) + } + } }, /** * @param {VAttribute} node diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index 64e858d31..b89ea01f0 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -718,6 +718,20 @@ tester.run('no-unused-properties', rule, { ` }, + // a property used as a template $props expression + { + filename: 'test.vue', + code: ` + + + ` + }, // properties used in a template expression { @@ -910,6 +924,20 @@ tester.run('no-unused-properties', rule, { ` }, + // a property used in v-on as $props expression + { + filename: 'test.vue', + code: ` + + + ` + }, // data used in a script expression { @@ -2452,6 +2480,48 @@ tester.run('no-unused-properties', rule, { {{ foo }} ` + }, + + // props.prop in template + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + code: ` + + `, + ...getTypeScriptFixtureTestOptions() } ], invalid: [ @@ -4619,6 +4689,57 @@ tester.run('no-unused-properties', rule, { line: 6 } ] + }, + + // a property used as a template $props member expression + { + filename: 'test.vue', + code: ` + + + `, + errors: ["'bar' of property found, but never used."] + }, + + // props.prop in template + { + filename: 'test.vue', + code: ` + + `, + errors: ["'b' of property found, but never used."] + }, + { + filename: 'test.vue', + code: ` + + `, + errors: ["'b' of property found, but never used."] + }, + { + code: ` + + `, + errors: ["'baz' of property found, but never used."], + ...getTypeScriptFixtureTestOptions() } ] })