CoolFace
Apppublic

Umama-at-Bluchip/Quick-UI

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
max-lines-per-function.js214 linesDownload Raw Back to rules
1/**2 * @fileoverview A rule to set the maximum number of line of code in a function.3 * @author Pete Ward <peteward44@gmail.com>4 */5"use strict";6 7//------------------------------------------------------------------------------8// Requirements9//------------------------------------------------------------------------------10 11const astUtils = require("./utils/ast-utils");12const { upperCaseFirst } = require("../shared/string-utils");13 14//------------------------------------------------------------------------------15// Constants16//------------------------------------------------------------------------------17 18const OPTIONS_SCHEMA = {19    type: "object",20    properties: {21        max: {22            type: "integer",23            minimum: 024        },25        skipComments: {26            type: "boolean"27        },28        skipBlankLines: {29            type: "boolean"30        },31        IIFEs: {32            type: "boolean"33        }34    },35    additionalProperties: false36};37 38const OPTIONS_OR_INTEGER_SCHEMA = {39    oneOf: [40        OPTIONS_SCHEMA,41        {42            type: "integer",43            minimum: 144        }45    ]46};47 48/**49 * Given a list of comment nodes, return a map with numeric keys (source code line numbers) and comment token values.50 * @param {Array} comments An array of comment nodes.51 * @returns {Map<string, Node>} A map with numeric keys (source code line numbers) and comment token values.52 */53function getCommentLineNumbers(comments) {54    const map = new Map();55 56    comments.forEach(comment => {57        for (let i = comment.loc.start.line; i <= comment.loc.end.line; i++) {58            map.set(i, comment);59        }60    });61    return map;62}63 64//------------------------------------------------------------------------------65// Rule Definition66//------------------------------------------------------------------------------67 68/** @type {import('../shared/types').Rule} */69module.exports = {70    meta: {71        type: "suggestion",72 73        docs: {74            description: "Enforce a maximum number of lines of code in a function",75            recommended: false,76            url: "https://eslint.org/docs/latest/rules/max-lines-per-function"77        },78 79        schema: [80            OPTIONS_OR_INTEGER_SCHEMA81        ],82        messages: {83            exceed: "{{name}} has too many lines ({{lineCount}}). Maximum allowed is {{maxLines}}."84        }85    },86 87    create(context) {88        const sourceCode = context.sourceCode;89        const lines = sourceCode.lines;90 91        const option = context.options[0];92        let maxLines = 50;93        let skipComments = false;94        let skipBlankLines = false;95        let IIFEs = false;96 97        if (typeof option === "object") {98            maxLines = typeof option.max === "number" ? option.max : 50;99            skipComments = !!option.skipComments;100            skipBlankLines = !!option.skipBlankLines;101            IIFEs = !!option.IIFEs;102        } else if (typeof option === "number") {103            maxLines = option;104        }105 106        const commentLineNumbers = getCommentLineNumbers(sourceCode.getAllComments());107 108        //--------------------------------------------------------------------------109        // Helpers110        //--------------------------------------------------------------------------111 112        /**113         * Tells if a comment encompasses the entire line.114         * @param {string} line The source line with a trailing comment115         * @param {number} lineNumber The one-indexed line number this is on116         * @param {ASTNode} comment The comment to remove117         * @returns {boolean} If the comment covers the entire line118         */119        function isFullLineComment(line, lineNumber, comment) {120            const start = comment.loc.start,121                end = comment.loc.end,122                isFirstTokenOnLine = start.line === lineNumber && !line.slice(0, start.column).trim(),123                isLastTokenOnLine = end.line === lineNumber && !line.slice(end.column).trim();124 125            return comment &&126                (start.line < lineNumber || isFirstTokenOnLine) &&127                (end.line > lineNumber || isLastTokenOnLine);128        }129 130        /**131         * Identifies is a node is a FunctionExpression which is part of an IIFE132         * @param {ASTNode} node Node to test133         * @returns {boolean} True if it's an IIFE134         */135        function isIIFE(node) {136            return (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") && node.parent && node.parent.type === "CallExpression" && node.parent.callee === node;137        }138 139        /**140         * Identifies is a node is a FunctionExpression which is embedded within a MethodDefinition or Property141         * @param {ASTNode} node Node to test142         * @returns {boolean} True if it's a FunctionExpression embedded within a MethodDefinition or Property143         */144        function isEmbedded(node) {145            if (!node.parent) {146                return false;147            }148            if (node !== node.parent.value) {149                return false;150            }151            if (node.parent.type === "MethodDefinition") {152                return true;153            }154            if (node.parent.type === "Property") {155                return node.parent.method === true || node.parent.kind === "get" || node.parent.kind === "set";156            }157            return false;158        }159 160        /**161         * Count the lines in the function162         * @param {ASTNode} funcNode Function AST node163         * @returns {void}164         * @private165         */166        function processFunction(funcNode) {167            const node = isEmbedded(funcNode) ? funcNode.parent : funcNode;168 169            if (!IIFEs && isIIFE(node)) {170                return;171            }172            let lineCount = 0;173 174            for (let i = node.loc.start.line - 1; i < node.loc.end.line; ++i) {175                const line = lines[i];176 177                if (skipComments) {178                    if (commentLineNumbers.has(i + 1) && isFullLineComment(line, i + 1, commentLineNumbers.get(i + 1))) {179                        continue;180                    }181                }182 183                if (skipBlankLines) {184                    if (line.match(/^\s*$/u)) {185                        continue;186                    }187                }188 189                lineCount++;190            }191 192            if (lineCount > maxLines) {193                const name = upperCaseFirst(astUtils.getFunctionNameWithKind(funcNode));194 195                context.report({196                    node,197                    messageId: "exceed",198                    data: { name, lineCount, maxLines }199                });200            }201        }202 203        //--------------------------------------------------------------------------204        // Public API205        //--------------------------------------------------------------------------206 207        return {208            FunctionDeclaration: processFunction,209            FunctionExpression: processFunction,210            ArrowFunctionExpression: processFunction211        };212    }213};214