From 5c0f3874551b9f9fb7997f3e0059ce3cacfd5266 Mon Sep 17 00:00:00 2001 From: Evgeny Stepanovych Date: Mon, 27 Oct 2025 18:43:57 +0100 Subject: [PATCH 1/3] fix(eslint-plugin): [no-duplicate-enum-values] support explicitly signed numbers (#11722) --- .../rules/no-duplicate-enum-values.test.ts | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/no-duplicate-enum-values.test.ts b/packages/eslint-plugin/tests/rules/no-duplicate-enum-values.test.ts index a2e00872bd7c..d40a89701111 100644 --- a/packages/eslint-plugin/tests/rules/no-duplicate-enum-values.test.ts +++ b/packages/eslint-plugin/tests/rules/no-duplicate-enum-values.test.ts @@ -25,6 +25,54 @@ enum E { } `, ` +enum E { + A = -1, + B = -2, +} + `, + ` +enum E { + A = +1, + B = +2, +} + `, + ` +enum E { + A = +1, + B = -1, +} + `, + ` +enum E { + A = 1, + B = -1, +} + `, + ` +enum E { + A = -0, + B = +0, +} + `, + ` +enum E { + A = -0, + B = 0, +} + `, + ` +enum E { + A = 1, + B = '1', +} + `, + ` +enum E { + A = -1, + B = '-1', +} + `, + ` enum E { A = 'A', B = 'B', @@ -74,6 +122,42 @@ enum E { } `, ` +enum E { + A = NaN, + B = NaN, +} + `, + ` +enum E { + A = NaN, + B = -NaN, +} + `, + ` +enum E { + A = 'NaN', + B = NaN, +} + `, + ` +enum E { + A = -+-0, + B = +-+0, +} + `, + ` +enum E { + A = -'', + B = 0, +} + `, + ` +enum E { + A = Infinity, + B = Infinity, +} + `, + ` const A = 'A'; enum E { A = 'A', @@ -100,6 +184,166 @@ enum E { }, { code: ` +enum E { + A = -1, + B = -1, +} + `, + errors: [ + { + column: 3, + data: { value: -1 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` +enum E { + A = +1, + B = +1, +} + `, + errors: [ + { + column: 3, + data: { value: 1 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` +enum E { + A = +0, + B = 0, +} + `, + errors: [ + { + column: 3, + data: { value: 0 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` +enum E { + A = -0, + B = -0, +} + `, + errors: [ + { + column: 3, + data: { value: -0 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` +enum E { + A = +'0', + B = 0, +} + `, + errors: [ + { + column: 3, + data: { value: 0 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` +enum E { + A = 0x10, + B = 16, +} + `, + errors: [ + { + column: 3, + data: { value: 0x10 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` +enum E { + A = +'1e2', + B = 100, +} + `, + errors: [ + { + column: 3, + data: { value: 1e2 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` +enum E { + A = +'', + B = 0, +} + `, + errors: [ + { + column: 3, + data: { value: 0 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` +enum E { + A = -+1, + B = +-1, +} + `, + errors: [ + { + column: 3, + data: { value: -1 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` +enum E { + A = -\`0\`, + B = -0, +} + `, + errors: [ + { + column: 3, + data: { value: -0 }, + line: 4, + messageId: 'duplicateValue', + }, + ], + }, + { + code: ` enum E { A = 'A', B = 'A', From 7f34b9b4a9065820eedced045297248837ecf375 Mon Sep 17 00:00:00 2001 From: Evgeny Stepanovych Date: Mon, 27 Oct 2025 18:48:31 +0100 Subject: [PATCH 2/3] fix(eslint-plugin): [no-duplicate-enum-values] support explicitly signed numbers (#11722) --- .../src/rules/no-duplicate-enum-values.ts | 50 ++++++++++++++----- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-duplicate-enum-values.ts b/packages/eslint-plugin/src/rules/no-duplicate-enum-values.ts index c5a858dbdcaa..b9c6fe08d6e6 100644 --- a/packages/eslint-plugin/src/rules/no-duplicate-enum-values.ts +++ b/packages/eslint-plugin/src/rules/no-duplicate-enum-values.ts @@ -36,6 +36,15 @@ export default createRule({ ); } + function isSupportedUnary( + node: TSESTree.Expression, + ): node is TSESTree.UnaryExpression { + return ( + node.type === AST_NODE_TYPES.UnaryExpression && + ['-', '+'].includes(node.operator) + ); + } + function isStaticTemplateLiteral( node: TSESTree.Expression, ): node is TSESTree.TemplateLiteral { @@ -46,30 +55,47 @@ export default createRule({ ); } + function getMemberValue( + initializer: TSESTree.Expression, + ): number | string | undefined { + switch (true) { + case isStringLiteral(initializer): + case isNumberLiteral(initializer): + return initializer.value; + case isSupportedUnary(initializer): { + const inner = Number(getMemberValue(initializer.argument)); + if (Number.isNaN(inner)) { + return undefined; + } + + return initializer.operator === '-' ? -inner : inner; + } + case isStaticTemplateLiteral(initializer): + return initializer.quasis[0].value.cooked; + default: + return undefined; + } + } + return { TSEnumDeclaration(node: TSESTree.TSEnumDeclaration): void { const enumMembers = node.body.members; - const seenValues = new Set(); + const seenValues: (number | string)[] = []; enumMembers.forEach(member => { if (member.initializer == null) { return; } - let value: number | string | undefined; - if (isStringLiteral(member.initializer)) { - value = member.initializer.value; - } else if (isNumberLiteral(member.initializer)) { - value = member.initializer.value; - } else if (isStaticTemplateLiteral(member.initializer)) { - value = member.initializer.quasis[0].value.cooked; - } - + const value = getMemberValue(member.initializer); if (value == null) { return; } - if (seenValues.has(value)) { + const isAlreadyPresent = seenValues.some(seenValue => + Object.is(seenValue, value), + ); + if (isAlreadyPresent) { context.report({ node: member, messageId: 'duplicateValue', @@ -78,7 +104,7 @@ export default createRule({ }, }); } else { - seenValues.add(value); + seenValues.push(value); } }); }, From 874e88956a0bdef3c665d7e419d2d515426e49a7 Mon Sep 17 00:00:00 2001 From: Evgeny Stepanovych Date: Mon, 27 Oct 2025 19:03:54 +0100 Subject: [PATCH 3/3] fix(eslint-plugin): [no-duplicate-enum-values] support explicitly signed numbers (#11722) --- .../eslint-plugin/tests/rules/no-duplicate-enum-values.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/tests/rules/no-duplicate-enum-values.test.ts b/packages/eslint-plugin/tests/rules/no-duplicate-enum-values.test.ts index d40a89701111..81840e8cfcb8 100644 --- a/packages/eslint-plugin/tests/rules/no-duplicate-enum-values.test.ts +++ b/packages/eslint-plugin/tests/rules/no-duplicate-enum-values.test.ts @@ -53,7 +53,7 @@ enum E { A = -0, B = +0, } - `, + `, ` enum E { A = -0,