diff --git a/lib/rules/strict-logical-expressions.ts b/lib/rules/strict-logical-expressions.ts index c6df887..3eb89b1 100644 --- a/lib/rules/strict-logical-expressions.ts +++ b/lib/rules/strict-logical-expressions.ts @@ -97,17 +97,29 @@ export default createRule({ } } + // Return the core identifier or expression + function determineNode(originalNode: TSESTree.Expression) { + let nodeToEvaluate = originalNode; + if (nodeToEvaluate.type === TSESTree.AST_NODE_TYPES.ChainExpression) { + nodeToEvaluate = nodeToEvaluate.expression; + } + + if ( + nodeToEvaluate.type === TSESTree.AST_NODE_TYPES.MemberExpression && + nodeToEvaluate.property.type !== + TSESTree.AST_NODE_TYPES.PrivateIdentifier + ) { + nodeToEvaluate = nodeToEvaluate.property; + } + + return nodeToEvaluate; + } + function checkLogicalExpression( expressionNode: TSESTree.LogicalExpression, checkRightNode: boolean ) { - let leftNode = expressionNode.left; - if ( - leftNode.type === TSESTree.AST_NODE_TYPES.MemberExpression && - leftNode.property.type !== TSESTree.AST_NODE_TYPES.PrivateIdentifier - ) { - leftNode = leftNode.property; - } + const leftNode = determineNode(expressionNode.left); if (leftNode.type === TSESTree.AST_NODE_TYPES.LogicalExpression) { checkLogicalExpression(leftNode, true); @@ -116,13 +128,7 @@ export default createRule({ } if (checkRightNode) { - let rightNode = expressionNode.right; - if ( - rightNode.type === TSESTree.AST_NODE_TYPES.MemberExpression && - rightNode.property.type !== TSESTree.AST_NODE_TYPES.PrivateIdentifier - ) { - rightNode = rightNode.property; - } + const rightNode = determineNode(expressionNode.right); if (rightNode.type === TSESTree.AST_NODE_TYPES.Identifier) { checkAndReportIdentifier(rightNode, expressionNode.right); diff --git a/tests/lib/rules/strict-logical-expressions.test.ts b/tests/lib/rules/strict-logical-expressions.test.ts index f984c37..4c71623 100644 --- a/tests/lib/rules/strict-logical-expressions.test.ts +++ b/tests/lib/rules/strict-logical-expressions.test.ts @@ -97,6 +97,19 @@ ruleTester.run("strict-logical-expressions", rule, { options: [{ allowString: true }], filename: "react.tsx", }, + { + code: [ + 'type Bar = "bar"', + "const obj: { foo: Bar } = { foo: 'bar' };", + "{obj?.foo && }", + ].join("\n"), + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + filename: "react.tsx", + }, ], invalid: [ { @@ -248,5 +261,41 @@ ruleTester.run("strict-logical-expressions", rule, { ].join("\n"), filename: "react.tsx", }, + { + code: [ + "const first = 100;", + 'const second = { foo: "bar" };', + "{first && second?.foo && }", + ].join("\n"), + errors: [{ messageId: "conditionErrorFalseyString" }], + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + output: [ + "const first = 100;", + 'const second = { foo: "bar" };', + "{first && !!second?.foo && }", + ].join("\n"), + filename: "react.tsx", + }, + { + code: [ + "const obj = { foo: 100 };", + "{obj?.foo && }", + ].join("\n"), + errors: [{ messageId: "conditionErrorFalseyNumber" }], + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + output: [ + "const obj = { foo: 100 };", + "{!!obj?.foo && }", + ].join("\n"), + filename: "react.tsx", + }, ], });