diff --git a/lib/utils/property-references.js b/lib/utils/property-references.js index 4d4e39805..1ed26640f 100644 --- a/lib/utils/property-references.js +++ b/lib/utils/property-references.js @@ -317,7 +317,22 @@ function definePropertyReferenceExtractor( if (parent.object === node) { // `arg.foo` const name = utils.getStaticPropertyName(parent) - if (name) { + + if ( + name === '$props' && + parent.parent.type === 'MemberExpression' + ) { + // `$props.arg` + const propName = utils.getStaticPropertyName(parent.parent) + + if (!propName) return unknownMemberAsUnreferenced ? NEVER : ANY + + return new PropertyReferencesForMember( + parent.parent, + propName, + withInTemplate + ) + } else if (name) { return new PropertyReferencesForMember( parent, name, @@ -655,8 +670,17 @@ function definePropertyReferenceExtractor( references.push(extractFromExpression(id, true)) } } else { + const referenceId = + id.name === '$props' && + id.parent.type === 'MemberExpression' && + id.parent.property.type === 'Identifier' + ? id.parent.property + : id + references.push( - extractFromName(id.name, id, () => extractFromExpression(id, true)) + extractFromName(referenceId.name, referenceId, () => + extractFromExpression(referenceId, true) + ) ) } } diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index 0139559b1..3363f9128 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -67,6 +67,19 @@ tester.run('no-unused-properties', rule, { ` }, + { + filename: 'test.vue', + code: ` + + ` + }, // default options { filename: 'test.vue', @@ -139,6 +152,20 @@ tester.run('no-unused-properties', rule, { ` }, + // a property used as a template $props member expression + { + filename: 'test.vue', + code: ` + + + ` + }, // properties used in a template expression { @@ -154,6 +181,20 @@ tester.run('no-unused-properties', rule, { ` }, + // properties used in a template expression as $props member expression + { + filename: 'test.vue', + code: ` + + + ` + }, // a property used in v-if { @@ -173,6 +214,24 @@ tester.run('no-unused-properties', rule, { ` }, + // a property used in v-if as $props member expression + { + filename: 'test.vue', + code: ` + + + ` + }, // a property used in v-for { @@ -193,6 +252,25 @@ tester.run('no-unused-properties', rule, { ` }, + // a property used in v-for as $props member expression + { + filename: 'test.vue', + code: ` + + + ` + }, // a property used in v-html { @@ -208,6 +286,20 @@ tester.run('no-unused-properties', rule, { ` }, + // a property used in v-html as $props member expression + { + filename: 'test.vue', + code: ` + + + ` + }, // a property passed in a component { @@ -223,6 +315,20 @@ tester.run('no-unused-properties', rule, { ` }, + // a property passed in a component as $props member expression + { + filename: 'test.vue', + code: ` + + + ` + }, // a property used in v-on { @@ -238,6 +344,20 @@ tester.run('no-unused-properties', rule, { ` }, + // a property used in v-on as $props member expression + { + filename: 'test.vue', + code: ` + + + ` + }, // data used in a script expression { @@ -1196,6 +1316,21 @@ tester.run('no-unused-properties', rule, { ` }, + { + filename: 'test.vue', + code: ` + + ` + }, // deep data { @@ -1587,6 +1722,29 @@ tester.run('no-unused-properties', rule, { } ] }, + { + filename: 'test.vue', + code: ` + + `, + options: [ + { + groups: ['props', 'computed'], + ignorePublicMembers: true + } + ] + }, // expose {