From bcb7474ba75fb50cc63e0705809c34a5fbbd832e Mon Sep 17 00:00:00 2001 From: Shridhar Goel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 16 Aug 2024 03:49:50 +0800 Subject: [PATCH 1/6] Handle functions and assignment in prefer-at condition --- eslint-plugin-expensify/prefer-at.js | 16 +++++++++++++++- eslint-plugin-expensify/tests/prefer-at.test.js | 6 ++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/eslint-plugin-expensify/prefer-at.js b/eslint-plugin-expensify/prefer-at.js index 0e92f7d..13c6f46 100644 --- a/eslint-plugin-expensify/prefer-at.js +++ b/eslint-plugin-expensify/prefer-at.js @@ -67,12 +67,26 @@ module.exports = { return indexExpression; } + function isAssignmentExpression(node) { + return node.parent && node.parent.type === AST_NODE_TYPES.AssignmentExpression && node.parent.left === node; + } + function checkNode(node) { if (node.type === AST_NODE_TYPES.MemberExpression && node.property) { if (!isArrayType(node.object)) { return; } + // Skip if the property is a method (like a?.map) + if (node.parent && node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) { + return; + } + + // Skip if the node is part of an assignment expression + if (isAssignmentExpression(node)) { + return; + } + const indexExpression = parseExpression(node.property); if (indexExpression !== null && indexExpression !== 'length' && indexExpression !== 'at') { @@ -91,7 +105,7 @@ module.exports = { function shouldIgnoreNode(node) { return ( node.parent && - node.parent.type === AST_NODE_TYPES.MemberExpression && + (node.parent.type === AST_NODE_TYPES.MemberExpression || node.parent.type === AST_NODE_TYPES.OptionalMemberExpression) && node.parent.property === node ); } diff --git a/eslint-plugin-expensify/tests/prefer-at.test.js b/eslint-plugin-expensify/tests/prefer-at.test.js index dd65f76..84e3e4f 100644 --- a/eslint-plugin-expensify/tests/prefer-at.test.js +++ b/eslint-plugin-expensify/tests/prefer-at.test.js @@ -66,6 +66,12 @@ ruleTester.run('prefer-at', rule, { { code: 'const a = ["a", "b", "c"] as const; a[0]', }, + { + code: 'const example = [1, 2, 3, 4]; example.map(x => x * 2);', + }, + { + code: 'const example = [1, 2, 3, 4]; const x = 1; example[x] = 5;', + }, ], invalid: [ { From ebf731fdda4391e8d4ff15c6d90459aa048e7259 Mon Sep 17 00:00:00 2001 From: Shridhar Goel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 16 Aug 2024 01:21:12 +0530 Subject: [PATCH 2/6] Update --- eslint-plugin-expensify/prefer-at.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint-plugin-expensify/prefer-at.js b/eslint-plugin-expensify/prefer-at.js index 13c6f46..fddd196 100644 --- a/eslint-plugin-expensify/prefer-at.js +++ b/eslint-plugin-expensify/prefer-at.js @@ -105,7 +105,7 @@ module.exports = { function shouldIgnoreNode(node) { return ( node.parent && - (node.parent.type === AST_NODE_TYPES.MemberExpression || node.parent.type === AST_NODE_TYPES.OptionalMemberExpression) && + (node.parent.type === AST_NODE_TYPES.MemberExpression) && node.parent.property === node ); } From b15c9ccdc56c978525b4e0af2d97f19de20540dc Mon Sep 17 00:00:00 2001 From: Shridhar Goel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 16 Aug 2024 01:22:28 +0530 Subject: [PATCH 3/6] Update --- eslint-plugin-expensify/prefer-at.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint-plugin-expensify/prefer-at.js b/eslint-plugin-expensify/prefer-at.js index fddd196..3222d02 100644 --- a/eslint-plugin-expensify/prefer-at.js +++ b/eslint-plugin-expensify/prefer-at.js @@ -105,7 +105,7 @@ module.exports = { function shouldIgnoreNode(node) { return ( node.parent && - (node.parent.type === AST_NODE_TYPES.MemberExpression) && + node.parent.type === AST_NODE_TYPES.MemberExpression && node.parent.property === node ); } From d33d76712413ae0697cd58d4c9273ed0d5f69453 Mon Sep 17 00:00:00 2001 From: Shridhar Goel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 16 Aug 2024 01:22:59 +0530 Subject: [PATCH 4/6] Update comments --- eslint-plugin-expensify/prefer-at.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eslint-plugin-expensify/prefer-at.js b/eslint-plugin-expensify/prefer-at.js index 3222d02..d169102 100644 --- a/eslint-plugin-expensify/prefer-at.js +++ b/eslint-plugin-expensify/prefer-at.js @@ -77,12 +77,12 @@ module.exports = { return; } - // Skip if the property is a method (like a?.map) + // Skip if the property is a method (like a.map) if (node.parent && node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) { return; } - // Skip if the node is part of an assignment expression + // Skip if the node is part of an assignment expression (like a[i] = 2) if (isAssignmentExpression(node)) { return; } From edb80f1ca31545d9e96ae17b1b315c33e4828402 Mon Sep 17 00:00:00 2001 From: Shridhar Goel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:27:37 +0530 Subject: [PATCH 5/6] Update --- eslint-plugin-expensify/prefer-at.js | 12 ++++------ .../utils/is-left-hand-side.js | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 eslint-plugin-expensify/utils/is-left-hand-side.js diff --git a/eslint-plugin-expensify/prefer-at.js b/eslint-plugin-expensify/prefer-at.js index d169102..c7c1056 100644 --- a/eslint-plugin-expensify/prefer-at.js +++ b/eslint-plugin-expensify/prefer-at.js @@ -1,6 +1,8 @@ const { AST_NODE_TYPES, ESLintUtils } = require('@typescript-eslint/utils'); const message = require('./CONST').MESSAGE.PREFER_AT; +const { isLeftHandSide } = require('./utils/is-left-hand-side'); + module.exports = { meta: { fixable: 'code', @@ -67,23 +69,19 @@ module.exports = { return indexExpression; } - function isAssignmentExpression(node) { - return node.parent && node.parent.type === AST_NODE_TYPES.AssignmentExpression && node.parent.left === node; - } - function checkNode(node) { if (node.type === AST_NODE_TYPES.MemberExpression && node.property) { if (!isArrayType(node.object)) { return; } - // Skip if the property is a method (like a.map) + // Skip if the property is a method (like a?.map) if (node.parent && node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) { return; } - // Skip if the node is part of an assignment expression (like a[i] = 2) - if (isAssignmentExpression(node)) { + // Skip if the node is part of an assignment expression + if (isLeftHandSide(node)) { return; } diff --git a/eslint-plugin-expensify/utils/is-left-hand-side.js b/eslint-plugin-expensify/utils/is-left-hand-side.js new file mode 100644 index 0000000..b7872a4 --- /dev/null +++ b/eslint-plugin-expensify/utils/is-left-hand-side.js @@ -0,0 +1,23 @@ +// https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/rules/utils/is-left-hand-side.js + +function isLeftHandSide(node) { + return ( + (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' + && node.parent.argument === node + ); +} + +module.exports = { isLeftHandSide }; \ No newline at end of file From b2de406882fff9535b0f7fa76fadb6f743310be3 Mon Sep 17 00:00:00 2001 From: Shridhar Goel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:23:46 +0530 Subject: [PATCH 6/6] Update --- .../utils/is-left-hand-side.js | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/eslint-plugin-expensify/utils/is-left-hand-side.js b/eslint-plugin-expensify/utils/is-left-hand-side.js index b7872a4..6b03b32 100644 --- a/eslint-plugin-expensify/utils/is-left-hand-side.js +++ b/eslint-plugin-expensify/utils/is-left-hand-side.js @@ -1,23 +1,27 @@ // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/rules/utils/is-left-hand-side.js +const { AST_NODE_TYPES } = require('@typescript-eslint/utils'); + function isLeftHandSide(node) { + const { parent } = node; + return ( - (node.parent.type === 'AssignmentExpression' || node.parent.type === 'AssignmentPattern') - && node.parent.left === node + (parent.type === AST_NODE_TYPES.AssignmentExpression || parent.type === AST_NODE_TYPES.AssignmentPattern) + && parent.left === node ) - || (node.parent.type === 'UpdateExpression' && node.parent.argument === node) - || (node.parent.type === 'ArrayPattern' && node.parent.elements.includes(node)) + || (parent.type === AST_NODE_TYPES.UpdateExpression && parent.argument === node) + || (parent.type === AST_NODE_TYPES.ArrayPattern && parent.elements.includes(node)) || ( - node.parent.type === 'Property' - && node.parent.value === node - && node.parent.parent.type === 'ObjectPattern' - && node.parent.parent.properties.includes(node.parent) + parent.type === AST_NODE_TYPES.Property + && parent.value === node + && parent.parent.type === AST_NODE_TYPES.ObjectPattern + && parent.parent.properties.includes(parent) ) || ( - node.parent.type === 'UnaryExpression' - && node.parent.operator === 'delete' - && node.parent.argument === node + parent.type === AST_NODE_TYPES.UnaryExpression + && parent.operator === 'delete' + && parent.argument === node ); } -module.exports = { isLeftHandSide }; \ No newline at end of file +module.exports = { isLeftHandSide };