From 6f50fbf49300ffb4bbe7efc234187b5f3042db2e Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Sun, 22 Sep 2024 19:09:51 -0600 Subject: [PATCH 1/3] fix(eslint-plugin): [prefer-literal-enum-member] allow nested bitwise operations --- .../src/rules/prefer-literal-enum-member.ts | 99 +++++++++---------- .../rules/prefer-literal-enum-member.test.ts | 58 +++++++++++ 2 files changed, 107 insertions(+), 50 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts b/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts index dcc31ba5742a..69ab03ea2868 100644 --- a/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts +++ b/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts @@ -77,69 +77,68 @@ export default createRule({ return false; } - function isAllowedBitwiseOperand( - decl: TSESTree.TSEnumDeclaration, - node: TSESTree.Node, - ): boolean { - return ( - node.type === AST_NODE_TYPES.Literal || isSelfEnumMember(decl, node) - ); - } - return { TSEnumMember(node): void { // If there is no initializer, then this node is just the name of the member, so ignore. if (node.initializer == null) { return; } - // any old literal - if (node.initializer.type === AST_NODE_TYPES.Literal) { - return; - } - // TemplateLiteral without expressions - if ( - node.initializer.type === AST_NODE_TYPES.TemplateLiteral && - node.initializer.expressions.length === 0 - ) { - return; - } const declaration = node.parent.parent; - // -1 and +1 - if (node.initializer.type === AST_NODE_TYPES.UnaryExpression) { - if ( - node.initializer.argument.type === AST_NODE_TYPES.Literal && - ['+', '-'].includes(node.initializer.operator) - ) { - return; + function isAllowedInitializerExpressionRecursive( + node: TSESTree.Expression | TSESTree.PrivateIdentifier, + partOfBitwiseComputation: boolean, + ): boolean { + // You can only refer to an enum member if it's part of a bitwise computation. + // so C = B isn't allowed (special case), but C = A | B is. + if (partOfBitwiseComputation && isSelfEnumMember(declaration, node)) { + return true; } - if ( - allowBitwiseExpressions && - node.initializer.operator === '~' && - isAllowedBitwiseOperand(declaration, node.initializer.argument) - ) { - return; + switch (node.type) { + // any old literal + case AST_NODE_TYPES.Literal: + return true; + + // TemplateLiteral without expressions + case AST_NODE_TYPES.TemplateLiteral: + return node.expressions.length === 0; + + // +123, -123, etc. + case AST_NODE_TYPES.UnaryExpression: + if (['+', '-'].includes(node.operator)) { + return isAllowedInitializerExpressionRecursive( + node.argument, + partOfBitwiseComputation, + ); + } + + if (allowBitwiseExpressions && node.operator === '~') { + return isAllowedInitializerExpressionRecursive( + node.argument, + true, + ); + } + return false; + + case AST_NODE_TYPES.BinaryExpression: + if ( + allowBitwiseExpressions && + ['|', '&', '^', '<<', '>>', '>>>'].includes(node.operator) + ) { + return ( + isAllowedInitializerExpressionRecursive(node.left, true) && + isAllowedInitializerExpressionRecursive(node.right, true) + ); + } + return false; + + default: + return false; } } - if ( - node.initializer.type === AST_NODE_TYPES.UnaryExpression && - node.initializer.argument.type === AST_NODE_TYPES.Literal && - (['+', '-'].includes(node.initializer.operator) || - (allowBitwiseExpressions && node.initializer.operator === '~')) - ) { - return; - } - if ( - allowBitwiseExpressions && - node.initializer.type === AST_NODE_TYPES.BinaryExpression && - ['|', '&', '^', '<<', '>>', '>>>'].includes( - node.initializer.operator, - ) && - isAllowedBitwiseOperand(declaration, node.initializer.left) && - isAllowedBitwiseOperand(declaration, node.initializer.right) - ) { + if (isAllowedInitializerExpressionRecursive(node.initializer, false)) { return; } diff --git a/packages/eslint-plugin/tests/rules/prefer-literal-enum-member.test.ts b/packages/eslint-plugin/tests/rules/prefer-literal-enum-member.test.ts index 1247ee27bf29..d38232630cf6 100644 --- a/packages/eslint-plugin/tests/rules/prefer-literal-enum-member.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-literal-enum-member.test.ts @@ -110,6 +110,50 @@ enum Foo { enum Foo { ['A-1'] = 1 << 0, C = ~Foo['A-1'], +} + `, + options: [{ allowBitwiseExpressions: true }], + }, + { + code: ` +enum Foo { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + D = A | B | C, +} + `, + options: [{ allowBitwiseExpressions: true }], + }, + { + code: ` +enum Foo { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + D = Foo.A | Foo.B | Foo.C, +} + `, + options: [{ allowBitwiseExpressions: true }], + }, + { + code: ` +enum Foo { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + D = Foo.A | (Foo.B & ~Foo.C), +} + `, + options: [{ allowBitwiseExpressions: true }], + }, + { + code: ` +enum Foo { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + D = Foo.A | -Foo.B, } `, options: [{ allowBitwiseExpressions: true }], @@ -433,5 +477,19 @@ enum Foo { }, ], }, + { + code: ` +enum Foo { + A, + B = +A, +} + `, + errors: [ + { + messageId: 'notLiteral', + line: 4, + }, + ], + }, ], }); From a1e859618bc62d0c04e77bb2bfd9c499de5b1bab Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Sun, 22 Sep 2024 19:35:11 -0600 Subject: [PATCH 2/3] tweak things slightly --- .../src/rules/prefer-literal-enum-member.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts b/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts index 69ab03ea2868..4bcaa3c348a2 100644 --- a/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts +++ b/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts @@ -113,20 +113,18 @@ export default createRule({ ); } - if (allowBitwiseExpressions && node.operator === '~') { - return isAllowedInitializerExpressionRecursive( - node.argument, - true, + if (allowBitwiseExpressions) { + return ( + node.operator === '~' && + isAllowedInitializerExpressionRecursive(node.argument, true) ); } return false; case AST_NODE_TYPES.BinaryExpression: - if ( - allowBitwiseExpressions && - ['|', '&', '^', '<<', '>>', '>>>'].includes(node.operator) - ) { + if (allowBitwiseExpressions) { return ( + ['|', '&', '^', '<<', '>>', '>>>'].includes(node.operator) && isAllowedInitializerExpressionRecursive(node.left, true) && isAllowedInitializerExpressionRecursive(node.right, true) ); From b65ae2b3eff80011fb2afa418fe75541d75c0ff8 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Mon, 23 Sep 2024 11:45:03 -0600 Subject: [PATCH 3/3] move comment --- packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts b/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts index 4bcaa3c348a2..8588aea54ff9 100644 --- a/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts +++ b/packages/eslint-plugin/src/rules/prefer-literal-enum-member.ts @@ -104,8 +104,8 @@ export default createRule({ case AST_NODE_TYPES.TemplateLiteral: return node.expressions.length === 0; - // +123, -123, etc. case AST_NODE_TYPES.UnaryExpression: + // +123, -123, etc. if (['+', '-'].includes(node.operator)) { return isAllowedInitializerExpressionRecursive( node.argument, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy