Skip to content

⬅️ Back to Table of Contents

📄 no-duplicate-enum-values

📊 Analysis Summary

Metric Count
🔧 Functions 6
📦 Imports 3

📚 Table of Contents

🛠️ File Location:

📂 packages/eslint-plugin/src/rules/no-duplicate-enum-values.ts

📤 Default Export

export default createRule({ ... })
Property Value
name 'no-duplicate-enum-values'
meta.type 'problem'
meta.docs.description 'Disallow duplicate enum member values'
meta.docs.recommended 'recommended'
meta.hasSuggestions false
meta.messages.duplicateValue 'Duplicate enum member value {{value}}.'
meta.schema []
defaultOptions []

Entry point: create — documented under Functions.


📦 Imports

Name Source
TSESTree @typescript-eslint/utils
AST_NODE_TYPES @typescript-eslint/utils
createRule ../util

Functions

create(context: any): { TSEnumDeclaration(node: TSESTree.TSEnumDeclaration): void…

Parameters:

  • context any

Returns: { TSEnumDeclaration(node: TSESTree.TSEnumDeclaration): void; }

Calls:

  • ['-', '+'].includes
  • isStringLiteral
  • isNumberLiteral
  • isSupportedUnary
  • Number
  • getMemberValue
  • Number.isNaN
  • isStaticTemplateLiteral
  • enumMembers.forEach
  • seenValues.some
  • Object.is
  • context.report
  • seenValues.push
Code
create(context) {
    function isStringLiteral(
      node: TSESTree.Expression,
    ): node is TSESTree.StringLiteral {
      return (
        node.type === AST_NODE_TYPES.Literal && typeof node.value === 'string'
      );
    }

    function isNumberLiteral(
      node: TSESTree.Expression,
    ): node is TSESTree.NumberLiteral {
      return (
        node.type === AST_NODE_TYPES.Literal && typeof node.value === 'number'
      );
    }

    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 {
      return (
        node.type === AST_NODE_TYPES.TemplateLiteral &&
        node.expressions.length === 0 &&
        node.quasis.length === 1
      );
    }

    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 ?? undefined;
        default:
          return undefined;
      }
    }

    return {
      TSEnumDeclaration(node: TSESTree.TSEnumDeclaration): void {
        const enumMembers = node.body.members;
        const seenValues: (number | string)[] = [];

        enumMembers.forEach(member => {
          if (member.initializer == null) {
            return;
          }

          const value = getMemberValue(member.initializer);
          if (value == null) {
            return;
          }

          const isAlreadyPresent = seenValues.some(seenValue =>
            Object.is(seenValue, value),
          );
          if (isAlreadyPresent) {
            context.report({
              node: member,
              messageId: 'duplicateValue',
              data: {
                value,
              },
            });
          } else {
            seenValues.push(value);
          }
        });
      },
    };
  }

Internal helpers

Declared inside another function in this file.

isStringLiteral(node: TSESTree.Expression): node is TSESTree.StringLiteral

Parameters:

  • node TSESTree.Expression

Returns: node is TSESTree.StringLiteral

Code
function isStringLiteral(
      node: TSESTree.Expression,
    ): node is TSESTree.StringLiteral {
      return (
        node.type === AST_NODE_TYPES.Literal && typeof node.value === 'string'
      );
    }

isNumberLiteral(node: TSESTree.Expression): node is TSESTree.NumberLiteral

Parameters:

  • node TSESTree.Expression

Returns: node is TSESTree.NumberLiteral

Code
function isNumberLiteral(
      node: TSESTree.Expression,
    ): node is TSESTree.NumberLiteral {
      return (
        node.type === AST_NODE_TYPES.Literal && typeof node.value === 'number'
      );
    }

isSupportedUnary(node: TSESTree.Expression): node is TSESTree.UnaryExpression

Parameters:

  • node TSESTree.Expression

Returns: node is TSESTree.UnaryExpression

Calls:

  • ['-', '+'].includes
Code
function isSupportedUnary(
      node: TSESTree.Expression,
    ): node is TSESTree.UnaryExpression {
      return (
        node.type === AST_NODE_TYPES.UnaryExpression &&
        ['-', '+'].includes(node.operator)
      );
    }

isStaticTemplateLiteral(node: TSESTree.Expression): node is TSESTree.TemplateLiteral

Parameters:

  • node TSESTree.Expression

Returns: node is TSESTree.TemplateLiteral

Code
function isStaticTemplateLiteral(
      node: TSESTree.Expression,
    ): node is TSESTree.TemplateLiteral {
      return (
        node.type === AST_NODE_TYPES.TemplateLiteral &&
        node.expressions.length === 0 &&
        node.quasis.length === 1
      );
    }

getMemberValue(initializer: TSESTree.Expression): number | string | undefined

Parameters:

  • initializer TSESTree.Expression

Returns: number | string | undefined

Calls:

  • isStringLiteral
  • isNumberLiteral
  • isSupportedUnary
  • Number
  • getMemberValue
  • Number.isNaN
  • isStaticTemplateLiteral
Code
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 ?? undefined;
        default:
          return undefined;
      }
    }

Generated by Syntax Scribe