You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
/** * @fileoverview Rule to flag use of duplicate keys in an object. * @author Ian Christian Myers */
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const GET_KIND = /^(?:init|get)$/u; const SET_KIND = /^(?:init|set)$/u;
/** * The class which stores properties' information of an object. */ class ObjectInfo {
// eslint-disable-next-line jsdoc/require-description
/** * @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: { type: "problem",
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 === null) { 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); } }; } };
|