|                                                                                                                                                                                                                                                                                                                                                                                     |  | /** * @fileoverview Rule to forbid or enforce dangling commas. * @author Ian Christian Myers * @deprecated in ESLint v8.53.0 */
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const DEFAULT_OPTIONS = Object.freeze({    arrays: "never",    objects: "never",    imports: "never",    exports: "never",    functions: "never"});
/** * Checks whether or not a trailing comma is allowed in a given node. * If the `lastItem` is `RestElement` or `RestProperty`, it disallows trailing commas. * @param {ASTNode} lastItem The node of the last element in the given node. * @returns {boolean} `true` if a trailing comma is allowed. */function isTrailingCommaAllowed(lastItem) {    return !(        lastItem.type === "RestElement" ||        lastItem.type === "RestProperty" ||        lastItem.type === "ExperimentalRestProperty"    );}
/** * Normalize option value. * @param {string|Object|undefined} optionValue The 1st option value to normalize. * @param {number} ecmaVersion The normalized ECMAScript version. * @returns {Object} The normalized option value. */function normalizeOptions(optionValue, ecmaVersion) {    if (typeof optionValue === "string") {        return {            arrays: optionValue,            objects: optionValue,            imports: optionValue,            exports: optionValue,            functions: ecmaVersion < 2017 ? "ignore" : optionValue        };    }    if (typeof optionValue === "object" && optionValue !== null) {        return {            arrays: optionValue.arrays || DEFAULT_OPTIONS.arrays,            objects: optionValue.objects || DEFAULT_OPTIONS.objects,            imports: optionValue.imports || DEFAULT_OPTIONS.imports,            exports: optionValue.exports || DEFAULT_OPTIONS.exports,            functions: optionValue.functions || DEFAULT_OPTIONS.functions        };    }
    return DEFAULT_OPTIONS;}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../shared/types').Rule} */module.exports = {    meta: {        deprecated: true,        replacedBy: [],        type: "layout",
        docs: {            description: "Require or disallow trailing commas",            recommended: false,            url: "https://eslint.org/docs/latest/rules/comma-dangle"        },
        fixable: "code",
        schema: {            definitions: {                value: {                    enum: [                        "always-multiline",                        "always",                        "never",                        "only-multiline"                    ]                },                valueWithIgnore: {                    enum: [                        "always-multiline",                        "always",                        "ignore",                        "never",                        "only-multiline"                    ]                }            },            type: "array",            items: [                {                    oneOf: [                        {                            $ref: "#/definitions/value"                        },                        {                            type: "object",                            properties: {                                arrays: { $ref: "#/definitions/valueWithIgnore" },                                objects: { $ref: "#/definitions/valueWithIgnore" },                                imports: { $ref: "#/definitions/valueWithIgnore" },                                exports: { $ref: "#/definitions/valueWithIgnore" },                                functions: { $ref: "#/definitions/valueWithIgnore" }                            },                            additionalProperties: false                        }                    ]                }            ],            additionalItems: false        },
        messages: {            unexpected: "Unexpected trailing comma.",            missing: "Missing trailing comma."        }    },
    create(context) {        const options = normalizeOptions(context.options[0], context.languageOptions.ecmaVersion);
        const sourceCode = context.sourceCode;
        /**         * Gets the last item of the given node.         * @param {ASTNode} node The node to get.         * @returns {ASTNode|null} The last node or null.         */        function getLastItem(node) {
            /**             * Returns the last element of an array             * @param {any[]} array The input array             * @returns {any} The last element             */            function last(array) {                return array[array.length - 1];            }
            switch (node.type) {                case "ObjectExpression":                case "ObjectPattern":                    return last(node.properties);                case "ArrayExpression":                case "ArrayPattern":                    return last(node.elements);                case "ImportDeclaration":                case "ExportNamedDeclaration":                    return last(node.specifiers);                case "FunctionDeclaration":                case "FunctionExpression":                case "ArrowFunctionExpression":                    return last(node.params);                case "CallExpression":                case "NewExpression":                    return last(node.arguments);                default:                    return null;            }        }
        /**         * Gets the trailing comma token of the given node.         * If the trailing comma does not exist, this returns the token which is         * the insertion point of the trailing comma token.         * @param {ASTNode} node The node to get.         * @param {ASTNode} lastItem The last item of the node.         * @returns {Token} The trailing comma token or the insertion point.         */        function getTrailingToken(node, lastItem) {            switch (node.type) {                case "ObjectExpression":                case "ArrayExpression":                case "CallExpression":                case "NewExpression":                    return sourceCode.getLastToken(node, 1);                default: {                    const nextToken = sourceCode.getTokenAfter(lastItem);
                    if (astUtils.isCommaToken(nextToken)) {                        return nextToken;                    }                    return sourceCode.getLastToken(lastItem);                }            }        }
        /**         * Checks whether or not a given node is multiline.         * This rule handles a given node as multiline when the closing parenthesis         * and the last element are not on the same line.         * @param {ASTNode} node A node to check.         * @returns {boolean} `true` if the node is multiline.         */        function isMultiline(node) {            const lastItem = getLastItem(node);
            if (!lastItem) {                return false;            }
            const penultimateToken = getTrailingToken(node, lastItem);            const lastToken = sourceCode.getTokenAfter(penultimateToken);
            return lastToken.loc.end.line !== penultimateToken.loc.end.line;        }
        /**         * Reports a trailing comma if it exists.         * @param {ASTNode} node A node to check. Its type is one of         *   ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,         *   ImportDeclaration, and ExportNamedDeclaration.         * @returns {void}         */        function forbidTrailingComma(node) {            const lastItem = getLastItem(node);
            if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) {                return;            }
            const trailingToken = getTrailingToken(node, lastItem);
            if (astUtils.isCommaToken(trailingToken)) {                context.report({                    node: lastItem,                    loc: trailingToken.loc,                    messageId: "unexpected",                    *fix(fixer) {                        yield fixer.remove(trailingToken);
                        /*                         * Extend the range of the fix to include surrounding tokens to ensure                         * that the element after which the comma is removed stays _last_.                         * This intentionally makes conflicts in fix ranges with rules that may be                         * adding or removing elements in the same autofix pass.                         * https://github.com/eslint/eslint/issues/15660
                         */                        yield fixer.insertTextBefore(sourceCode.getTokenBefore(trailingToken), "");                        yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");                    }                });            }        }
        /**         * Reports the last element of a given node if it does not have a trailing         * comma.         *         * If a given node is `ArrayPattern` which has `RestElement`, the trailing         * comma is disallowed, so report if it exists.         * @param {ASTNode} node A node to check. Its type is one of         *   ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,         *   ImportDeclaration, and ExportNamedDeclaration.         * @returns {void}         */        function forceTrailingComma(node) {            const lastItem = getLastItem(node);
            if (!lastItem || (node.type === "ImportDeclaration" && lastItem.type !== "ImportSpecifier")) {                return;            }            if (!isTrailingCommaAllowed(lastItem)) {                forbidTrailingComma(node);                return;            }
            const trailingToken = getTrailingToken(node, lastItem);
            if (trailingToken.value !== ",") {                context.report({                    node: lastItem,                    loc: {                        start: trailingToken.loc.end,                        end: astUtils.getNextLocation(sourceCode, trailingToken.loc.end)                    },                    messageId: "missing",                    *fix(fixer) {                        yield fixer.insertTextAfter(trailingToken, ",");
                        /*                         * Extend the range of the fix to include surrounding tokens to ensure                         * that the element after which the comma is inserted stays _last_.                         * This intentionally makes conflicts in fix ranges with rules that may be                         * adding or removing elements in the same autofix pass.                         * https://github.com/eslint/eslint/issues/15660
                         */                        yield fixer.insertTextBefore(trailingToken, "");                        yield fixer.insertTextAfter(sourceCode.getTokenAfter(trailingToken), "");                    }                });            }        }
        /**         * If a given node is multiline, reports the last element of a given node         * when it does not have a trailing comma.         * Otherwise, reports a trailing comma if it exists.         * @param {ASTNode} node A node to check. Its type is one of         *   ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,         *   ImportDeclaration, and ExportNamedDeclaration.         * @returns {void}         */        function forceTrailingCommaIfMultiline(node) {            if (isMultiline(node)) {                forceTrailingComma(node);            } else {                forbidTrailingComma(node);            }        }
        /**         * Only if a given node is not multiline, reports the last element of a given node         * when it does not have a trailing comma.         * Otherwise, reports a trailing comma if it exists.         * @param {ASTNode} node A node to check. Its type is one of         *   ObjectExpression, ObjectPattern, ArrayExpression, ArrayPattern,         *   ImportDeclaration, and ExportNamedDeclaration.         * @returns {void}         */        function allowTrailingCommaIfMultiline(node) {            if (!isMultiline(node)) {                forbidTrailingComma(node);            }        }
        const predicate = {            always: forceTrailingComma,            "always-multiline": forceTrailingCommaIfMultiline,            "only-multiline": allowTrailingCommaIfMultiline,            never: forbidTrailingComma,            ignore() {}        };
        return {            ObjectExpression: predicate[options.objects],            ObjectPattern: predicate[options.objects],
            ArrayExpression: predicate[options.arrays],            ArrayPattern: predicate[options.arrays],
            ImportDeclaration: predicate[options.imports],
            ExportNamedDeclaration: predicate[options.exports],
            FunctionDeclaration: predicate[options.functions],            FunctionExpression: predicate[options.functions],            ArrowFunctionExpression: predicate[options.functions],            CallExpression: predicate[options.functions],            NewExpression: predicate[options.functions]        };    }};
 |