| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 | /** * @fileoverview Counts the cyclomatic complexity of each function of the script. See http://en.wikipedia.org/wiki/Cyclomatic_complexity. * Counts the number of if, conditional, for, while, try, switch/case, * @author Patrick Brosset */"use strict";//------------------------------------------------------------------------------// Requirements//------------------------------------------------------------------------------const astUtils = require("./utils/ast-utils");const { upperCaseFirst } = require("../shared/string-utils");//------------------------------------------------------------------------------// Rule Definition//------------------------------------------------------------------------------/** @type {import('../shared/types').Rule} */module.exports = {    meta: {        type: "suggestion",        docs: {            description: "Enforce a maximum cyclomatic complexity allowed in a program",            recommended: false,            url: "https://eslint.org/docs/rules/complexity"        },        schema: [            {                oneOf: [                    {                        type: "integer",                        minimum: 0                    },                    {                        type: "object",                        properties: {                            maximum: {                                type: "integer",                                minimum: 0                            },                            max: {                                type: "integer",                                minimum: 0                            }                        },                        additionalProperties: false                    }                ]            }        ],        messages: {            complex: "{{name}} has a complexity of {{complexity}}. Maximum allowed is {{max}}."        }    },    create(context) {        const option = context.options[0];        let THRESHOLD = 20;        if (            typeof option === "object" &&            (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))        ) {            THRESHOLD = option.maximum || option.max;        } else if (typeof option === "number") {            THRESHOLD = option;        }        //--------------------------------------------------------------------------        // Helpers        //--------------------------------------------------------------------------        // Using a stack to store complexity per code path        const complexities = [];        /**         * Increase the complexity of the code path in context         * @returns {void}         * @private         */        function increaseComplexity() {            complexities[complexities.length - 1]++;        }        //--------------------------------------------------------------------------        // Public API        //--------------------------------------------------------------------------        return {            onCodePathStart() {                // The initial complexity is 1, representing one execution path in the CodePath                complexities.push(1);            },            // Each branching in the code adds 1 to the complexity            CatchClause: increaseComplexity,            ConditionalExpression: increaseComplexity,            LogicalExpression: increaseComplexity,            ForStatement: increaseComplexity,            ForInStatement: increaseComplexity,            ForOfStatement: increaseComplexity,            IfStatement: increaseComplexity,            WhileStatement: increaseComplexity,            DoWhileStatement: increaseComplexity,            // Avoid `default`            "SwitchCase[test]": increaseComplexity,            // Logical assignment operators have short-circuiting behavior            AssignmentExpression(node) {                if (astUtils.isLogicalAssignmentOperator(node.operator)) {                    increaseComplexity();                }            },            onCodePathEnd(codePath, node) {                const complexity = complexities.pop();                /*                 * This rule only evaluates complexity of functions, so "program" is excluded.                 * Class field initializers and class static blocks are implicit functions. Therefore,                 * they shouldn't contribute to the enclosing function's complexity, but their                 * own complexity should be evaluated.                 */                if (                    codePath.origin !== "function" &&                    codePath.origin !== "class-field-initializer" &&                    codePath.origin !== "class-static-block"                ) {                    return;                }                if (complexity > THRESHOLD) {                    let name;                    if (codePath.origin === "class-field-initializer") {                        name = "class field initializer";                    } else if (codePath.origin === "class-static-block") {                        name = "class static block";                    } else {                        name = astUtils.getFunctionNameWithKind(node);                    }                    context.report({                        node,                        messageId: "complex",                        data: {                            name: upperCaseFirst(name),                            complexity,                            max: THRESHOLD                        }                    });                }            }        };    }};
 |