diff --git a/docs/rules/no-unused-properties.md b/docs/rules/no-unused-properties.md
index da8fa7d87..4c8300923 100644
--- a/docs/rules/no-unused-properties.md
+++ b/docs/rules/no-unused-properties.md
@@ -14,7 +14,7 @@ since: v7.0.0
This rule is aimed at eliminating unused properties.
::: warning Note
-This rule cannot be checked for use in other components (e.g. `mixins`, Property access via `$refs`) and use in places where the scope cannot be determined.
+This rule cannot check for use of properties by other components (e.g. `mixins`, property access via `$refs`) and use in places where the scope cannot be determined. Some access to properties might be implied, for example accessing data or computed via a variable such as `this[varName]`. In this case, the default is to assume all properties, methods, etc. are 'used'. See the `unreferencedOptions` for a more strict interpretation of 'use' in these cases.
:::
@@ -56,7 +56,8 @@ This rule cannot be checked for use in other components (e.g. `mixins`, Property
"vue/no-unused-properties": ["error", {
"groups": ["props"],
"deepData": false,
- "ignorePublicMembers": false
+ "ignorePublicMembers": false,
+ "unreferencedOptions": []
}]
}
```
@@ -69,6 +70,7 @@ This rule cannot be checked for use in other components (e.g. `mixins`, Property
- `"setup"`
- `deepData` (`boolean`) If `true`, the object of the property defined in `data` will be searched deeply. Default is `false`. Include `"data"` in `groups` to use this option.
- `ignorePublicMembers` (`boolean`) If `true`, members marked with a [JSDoc `/** @public */` tag](https://jsdoc.app/tags-public.html) will be ignored. Default is `false`.
+- `unreferencedOptions` (`string[]`) Array of access methods that should be interpreted as leaving properties unreferenced. Currently, two such methods are available: `unknownMemberAsUnreferenced`, and `returnAsUnreferenced`. See examples below.
### `"groups": ["props", "data"]`
@@ -218,6 +220,71 @@ This rule cannot be checked for use in other components (e.g. `mixins`, Property
+### `{ "groups": ["computed"], "unreferencedOptions": ["unknownMemberAsUnreferenced"] }`
+
+
+
+```vue
+
+
+
+
+```
+
+
+
+### `{ "groups": ["computed"], "unreferencedOptions": ["returnAsUnreferenced"] }`
+
+
+
+```vue
+
+
+
+
+```
+
+
+
## :rocket: Version
This rule was introduced in eslint-plugin-vue v7.0.0
diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js
index 99a20a40e..1421ad0b8 100644
--- a/lib/rules/no-unused-properties.js
+++ b/lib/rules/no-unused-properties.js
@@ -55,6 +55,9 @@ const GROUP_SETUP = 'setup'
const GROUP_WATCHER = 'watch'
const GROUP_EXPOSE = 'expose'
+const UNREFERENCED_UNKNOWN_MEMBER = 'unknownMemberAsUnreferenced'
+const UNREFERENCED_RETURN = 'returnAsUnreferenced'
+
const PROPERTY_LABEL = {
props: 'property',
data: 'data',
@@ -206,7 +209,15 @@ module.exports = {
uniqueItems: true
},
deepData: { type: 'boolean' },
- ignorePublicMembers: { type: 'boolean' }
+ ignorePublicMembers: { type: 'boolean' },
+ unreferencedOptions: {
+ type: 'array',
+ items: {
+ enum: [UNREFERENCED_UNKNOWN_MEMBER, UNREFERENCED_RETURN]
+ },
+ additionalItems: false,
+ uniqueItems: true
+ }
},
additionalProperties: false
}
@@ -221,8 +232,17 @@ module.exports = {
const groups = new Set(options.groups || [GROUP_PROPERTY])
const deepData = Boolean(options.deepData)
const ignorePublicMembers = Boolean(options.ignorePublicMembers)
+ const unreferencedOptions = new Set(options.unreferencedOptions || [])
- const propertyReferenceExtractor = definePropertyReferenceExtractor(context)
+ const propertyReferenceExtractor = definePropertyReferenceExtractor(
+ context,
+ {
+ unknownMemberAsUnreferenced: unreferencedOptions.has(
+ UNREFERENCED_UNKNOWN_MEMBER
+ ),
+ returnAsUnreferenced: unreferencedOptions.has(UNREFERENCED_RETURN)
+ }
+ )
/** @type {TemplatePropertiesContainer} */
const templatePropertiesContainer = {
diff --git a/lib/utils/property-references.js b/lib/utils/property-references.js
index 7a881af2f..4be7b17c7 100644
--- a/lib/utils/property-references.js
+++ b/lib/utils/property-references.js
@@ -92,7 +92,10 @@ module.exports = {
/**
* @param {RuleContext} context The rule context.
*/
-function definePropertyReferenceExtractor(context) {
+function definePropertyReferenceExtractor(
+ context,
+ { unknownMemberAsUnreferenced = false, returnAsUnreferenced = false } = {}
+) {
/** @type {Map} */
const cacheForExpression = new Map()
/** @type {Map} */
@@ -314,9 +317,15 @@ function definePropertyReferenceExtractor(context) {
if (parent.object === node) {
// `arg.foo`
const name = utils.getStaticPropertyName(parent)
- return name
- ? new PropertyReferencesForMember(parent, name, withInTemplate)
- : ANY
+ if (name) {
+ return new PropertyReferencesForMember(
+ parent,
+ name,
+ withInTemplate
+ )
+ } else {
+ return unknownMemberAsUnreferenced ? NEVER : ANY
+ }
}
return NEVER
}
@@ -331,12 +340,18 @@ function definePropertyReferenceExtractor(context) {
return extractFromExpression(parent, withInTemplate)
}
case 'ArrowFunctionExpression':
- case 'ReturnStatement':
case 'VExpressionContainer':
case 'Property':
case 'ArrayExpression': {
return maybeExternalUsed(parent) ? ANY : NEVER
}
+ case 'ReturnStatement': {
+ if (returnAsUnreferenced) {
+ return NEVER
+ } else {
+ return maybeExternalUsed(parent) ? ANY : NEVER
+ }
+ }
}
return NEVER
}
diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js
index a75d83e72..8d4b2b215 100644
--- a/tests/lib/rules/no-unused-properties.js
+++ b/tests/lib/rules/no-unused-properties.js
@@ -21,6 +21,33 @@ const allOptions = [
]
const deepDataOptions = [{ groups: ['data'], deepData: true }]
+const unreferencedOptions = {
+ // Report errors when accessing via unknown property, e.g. this[varName]
+ unknownMemberAsUnreferenced: [
+ {
+ groups: ['computed'],
+ unreferencedOptions: ['unknownMemberAsUnreferenced']
+ }
+ ],
+ // Report errors when returning this
+ returnAsUnreferenced: [
+ {
+ groups: ['computed'],
+ unreferencedOptions: ['returnAsUnreferenced']
+ }
+ ],
+ // Report all
+ all: [
+ {
+ groups: ['computed'],
+ unreferencedOptions: [
+ 'unknownMemberAsUnreferenced',
+ 'returnAsUnreferenced'
+ ]
+ }
+ ]
+}
+
tester.run('no-unused-properties', rule, {
valid: [
// a property used in a script expression
@@ -1699,7 +1726,6 @@ tester.run('no-unused-properties', rule, {
`
}
],
-
invalid: [
// unused property
{
@@ -2803,6 +2829,138 @@ tester.run('no-unused-properties', rule, {
line: 10
}
]
+ },
+
+ // unreferencedOptions: unknownMemberAsUnreferenced
+ {
+ filename: 'test.vue',
+ code: `
+ `,
+ options: unreferencedOptions.unknownMemberAsUnreferenced,
+ errors: [
+ {
+ message: "'two' of computed property found, but never used.",
+ line: 8
+ }
+ ]
+ },
+ // unreferencedOptions: returnAsUnreferenced
+ {
+ filename: 'test.vue',
+ code: `
+ `,
+ options: unreferencedOptions.returnAsUnreferenced,
+ errors: [
+ {
+ message: "'two' of computed property found, but never used.",
+ line: 8
+ }
+ ]
+ },
+ // unreferencedOptions: returnAsUnreferenced via variable with deepData
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ options: [
+ {
+ groups: ['data'],
+ unreferencedOptions: ['returnAsUnreferenced'],
+ deepData: true
+ }
+ ],
+ errors: [
+ {
+ message: "'foo.bar' of data found, but never used.",
+ line: 7
+ }
+ ]
+ },
+ // unreferencedOptions: all
+ {
+ filename: 'test.vue',
+ code: `
+ `,
+ options: unreferencedOptions.all,
+ errors: [
+ {
+ message: "'two' of computed property found, but never used.",
+ line: 8
+ }
+ ]
}
]
})