diff --git a/rules/consistent-destructuring.js b/rules/consistent-destructuring.js index 17ddabbe60..45cfe94d7d 100644 --- a/rules/consistent-destructuring.js +++ b/rules/consistent-destructuring.js @@ -1,6 +1,7 @@ 'use strict'; const avoidCapture = require('./utils/avoid-capture.js'); -const {not, notLeftHandSideSelector} = require('./selectors/index.js'); +const {not} = require('./selectors/index.js'); +const isLeftHandSide = require('./utils/is-left-hand-side.js'); const MESSAGE_ID = 'consistentDestructuring'; const MESSAGE_ID_SUGGEST = 'consistentDestructuringSuggest'; @@ -15,7 +16,6 @@ const declaratorSelector = [ const memberSelector = [ 'MemberExpression', '[computed!=true]', - notLeftHandSideSelector(), not([ 'CallExpression > .callee', 'NewExpression> .callee', @@ -70,6 +70,10 @@ const create = context => { }); }, [memberSelector](node) { + if (isLeftHandSide(node)) { + return; + } + const declaration = declarations.get(source.getText(node.object)); if (!declaration) { diff --git a/rules/prefer-array-find.js b/rules/prefer-array-find.js index e75c3c0462..965d2e55bb 100644 --- a/rules/prefer-array-find.js +++ b/rules/prefer-array-find.js @@ -3,7 +3,6 @@ const {isParenthesized, findVariable} = require('@eslint-community/eslint-utils' const { not, methodCallSelector, - notLeftHandSideSelector, } = require('./selectors/index.js'); const getVariableIdentifiers = require('./utils/get-variable-identifiers.js'); const avoidCapture = require('./utils/avoid-capture.js'); @@ -15,6 +14,7 @@ const { removeMethodCall, renameVariable, } = require('./fix/index.js'); +const isLeftHandSide = require('./utils/is-left-hand-side.js'); const ERROR_ZERO_INDEX = 'error-zero-index'; const ERROR_SHIFT = 'error-shift'; @@ -62,7 +62,6 @@ const zeroIndexSelector = [ '[computed!=false]', '[property.type="Literal"]', '[property.raw="0"]', - notLeftHandSideSelector(), methodCallSelector({ ...filterMethodSelectorOptions, path: 'object', @@ -267,6 +266,10 @@ const create = context => { const listeners = { [zeroIndexSelector](node) { + if (isLeftHandSide(node)) { + return; + } + return { node: node.object.callee.property, messageId: ERROR_ZERO_INDEX, diff --git a/rules/prefer-at.js b/rules/prefer-at.js index 1fae8d3f58..a78206c018 100644 --- a/rules/prefer-at.js +++ b/rules/prefer-at.js @@ -13,7 +13,7 @@ const { getNegativeIndexLengthNode, removeLengthNode, } = require('./shared/negative-index.js'); -const {methodCallSelector, callExpressionSelector, notLeftHandSideSelector} = require('./selectors/index.js'); +const {methodCallSelector, callExpressionSelector} = require('./selectors/index.js'); const {removeMemberExpressionProperty, removeMethodCall} = require('./fix/index.js'); const {isLiteral} = require('./ast/index.js'); @@ -38,7 +38,6 @@ const indexAccess = [ 'MemberExpression', '[optional!=true]', '[computed!=false]', - notLeftHandSideSelector(), ].join(''); const sliceCall = methodCallSelector({method: 'slice', minimumArguments: 1, maximumArguments: 2}); const stringCharAt = methodCallSelector({method: 'charAt', argumentsLength: 1}); @@ -150,6 +149,10 @@ function create(context) { return { [indexAccess](node) { + if (isLeftHandSide(node)) { + return; + } + const indexNode = node.property; const lengthNode = getNegativeIndexLengthNode(indexNode, node.object); diff --git a/rules/prefer-number-properties.js b/rules/prefer-number-properties.js index 23210b0e02..b3b733ba6a 100644 --- a/rules/prefer-number-properties.js +++ b/rules/prefer-number-properties.js @@ -2,6 +2,7 @@ const {GlobalReferenceTracker} = require('./utils/global-reference-tracker.js'); const {replaceReferenceIdentifier} = require('./fix/index.js'); const {fixSpaceAroundKeyword} = require('./fix/index.js'); +const isLeftHandSide = require('./utils/is-left-hand-side.js'); const MESSAGE_ID_ERROR = 'error'; const MESSAGE_ID_SUGGESTION = 'suggestion'; @@ -90,6 +91,7 @@ const create = context => { const tracker = new GlobalReferenceTracker({ objects, handle: reference => checkProperty(reference, sourceCode), + filter: ({node}) => !isLeftHandSide(node), }); return tracker.createListeners(context); diff --git a/rules/selectors/index.js b/rules/selectors/index.js index ce539b0fe2..10b13bf04a 100644 --- a/rules/selectors/index.js +++ b/rules/selectors/index.js @@ -19,5 +19,4 @@ module.exports = { callOrNewExpressionSelector: require('./call-or-new-expression-selector.js').callOrNewExpressionSelector, STATIC_REQUIRE_SELECTOR: require('./require-selector.js').STATIC_REQUIRE_SELECTOR, STATIC_REQUIRE_SOURCE_SELECTOR: require('./require-selector.js').STATIC_REQUIRE_SOURCE_SELECTOR, - notLeftHandSideSelector: require('./not-left-hand-side.js'), }; diff --git a/rules/selectors/not-left-hand-side.js b/rules/selectors/not-left-hand-side.js deleted file mode 100644 index 51e16355bb..0000000000 --- a/rules/selectors/not-left-hand-side.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; -const not = require('./negation.js'); - -function notLeftHandSideSelector(path) { - const prefix = path ? `${path}.` : ''; - - // Keep logic sync with `../utils/is-left-hand-side.js` - return not([ - `[${prefix}type="AssignmentExpression"] > .left`, - `[${prefix}type="UpdateExpression"] > .argument`, - `[${prefix}type="UnaryExpression"][${prefix}operator="delete"] > .argument`, - ]); -} - -module.exports = notLeftHandSideSelector; diff --git a/rules/utils/is-left-hand-side.js b/rules/utils/is-left-hand-side.js index f2101c6582..cc3ddb516c 100644 --- a/rules/utils/is-left-hand-side.js +++ b/rules/utils/is-left-hand-side.js @@ -1,9 +1,18 @@ 'use strict'; -// Keep logic sync with `../selector/not-left-hand-side.js` const isLeftHandSide = node => - (node.parent.type === 'AssignmentExpression' && node.parent.left === node) + ( + (node.parent.type === 'AssignmentExpression' || node.parent.type === 'AssignmentPattern') + && node.parent.left === node + ) || (node.parent.type === 'UpdateExpression' && node.parent.argument === node) + || (node.parent.type === 'ArrayPattern' && node.parent.elements.includes(node)) + || ( + node.parent.type === 'Property' + && node.parent.value === node + && node.parent.parent.type === 'ObjectPattern' + && node.parent.parent.properties.includes(node.parent) + ) || ( node.parent.type === 'UnaryExpression' && node.parent.operator === 'delete' diff --git a/test/prefer-array-find.mjs b/test/prefer-array-find.mjs index 9b5167fd8e..087e0d8007 100644 --- a/test/prefer-array-find.mjs +++ b/test/prefer-array-find.mjs @@ -47,6 +47,7 @@ test({ '++ array.filter(foo)[0]', 'array.filter(foo)[0]--', 'delete array.filter(foo)[0]', + '[array.filter(foo)[0] = 1] = []', ], invalid: [ { diff --git a/test/prefer-at.mjs b/test/prefer-at.mjs index 15253fca34..6ced5f4e63 100644 --- a/test/prefer-at.mjs +++ b/test/prefer-at.mjs @@ -19,6 +19,8 @@ test.snapshot({ 'array[array.length - 1] --', 'delete array[array.length - 1]', 'class Foo {bar; #bar; baz() {return this.#bar[this.bar.length - 1]}}', + '([array[array.length - 1]] = [])', + '({foo: array[array.length - 1] = 9} = {})', ], invalid: [ 'array[array.length - 1];', diff --git a/test/prefer-number-properties.mjs b/test/prefer-number-properties.mjs index 68384b1b71..f6970fa3a2 100644 --- a/test/prefer-number-properties.mjs +++ b/test/prefer-number-properties.mjs @@ -91,6 +91,24 @@ test({ return ${code} } `), + + // Not read + 'global.isFinite = Number.isFinite;', + 'global.isFinite ??= 1;', + 'isFinite ||= 1;', + '[global.isFinite] = [];', + '[global.isFinite = 1] = [];', + '[[global.isFinite = 1]] = [];', + '[isFinite] = [];', + '[isFinite = 1] = [];', + '[[isFinite = 1]] = [];', + '({foo: global.isFinite} = {});', + '({foo: global.isFinite = 1} = {});', + '({foo: {bar: global.isFinite = 1}} = {});', + '({foo: isFinite} = {});', + '({foo: isFinite = 1} = {});', + '({foo: {bar: isFinite = 1}} = {});', + 'delete global.isFinite;', ], invalid: [