| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 | /** * @fileoverview Rule to warn when a function expression does not have a name. * @author Kyle T. Nunery */"use strict";//------------------------------------------------------------------------------// Requirements//------------------------------------------------------------------------------const astUtils = require("../ast-utils");/** * Checks whether or not a given variable is a function name. * @param {eslint-scope.Variable} variable - A variable to check. * @returns {boolean} `true` if the variable is a function name. */function isFunctionName(variable) {    return variable && variable.defs[0].type === "FunctionName";}//------------------------------------------------------------------------------// Rule Definition//------------------------------------------------------------------------------module.exports = {    meta: {        docs: {            description: "require or disallow named `function` expressions",            category: "Stylistic Issues",            recommended: false,            url: "https://eslint.org/docs/rules/func-names"        },        schema: [            {                enum: ["always", "as-needed", "never"]            }        ]    },    create(context) {        const never = context.options[0] === "never";        const asNeeded = context.options[0] === "as-needed";        /**         * Determines whether the current FunctionExpression node is a get, set, or         * shorthand method in an object literal or a class.         * @param {ASTNode} node - A node to check.         * @returns {boolean} True if the node is a get, set, or shorthand method.         */        function isObjectOrClassMethod(node) {            const parent = node.parent;            return (parent.type === "MethodDefinition" || (                parent.type === "Property" && (                    parent.method ||                    parent.kind === "get" ||                    parent.kind === "set"                )            ));        }        /**         * Determines whether the current FunctionExpression node has a name that would be         * inferred from context in a conforming ES6 environment.         * @param {ASTNode} node - A node to check.         * @returns {boolean} True if the node would have a name assigned automatically.         */        function hasInferredName(node) {            const parent = node.parent;            return isObjectOrClassMethod(node) ||                (parent.type === "VariableDeclarator" && parent.id.type === "Identifier" && parent.init === node) ||                (parent.type === "Property" && parent.value === node) ||                (parent.type === "AssignmentExpression" && parent.left.type === "Identifier" && parent.right === node) ||                (parent.type === "ExportDefaultDeclaration" && parent.declaration === node) ||                (parent.type === "AssignmentPattern" && parent.right === node);        }        return {            "FunctionExpression:exit"(node) {                // Skip recursive functions.                const nameVar = context.getDeclaredVariables(node)[0];                if (isFunctionName(nameVar) && nameVar.references.length > 0) {                    return;                }                const hasName = Boolean(node.id && node.id.name);                const name = astUtils.getFunctionNameWithKind(node);                if (never) {                    if (hasName) {                        context.report({                            node,                            message: "Unexpected named {{name}}.",                            data: { name }                        });                    }                } else {                    if (!hasName && (asNeeded ? !hasInferredName(node) : !isObjectOrClassMethod(node))) {                        context.report({                            node,                            message: "Unexpected unnamed {{name}}.",                            data: { name }                        });                    }                }            }        };    }};
 |