text: /**
   * @fileoverview Rule to flag use of duplicate keys in an object.
   * @author Ian Christian Myers
   */
  
  "use strict";
  
  //------------------------------------------------------------------------------
  // Requirements
  //------------------------------------------------------------------------------
  
  const astUtils = require("../ast-utils");
  
  //------------------------------------------------------------------------------
  // Helpers
  //------------------------------------------------------------------------------
  
  const GET_KIND = /^(?:init|get)$/;
  const SET_KIND = /^(?:init|set)$/;
  
  /**
   * The class which stores properties' information of an object.
   */
  class ObjectInfo {
  
      /**
       * @param {ObjectInfo|null} upper - The information of the outer object.
       * @param {ASTNode} node - The ObjectExpression node of this information.
       */
      constructor(upper, node) {
          this.upper = upper;
          this.node = node;
          this.properties = new Map();
      }
  
      /**
       * Gets the information of the given Property node.
       * @param {ASTNode} node - The Property node to get.
       * @returns {{get: boolean, set: boolean}} The information of the property.
       */
      getPropertyInfo(node) {
          const name = astUtils.getStaticPropertyName(node);
  
          if (!this.properties.has(name)) {
              this.properties.set(name, { get: false, set: false });
          }
          return this.properties.get(name);
      }
  
      /**
       * Checks whether the given property has been defined already or not.
       * @param {ASTNode} node - The Property node to check.
       * @returns {boolean} `true` if the property has been defined.
       */
      isPropertyDefined(node) {
          const entry = this.getPropertyInfo(node);
  
          return (
              (GET_KIND.test(node.kind) && entry.get) ||
              (SET_KIND.test(node.kind) && entry.set)
          );
      }
  
      /**
       * Defines the given property.
       * @param {ASTNode} node - The Property node to define.
       * @returns {void}
       */
      defineProperty(node) {
          const entry = this.getPropertyInfo(node);
  
          if (GET_KIND.test(node.kind)) {
              entry.get = true;
          }
          if (SET_KIND.test(node.kind)) {
              entry.set = true;
          }
      }
  }
  
  //------------------------------------------------------------------------------
  // Rule Definition
  //------------------------------------------------------------------------------
  
  module.exports = {
      meta: {
          docs: {
              description: "disallow duplicate keys in object literals",
              category: "Possible Errors",
              recommended: true,
              url: "https://eslint.org/docs/rules/no-dupe-keys"
          },
  
          schema: [],
  
          messages: {
              unexpected: "Duplicate key '{{name}}'."
          }
      },
  
      create(context) {
          let info = null;
  
          return {
              ObjectExpression(node) {
                  info = new ObjectInfo(info, node);
              },
              "ObjectExpression:exit"() {
                  info = info.upper;
              },
  
              Property(node) {
                  const name = astUtils.getStaticPropertyName(node);
  
                  // Skip destructuring.
                  if (node.parent.type !== "ObjectExpression") {
                      return;
                  }
  
                  // Skip if the name is not static.
                  if (!name) {
                      return;
                  }
  
                  // Reports if the name is defined already.
                  if (info.isPropertyDefined(node)) {
                      context.report({
                          node: info.node,
                          loc: node.key.loc,
                          messageId: "unexpected",
                          data: { name }
                      });
                  }
  
                  // Update info.
                  info.defineProperty(node);
              }
          };
      }
  };
  