/**
							 | 
						|
								 * @fileoverview Rule that warns when identifier names that are
							 | 
						|
								 * specified in the configuration are used.
							 | 
						|
								 * @author Keith Cirkel (http://keithcirkel.co.uk)
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								"use strict";
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Helpers
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Checks whether the given node represents assignment target in a normal assignment or destructuring.
							 | 
						|
								 * @param {ASTNode} node The node to check.
							 | 
						|
								 * @returns {boolean} `true` if the node is assignment target.
							 | 
						|
								 */
							 | 
						|
								function isAssignmentTarget(node) {
							 | 
						|
								    const parent = node.parent;
							 | 
						|
								
							 | 
						|
								    return (
							 | 
						|
								
							 | 
						|
								        // normal assignment
							 | 
						|
								        (
							 | 
						|
								            parent.type === "AssignmentExpression" &&
							 | 
						|
								            parent.left === node
							 | 
						|
								        ) ||
							 | 
						|
								
							 | 
						|
								        // destructuring
							 | 
						|
								        parent.type === "ArrayPattern" ||
							 | 
						|
								        parent.type === "RestElement" ||
							 | 
						|
								        (
							 | 
						|
								            parent.type === "Property" &&
							 | 
						|
								            parent.value === node &&
							 | 
						|
								            parent.parent.type === "ObjectPattern"
							 | 
						|
								        ) ||
							 | 
						|
								        (
							 | 
						|
								            parent.type === "AssignmentPattern" &&
							 | 
						|
								            parent.left === node
							 | 
						|
								        )
							 | 
						|
								    );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Checks whether the given node represents an imported name that is renamed in the same import/export specifier.
							 | 
						|
								 *
							 | 
						|
								 * Examples:
							 | 
						|
								 * import { a as b } from 'mod'; // node `a` is renamed import
							 | 
						|
								 * export { a as b } from 'mod'; // node `a` is renamed import
							 | 
						|
								 * @param {ASTNode} node `Identifier` node to check.
							 | 
						|
								 * @returns {boolean} `true` if the node is a renamed import.
							 | 
						|
								 */
							 | 
						|
								function isRenamedImport(node) {
							 | 
						|
								    const parent = node.parent;
							 | 
						|
								
							 | 
						|
								    return (
							 | 
						|
								        (
							 | 
						|
								            parent.type === "ImportSpecifier" &&
							 | 
						|
								            parent.imported !== parent.local &&
							 | 
						|
								            parent.imported === node
							 | 
						|
								        ) ||
							 | 
						|
								        (
							 | 
						|
								            parent.type === "ExportSpecifier" &&
							 | 
						|
								            parent.parent.source && // re-export
							 | 
						|
								            parent.local !== parent.exported &&
							 | 
						|
								            parent.local === node
							 | 
						|
								        )
							 | 
						|
								    );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Checks whether the given node is an ObjectPattern destructuring.
							 | 
						|
								 *
							 | 
						|
								 * Examples:
							 | 
						|
								 * const { a : b } = foo;
							 | 
						|
								 * @param {ASTNode} node `Identifier` node to check.
							 | 
						|
								 * @returns {boolean} `true` if the node is in an ObjectPattern destructuring.
							 | 
						|
								 */
							 | 
						|
								function isPropertyNameInDestructuring(node) {
							 | 
						|
								    const parent = node.parent;
							 | 
						|
								
							 | 
						|
								    return (
							 | 
						|
								        (
							 | 
						|
								            !parent.computed &&
							 | 
						|
								            parent.type === "Property" &&
							 | 
						|
								            parent.parent.type === "ObjectPattern" &&
							 | 
						|
								            parent.key === node
							 | 
						|
								        )
							 | 
						|
								    );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								// Rule Definition
							 | 
						|
								//------------------------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								/** @type {import('../shared/types').Rule} */
							 | 
						|
								module.exports = {
							 | 
						|
								    meta: {
							 | 
						|
								        type: "suggestion",
							 | 
						|
								
							 | 
						|
								        docs: {
							 | 
						|
								            description: "Disallow specified identifiers",
							 | 
						|
								            recommended: false,
							 | 
						|
								            url: "https://eslint.org/docs/latest/rules/id-denylist"
							 | 
						|
								        },
							 | 
						|
								
							 | 
						|
								        schema: {
							 | 
						|
								            type: "array",
							 | 
						|
								            items: {
							 | 
						|
								                type: "string"
							 | 
						|
								            },
							 | 
						|
								            uniqueItems: true
							 | 
						|
								        },
							 | 
						|
								        messages: {
							 | 
						|
								            restricted: "Identifier '{{name}}' is restricted.",
							 | 
						|
								            restrictedPrivate: "Identifier '#{{name}}' is restricted."
							 | 
						|
								        }
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    create(context) {
							 | 
						|
								
							 | 
						|
								        const denyList = new Set(context.options);
							 | 
						|
								        const reportedNodes = new Set();
							 | 
						|
								        const sourceCode = context.sourceCode;
							 | 
						|
								
							 | 
						|
								        let globalScope;
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Checks whether the given name is restricted.
							 | 
						|
								         * @param {string} name The name to check.
							 | 
						|
								         * @returns {boolean} `true` if the name is restricted.
							 | 
						|
								         * @private
							 | 
						|
								         */
							 | 
						|
								        function isRestricted(name) {
							 | 
						|
								            return denyList.has(name);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Checks whether the given node represents a reference to a global variable that is not declared in the source code.
							 | 
						|
								         * These identifiers will be allowed, as it is assumed that user has no control over the names of external global variables.
							 | 
						|
								         * @param {ASTNode} node `Identifier` node to check.
							 | 
						|
								         * @returns {boolean} `true` if the node is a reference to a global variable.
							 | 
						|
								         */
							 | 
						|
								        function isReferenceToGlobalVariable(node) {
							 | 
						|
								            const variable = globalScope.set.get(node.name);
							 | 
						|
								
							 | 
						|
								            return variable && variable.defs.length === 0 &&
							 | 
						|
								                variable.references.some(ref => ref.identifier === node);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Determines whether the given node should be checked.
							 | 
						|
								         * @param {ASTNode} node `Identifier` node.
							 | 
						|
								         * @returns {boolean} `true` if the node should be checked.
							 | 
						|
								         */
							 | 
						|
								        function shouldCheck(node) {
							 | 
						|
								            const parent = node.parent;
							 | 
						|
								
							 | 
						|
								            /*
							 | 
						|
								             * Member access has special rules for checking property names.
							 | 
						|
								             * Read access to a property with a restricted name is allowed, because it can be on an object that user has no control over.
							 | 
						|
								             * Write access isn't allowed, because it potentially creates a new property with a restricted name.
							 | 
						|
								             */
							 | 
						|
								            if (
							 | 
						|
								                parent.type === "MemberExpression" &&
							 | 
						|
								                parent.property === node &&
							 | 
						|
								                !parent.computed
							 | 
						|
								            ) {
							 | 
						|
								                return isAssignmentTarget(parent);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return (
							 | 
						|
								                parent.type !== "CallExpression" &&
							 | 
						|
								                parent.type !== "NewExpression" &&
							 | 
						|
								                !isRenamedImport(node) &&
							 | 
						|
								                !isPropertyNameInDestructuring(node) &&
							 | 
						|
								                !isReferenceToGlobalVariable(node)
							 | 
						|
								            );
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /**
							 | 
						|
								         * Reports an AST node as a rule violation.
							 | 
						|
								         * @param {ASTNode} node The node to report.
							 | 
						|
								         * @returns {void}
							 | 
						|
								         * @private
							 | 
						|
								         */
							 | 
						|
								        function report(node) {
							 | 
						|
								
							 | 
						|
								            /*
							 | 
						|
								             * We used the range instead of the node because it's possible
							 | 
						|
								             * for the same identifier to be represented by two different
							 | 
						|
								             * nodes, with the most clear example being shorthand properties:
							 | 
						|
								             * { foo }
							 | 
						|
								             * In this case, "foo" is represented by one node for the name
							 | 
						|
								             * and one for the value. The only way to know they are the same
							 | 
						|
								             * is to look at the range.
							 | 
						|
								             */
							 | 
						|
								            if (!reportedNodes.has(node.range.toString())) {
							 | 
						|
								                const isPrivate = node.type === "PrivateIdentifier";
							 | 
						|
								
							 | 
						|
								                context.report({
							 | 
						|
								                    node,
							 | 
						|
								                    messageId: isPrivate ? "restrictedPrivate" : "restricted",
							 | 
						|
								                    data: {
							 | 
						|
								                        name: node.name
							 | 
						|
								                    }
							 | 
						|
								                });
							 | 
						|
								                reportedNodes.add(node.range.toString());
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return {
							 | 
						|
								
							 | 
						|
								            Program(node) {
							 | 
						|
								                globalScope = sourceCode.getScope(node);
							 | 
						|
								            },
							 | 
						|
								
							 | 
						|
								            [[
							 | 
						|
								                "Identifier",
							 | 
						|
								                "PrivateIdentifier"
							 | 
						|
								            ]](node) {
							 | 
						|
								                if (isRestricted(node.name) && shouldCheck(node)) {
							 | 
						|
								                    report(node);
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        };
							 | 
						|
								    }
							 | 
						|
								};
							 |