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: `
+
+ {{ $props }}
+
+
+ `
+ },
// 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: `
+
+ {{props}}
+
+ `
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ {{props.a}}
+
+ `
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ {{foo.a}}
+
+ `
+ },
+ {
+ code: `
+
+
+ {{ props.foo }}{{ bar }}
+ `,
+ ...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: `
+
+ {{ $props.foo }}
+
+
+ `,
+ errors: ["'bar' of property found, but never used."]
+ },
+
+ // props.prop in template
+ {
+ filename: 'test.vue',
+ code: `
+
+ {{props.a}}
+
+ `,
+ errors: ["'b' of property found, but never used."]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ {{foo.a}}
+
+ `,
+ errors: ["'b' of property found, but never used."]
+ },
+ {
+ code: `
+
+
+ {{ props.foo }}{{ bar }}
+ `,
+ errors: ["'baz' of property found, but never used."],
+ ...getTypeScriptFixtureTestOptions()
}
]
})