From 8766e5895ae57ba824db722208931e6531a6111f Mon Sep 17 00:00:00 2001 From: dsl101 Date: Wed, 8 Mar 2023 12:27:39 +0000 Subject: [PATCH 01/10] Add option to show warnings when props could be accessed via this Ref #1636, this is my first stab at adding an option to not treat generic access to `this` as 'using' properties / data / computed, etc. If this is the right approach, I can try adding tests if needed. It's more general I think than what you'd proposed in that issue, but for my use case it works well. --- lib/rules/no-unused-properties.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index 040ee414c..a7e1a7117 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -55,6 +55,8 @@ const GROUP_SETUP = 'setup' const GROUP_WATCHER = 'watch' const GROUP_EXPOSE = 'expose' +const STOPREPORTING_THIS = 'ThisExpression' + const PROPERTY_LABEL = { props: 'property', data: 'data', @@ -206,7 +208,15 @@ module.exports = { uniqueItems: true }, deepData: { type: 'boolean' }, - ignorePublicMembers: { type: 'boolean' } + ignorePublicMembers: { type: 'boolean' }, + stopReporting: { + type: 'array', + items: { + enum: [ STOPREPORTING_THIS ] + }, + additionalItems: false, + uniqueItems: true + } }, additionalProperties: false } @@ -221,6 +231,7 @@ module.exports = { const groups = new Set(options.groups || [GROUP_PROPERTY]) const deepData = Boolean(options.deepData) const ignorePublicMembers = Boolean(options.ignorePublicMembers) + const stopReporting = new Set(options.stopReporting || [STOPREPORTING_THIS]) const propertyReferenceExtractor = definePropertyReferenceExtractor(context) @@ -560,6 +571,9 @@ module.exports = { if (!utils.isThis(node, context)) { return } + if (!stopReporting.has(STOPREPORTING_THIS)) { + return + } const container = getVueComponentPropertiesContainer(vueData.node) const propertyReferences = propertyReferenceExtractor.extractFromExpression(node, false) From 1158ea8afcf3e9372b749aec7872ce9ecc655d8c Mon Sep 17 00:00:00 2001 From: David Lomas Date: Thu, 9 Mar 2023 17:14:46 +0000 Subject: [PATCH 02/10] Fix case handling for this[unknown] and return this --- lib/rules/no-unused-properties.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index a7e1a7117..8b5da354f 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -55,7 +55,8 @@ const GROUP_SETUP = 'setup' const GROUP_WATCHER = 'watch' const GROUP_EXPOSE = 'expose' -const STOPREPORTING_THIS = 'ThisExpression' +const STOPREPORTING_UNKNOWN = 'unknownPropertyAccess' +const STOPREPORTING_RETURN = 'returnInstance' const PROPERTY_LABEL = { props: 'property', @@ -212,7 +213,10 @@ module.exports = { stopReporting: { type: 'array', items: { - enum: [ STOPREPORTING_THIS ] + enum: [ + STOPREPORTING_UNKNOWN, + STOPREPORTING_RETURN + ] }, additionalItems: false, uniqueItems: true @@ -231,7 +235,7 @@ module.exports = { const groups = new Set(options.groups || [GROUP_PROPERTY]) const deepData = Boolean(options.deepData) const ignorePublicMembers = Boolean(options.ignorePublicMembers) - const stopReporting = new Set(options.stopReporting || [STOPREPORTING_THIS]) + const stopReporting = new Set(options.stopReporting || [STOPREPORTING_UNKNOWN, STOPREPORTING_RETURN]) const propertyReferenceExtractor = definePropertyReferenceExtractor(context) @@ -571,9 +575,18 @@ module.exports = { if (!utils.isThis(node, context)) { return } - if (!stopReporting.has(STOPREPORTING_THIS)) { + + // e.g. return this + if (node.parent.type === 'ReturnStatement' && + !stopReporting.has(STOPREPORTING_RETURN)) { return - } + } + // e.g. this[unknown] + if (node.parent.computed && + !stopReporting.has(STOPREPORTING_UNKNOWN)) { + return + } + const container = getVueComponentPropertiesContainer(vueData.node) const propertyReferences = propertyReferenceExtractor.extractFromExpression(node, false) From 121196f1132061db44cebbfc5766f5c9f1728673 Mon Sep 17 00:00:00 2001 From: David Lomas Date: Thu, 9 Mar 2023 18:04:35 +0000 Subject: [PATCH 03/10] Fix linting errors --- lib/rules/no-unused-properties.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index 8b5da354f..b6a77e77e 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -213,10 +213,7 @@ module.exports = { stopReporting: { type: 'array', items: { - enum: [ - STOPREPORTING_UNKNOWN, - STOPREPORTING_RETURN - ] + enum: [STOPREPORTING_UNKNOWN, STOPREPORTING_RETURN] }, additionalItems: false, uniqueItems: true @@ -235,7 +232,9 @@ module.exports = { const groups = new Set(options.groups || [GROUP_PROPERTY]) const deepData = Boolean(options.deepData) const ignorePublicMembers = Boolean(options.ignorePublicMembers) - const stopReporting = new Set(options.stopReporting || [STOPREPORTING_UNKNOWN, STOPREPORTING_RETURN]) + const stopReporting = new Set( + options.stopReporting || [STOPREPORTING_UNKNOWN, STOPREPORTING_RETURN] + ) const propertyReferenceExtractor = definePropertyReferenceExtractor(context) @@ -577,15 +576,19 @@ module.exports = { } // e.g. return this - if (node.parent.type === 'ReturnStatement' && - !stopReporting.has(STOPREPORTING_RETURN)) { + if ( + node.parent.type === 'ReturnStatement' && + !stopReporting.has(STOPREPORTING_RETURN) + ) { return - } + } // e.g. this[unknown] - if (node.parent.computed && - !stopReporting.has(STOPREPORTING_UNKNOWN)) { + if ( + node.parent.computed && + !stopReporting.has(STOPREPORTING_UNKNOWN) + ) { return - } + } const container = getVueComponentPropertiesContainer(vueData.node) const propertyReferences = From b424846374e6e53909c287a65c6918447f36d6cf Mon Sep 17 00:00:00 2001 From: David Lomas Date: Fri, 10 Mar 2023 10:29:00 +0000 Subject: [PATCH 04/10] Add tests for stopReporting options --- tests/lib/rules/no-unused-properties.js | 172 +++++++++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index a75d83e72..634bc1095 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -21,6 +21,30 @@ const allOptions = [ ] const deepDataOptions = [{ groups: ['data'], deepData: true }] +const stopReportingOptions = { + // Stop reporting errors when accessing via unknown property, e.g. this[varName] + unknownPropertyAccess: [ + { + groups: ['computed'], + stopReporting: ['unknownPropertyAccess'] + } + ], + // Stop reporting errors when returning this + returnInstance: [ + { + groups: ['computed'], + stopReporting: ['returnInstance'] + } + ], + // Don't stop reporting any errors + none: [ + { + groups: ['computed'], + stopReporting: [] + } + ] +} + tester.run('no-unused-properties', rule, { valid: [ // a property used in a script expression @@ -1697,9 +1721,58 @@ tester.run('no-unused-properties', rule, { }, }; ` + }, + + // stopReportingOptions: unknownPropertyAccess + { + filename: 'test.vue', + code: ` + + `, + options: stopReportingOptions.unknownPropertyAccess + }, + // stopReportingOptions: returnInstance + { + filename: 'test.vue', + code: ` + + `, + options: stopReportingOptions.returnInstance } ], - invalid: [ // unused property { @@ -2803,6 +2876,103 @@ tester.run('no-unused-properties', rule, { line: 10 } ] + }, + + // stopReportingOptions: unknownPropertyAccess + { + filename: 'test.vue', + code: ` + + `, + options: stopReportingOptions.unknownPropertyAccess, + errors: [ + { + message: "'two' of computed property found, but never used.", + line: 8 + } + ] + }, + // stopReportingOptions: returnInstance + { + filename: 'test.vue', + code: ` + + `, + options: stopReportingOptions.returnInstance, + errors: [ + { + message: "'two' of computed property found, but never used.", + line: 8 + } + ] + }, + // stopReportingOptions: [] + { + filename: 'test.vue', + code: ` + + `, + options: stopReportingOptions.none, + errors: [ + { + message: "'two' of computed property found, but never used.", + line: 8 + } + ] } ] }) From f285bc2e3526b933d4dd0930f59f97f80077f10d Mon Sep 17 00:00:00 2001 From: David Lomas Date: Mon, 20 Mar 2023 23:01:48 +0000 Subject: [PATCH 05/10] Refactor stopReporting options into property-references.js Add additional test --- lib/rules/no-unused-properties.js | 28 ++++++++----------- lib/utils/property-references.js | 25 +++++++++++++---- tests/lib/rules/no-unused-properties.js | 36 +++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index b6a77e77e..6d45059f4 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -235,8 +235,18 @@ module.exports = { const stopReporting = new Set( options.stopReporting || [STOPREPORTING_UNKNOWN, STOPREPORTING_RETURN] ) + const stopReportingUnknown = Boolean( + stopReporting.has(STOPREPORTING_UNKNOWN) + ) + const stopReportingReturn = Boolean(stopReporting.has(STOPREPORTING_RETURN)) - const propertyReferenceExtractor = definePropertyReferenceExtractor(context) + const propertyReferenceExtractor = definePropertyReferenceExtractor( + context, + { + stopReportingUnknown, + stopReportingReturn + } + ) /** @type {TemplatePropertiesContainer} */ const templatePropertiesContainer = { @@ -574,22 +584,6 @@ module.exports = { if (!utils.isThis(node, context)) { return } - - // e.g. return this - if ( - node.parent.type === 'ReturnStatement' && - !stopReporting.has(STOPREPORTING_RETURN) - ) { - return - } - // e.g. this[unknown] - if ( - node.parent.computed && - !stopReporting.has(STOPREPORTING_UNKNOWN) - ) { - return - } - const container = getVueComponentPropertiesContainer(vueData.node) const propertyReferences = propertyReferenceExtractor.extractFromExpression(node, false) diff --git a/lib/utils/property-references.js b/lib/utils/property-references.js index 9e8b6638c..d840384fb 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, + { stopReportingUnknown = true, stopReportingReturn = true } = {} +) { /** @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 stopReportingUnknown ? ANY : NEVER + } } 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 (stopReportingReturn) { + return maybeExternalUsed(parent) ? ANY : NEVER + } else { + return NEVER + } + } } return NEVER } diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index 634bc1095..379299dee 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -2973,6 +2973,42 @@ tester.run('no-unused-properties', rule, { line: 8 } ] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [ + { + groups: ['data'], + deepData: true, + stopReporting: [] + } + ], + errors: [ + { + message: "'foo.bar' of data found, but never used.", + line: 7 + } + ] } ] }) From ad7ad796a6622f5d03a4867515ef7dde4103defc Mon Sep 17 00:00:00 2001 From: David Lomas Date: Wed, 22 Mar 2023 15:10:34 +0000 Subject: [PATCH 06/10] Refactor option / argument names for consistency --- lib/rules/no-unused-properties.js | 22 ++-- lib/utils/property-references.js | 10 +- tests/lib/rules/no-unused-properties.js | 133 ++++-------------------- 3 files changed, 36 insertions(+), 129 deletions(-) diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index 6d45059f4..2873540a3 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -55,8 +55,8 @@ const GROUP_SETUP = 'setup' const GROUP_WATCHER = 'watch' const GROUP_EXPOSE = 'expose' -const STOPREPORTING_UNKNOWN = 'unknownPropertyAccess' -const STOPREPORTING_RETURN = 'returnInstance' +const REPORT_DYNAMIC_THIS = 'reportDynamicThis' +const REPORT_RETURNED_THIS = 'reportReturnedThis' const PROPERTY_LABEL = { props: 'property', @@ -210,10 +210,10 @@ module.exports = { }, deepData: { type: 'boolean' }, ignorePublicMembers: { type: 'boolean' }, - stopReporting: { + reportingOptions: { type: 'array', items: { - enum: [STOPREPORTING_UNKNOWN, STOPREPORTING_RETURN] + enum: [REPORT_DYNAMIC_THIS, REPORT_RETURNED_THIS] }, additionalItems: false, uniqueItems: true @@ -232,19 +232,15 @@ module.exports = { const groups = new Set(options.groups || [GROUP_PROPERTY]) const deepData = Boolean(options.deepData) const ignorePublicMembers = Boolean(options.ignorePublicMembers) - const stopReporting = new Set( - options.stopReporting || [STOPREPORTING_UNKNOWN, STOPREPORTING_RETURN] - ) - const stopReportingUnknown = Boolean( - stopReporting.has(STOPREPORTING_UNKNOWN) - ) - const stopReportingReturn = Boolean(stopReporting.has(STOPREPORTING_RETURN)) + const reportingOptions = new Set(options.reportingOptions || []) + const reportDynamicThis = Boolean(reportingOptions.has(REPORT_DYNAMIC_THIS)) + const reportReturnedThis = Boolean(reportingOptions.has(REPORT_RETURNED_THIS)) const propertyReferenceExtractor = definePropertyReferenceExtractor( context, { - stopReportingUnknown, - stopReportingReturn + reportDynamicThis, + reportReturnedThis } ) diff --git a/lib/utils/property-references.js b/lib/utils/property-references.js index d840384fb..d17f40faa 100644 --- a/lib/utils/property-references.js +++ b/lib/utils/property-references.js @@ -94,7 +94,7 @@ module.exports = { */ function definePropertyReferenceExtractor( context, - { stopReportingUnknown = true, stopReportingReturn = true } = {} + { reportDynamicThis = false, reportReturnedThis = false } = {} ) { /** @type {Map} */ const cacheForExpression = new Map() @@ -324,7 +324,7 @@ function definePropertyReferenceExtractor( withInTemplate ) } else { - return stopReportingUnknown ? ANY : NEVER + return reportDynamicThis ? NEVER : ANY } } return NEVER @@ -346,10 +346,10 @@ function definePropertyReferenceExtractor( return maybeExternalUsed(parent) ? ANY : NEVER } case 'ReturnStatement': { - if (stopReportingReturn) { - return maybeExternalUsed(parent) ? ANY : NEVER - } else { + if (reportReturnedThis) { return NEVER + } else { + return maybeExternalUsed(parent) ? ANY : NEVER } } } diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index 379299dee..3ba1221e2 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -21,26 +21,26 @@ const allOptions = [ ] const deepDataOptions = [{ groups: ['data'], deepData: true }] -const stopReportingOptions = { - // Stop reporting errors when accessing via unknown property, e.g. this[varName] - unknownPropertyAccess: [ +const reportingOptions = { + // Report errors when accessing via unknown property, e.g. this[varName] + reportDynamicThis: [ { groups: ['computed'], - stopReporting: ['unknownPropertyAccess'] + reportingOptions: ['reportDynamicThis'] } ], - // Stop reporting errors when returning this - returnInstance: [ + // Report errors when returning this + reportReturnedThis: [ { groups: ['computed'], - stopReporting: ['returnInstance'] + reportingOptions: ['reportReturnedThis'] } ], - // Don't stop reporting any errors - none: [ + // Report all + all: [ { groups: ['computed'], - stopReporting: [] + reportingOptions: ['reportDynamicThis', 'reportReturnedThis'] } ] } @@ -1721,56 +1721,6 @@ tester.run('no-unused-properties', rule, { }, }; ` - }, - - // stopReportingOptions: unknownPropertyAccess - { - filename: 'test.vue', - code: ` - - `, - options: stopReportingOptions.unknownPropertyAccess - }, - // stopReportingOptions: returnInstance - { - filename: 'test.vue', - code: ` - - `, - options: stopReportingOptions.returnInstance } ], invalid: [ @@ -2878,7 +2828,7 @@ tester.run('no-unused-properties', rule, { ] }, - // stopReportingOptions: unknownPropertyAccess + // reportingOptions: reportDynamicThis { filename: 'test.vue', code: ` @@ -2895,13 +2845,13 @@ tester.run('no-unused-properties', rule, { methods: { handler () { const a = this.one - return this + const i = 'two' + return this[i] }, } } - - `, - options: stopReportingOptions.unknownPropertyAccess, + `, + options: reportingOptions.reportDynamicThis, errors: [ { message: "'two' of computed property found, but never used.", @@ -2909,7 +2859,7 @@ tester.run('no-unused-properties', rule, { } ] }, - // stopReportingOptions: returnInstance + // stopReportingOptions: reportReturnedThis { filename: 'test.vue', code: ` @@ -2926,14 +2876,12 @@ tester.run('no-unused-properties', rule, { methods: { handler () { const a = this.one - const i = 'two' - return this[i] + return this }, } } - - `, - options: stopReportingOptions.returnInstance, + `, + options: reportingOptions.reportReturnedThis, errors: [ { message: "'two' of computed property found, but never used.", @@ -2941,7 +2889,7 @@ tester.run('no-unused-properties', rule, { } ] }, - // stopReportingOptions: [] + // reportingOptions: all { filename: 'test.vue', code: ` @@ -2964,51 +2912,14 @@ tester.run('no-unused-properties', rule, { }, } } - - `, - options: stopReportingOptions.none, + `, + options: reportingOptions.all, errors: [ { message: "'two' of computed property found, but never used.", line: 8 } ] - }, - { - filename: 'test.vue', - code: ` - - `, - options: [ - { - groups: ['data'], - deepData: true, - stopReporting: [] - } - ], - errors: [ - { - message: "'foo.bar' of data found, but never used.", - line: 7 - } - ] } ] }) From 8172000d9bcf9363ae42dfdd5e1c8780077c4a3c Mon Sep 17 00:00:00 2001 From: David Lomas Date: Thu, 23 Mar 2023 17:38:40 +0000 Subject: [PATCH 07/10] Rename options --- lib/rules/no-unused-properties.js | 20 +++++++++--------- lib/utils/property-references.js | 6 +++--- tests/lib/rules/no-unused-properties.js | 27 ++++++++++++++----------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index 2873540a3..60250a156 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -55,8 +55,8 @@ const GROUP_SETUP = 'setup' const GROUP_WATCHER = 'watch' const GROUP_EXPOSE = 'expose' -const REPORT_DYNAMIC_THIS = 'reportDynamicThis' -const REPORT_RETURNED_THIS = 'reportReturnedThis' +const UNREFERENCED_UNKNOWN_MEMBER = 'unknownMemberAsUnreferenced' +const UNREFERENCED_RETURN = 'returnAsUnreferenced' const PROPERTY_LABEL = { props: 'property', @@ -210,10 +210,10 @@ module.exports = { }, deepData: { type: 'boolean' }, ignorePublicMembers: { type: 'boolean' }, - reportingOptions: { + unreferencedOptions: { type: 'array', items: { - enum: [REPORT_DYNAMIC_THIS, REPORT_RETURNED_THIS] + enum: [UNREFERENCED_UNKNOWN_MEMBER, UNREFERENCED_RETURN] }, additionalItems: false, uniqueItems: true @@ -232,15 +232,17 @@ module.exports = { const groups = new Set(options.groups || [GROUP_PROPERTY]) const deepData = Boolean(options.deepData) const ignorePublicMembers = Boolean(options.ignorePublicMembers) - const reportingOptions = new Set(options.reportingOptions || []) - const reportDynamicThis = Boolean(reportingOptions.has(REPORT_DYNAMIC_THIS)) - const reportReturnedThis = Boolean(reportingOptions.has(REPORT_RETURNED_THIS)) + const unreferencedOptions = new Set(options.unreferencedOptions || []) const propertyReferenceExtractor = definePropertyReferenceExtractor( context, { - reportDynamicThis, - reportReturnedThis + unknownMemberAsUnreferenced: Boolean( + unreferencedOptions.has(UNREFERENCED_UNKNOWN_MEMBER) + ), + returnAsUnreferenced: Boolean( + unreferencedOptions.has(UNREFERENCED_RETURN) + ) } ) diff --git a/lib/utils/property-references.js b/lib/utils/property-references.js index d17f40faa..ead7fd04a 100644 --- a/lib/utils/property-references.js +++ b/lib/utils/property-references.js @@ -94,7 +94,7 @@ module.exports = { */ function definePropertyReferenceExtractor( context, - { reportDynamicThis = false, reportReturnedThis = false } = {} + { unknownMemberAsUnreferenced = false, returnAsUnreferenced = false } = {} ) { /** @type {Map} */ const cacheForExpression = new Map() @@ -324,7 +324,7 @@ function definePropertyReferenceExtractor( withInTemplate ) } else { - return reportDynamicThis ? NEVER : ANY + return unknownMemberAsUnreferenced ? NEVER : ANY } } return NEVER @@ -346,7 +346,7 @@ function definePropertyReferenceExtractor( return maybeExternalUsed(parent) ? ANY : NEVER } case 'ReturnStatement': { - if (reportReturnedThis) { + if (returnAsUnreferenced) { return NEVER } else { return maybeExternalUsed(parent) ? ANY : NEVER diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index 3ba1221e2..5d1df259c 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -21,26 +21,29 @@ const allOptions = [ ] const deepDataOptions = [{ groups: ['data'], deepData: true }] -const reportingOptions = { +const unreferencedOptions = { // Report errors when accessing via unknown property, e.g. this[varName] - reportDynamicThis: [ + unknownMemberAsUnreferenced: [ { groups: ['computed'], - reportingOptions: ['reportDynamicThis'] + unreferencedOptions: ['unknownMemberAsUnreferenced'] } ], // Report errors when returning this - reportReturnedThis: [ + returnAsUnreferenced: [ { groups: ['computed'], - reportingOptions: ['reportReturnedThis'] + unreferencedOptions: ['returnAsUnreferenced'] } ], // Report all all: [ { groups: ['computed'], - reportingOptions: ['reportDynamicThis', 'reportReturnedThis'] + unreferencedOptions: [ + 'unknownMemberAsUnreferenced', + 'returnAsUnreferenced' + ] } ] } @@ -2828,7 +2831,7 @@ tester.run('no-unused-properties', rule, { ] }, - // reportingOptions: reportDynamicThis + // unreferencedOptions: unknownMemberAsUnreferenced { filename: 'test.vue', code: ` @@ -2851,7 +2854,7 @@ tester.run('no-unused-properties', rule, { } } `, - options: reportingOptions.reportDynamicThis, + options: unreferencedOptions.unknownMemberAsUnreferenced, errors: [ { message: "'two' of computed property found, but never used.", @@ -2859,7 +2862,7 @@ tester.run('no-unused-properties', rule, { } ] }, - // stopReportingOptions: reportReturnedThis + // unreferencedOptions: returnAsUnreferenced { filename: 'test.vue', code: ` @@ -2881,7 +2884,7 @@ tester.run('no-unused-properties', rule, { } } `, - options: reportingOptions.reportReturnedThis, + options: unreferencedOptions.returnAsUnreferenced, errors: [ { message: "'two' of computed property found, but never used.", @@ -2889,7 +2892,7 @@ tester.run('no-unused-properties', rule, { } ] }, - // reportingOptions: all + // unreferencedOptions: all { filename: 'test.vue', code: ` @@ -2913,7 +2916,7 @@ tester.run('no-unused-properties', rule, { } } `, - options: reportingOptions.all, + options: unreferencedOptions.all, errors: [ { message: "'two' of computed property found, but never used.", From 51c92967db74b8355fe15c69cf7a3856f1501223 Mon Sep 17 00:00:00 2001 From: David Lomas Date: Fri, 24 Mar 2023 17:07:10 +0000 Subject: [PATCH 08/10] Add additional test for returnAsUnreferenced with deepData --- tests/lib/rules/no-unused-properties.js | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/lib/rules/no-unused-properties.js b/tests/lib/rules/no-unused-properties.js index 5d1df259c..8d4b2b215 100644 --- a/tests/lib/rules/no-unused-properties.js +++ b/tests/lib/rules/no-unused-properties.js @@ -2892,6 +2892,44 @@ tester.run('no-unused-properties', rule, { } ] }, + // 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', From d75ea583e682d4b6d5dc1be2991eb479761a18e4 Mon Sep 17 00:00:00 2001 From: David Lomas Date: Fri, 7 Apr 2023 13:18:47 +0100 Subject: [PATCH 09/10] Add documentation for new option --- docs/rules/no-unused-properties.md | 71 +++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 2 deletions(-) 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 From bd4454b5fb0125463e531c07720151a763990c26 Mon Sep 17 00:00:00 2001 From: David Lomas Date: Thu, 13 Apr 2023 09:53:20 +0100 Subject: [PATCH 10/10] Remove unnecessary cast to Boolean --- lib/rules/no-unused-properties.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/rules/no-unused-properties.js b/lib/rules/no-unused-properties.js index 41644484c..1421ad0b8 100644 --- a/lib/rules/no-unused-properties.js +++ b/lib/rules/no-unused-properties.js @@ -237,12 +237,10 @@ module.exports = { const propertyReferenceExtractor = definePropertyReferenceExtractor( context, { - unknownMemberAsUnreferenced: Boolean( - unreferencedOptions.has(UNREFERENCED_UNKNOWN_MEMBER) + unknownMemberAsUnreferenced: unreferencedOptions.has( + UNREFERENCED_UNKNOWN_MEMBER ), - returnAsUnreferenced: Boolean( - unreferencedOptions.has(UNREFERENCED_RETURN) - ) + returnAsUnreferenced: unreferencedOptions.has(UNREFERENCED_RETURN) } )