111 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * @fileoverview Rule to enforce declarations in program or function body root.
 | 
						|
 * @author Brandon Mills
 | 
						|
 */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
// Requirements
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
 | 
						|
const astUtils = require("./utils/ast-utils");
 | 
						|
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
// Rule Definition
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
 | 
						|
const validParent = new Set(["Program", "StaticBlock", "ExportNamedDeclaration", "ExportDefaultDeclaration"]);
 | 
						|
const validBlockStatementParent = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
 | 
						|
 | 
						|
/**
 | 
						|
 * Finds the nearest enclosing context where this rule allows declarations and returns its description.
 | 
						|
 * @param {ASTNode} node Node to search from.
 | 
						|
 * @returns {string} Description. One of "program", "function body", "class static block body".
 | 
						|
 */
 | 
						|
function getAllowedBodyDescription(node) {
 | 
						|
    let { parent } = node;
 | 
						|
 | 
						|
    while (parent) {
 | 
						|
 | 
						|
        if (parent.type === "StaticBlock") {
 | 
						|
            return "class static block body";
 | 
						|
        }
 | 
						|
 | 
						|
        if (astUtils.isFunction(parent)) {
 | 
						|
            return "function body";
 | 
						|
        }
 | 
						|
 | 
						|
        ({ parent } = parent);
 | 
						|
    }
 | 
						|
 | 
						|
    return "program";
 | 
						|
}
 | 
						|
 | 
						|
/** @type {import('../shared/types').Rule} */
 | 
						|
module.exports = {
 | 
						|
    meta: {
 | 
						|
        type: "problem",
 | 
						|
 | 
						|
        docs: {
 | 
						|
            description: "Disallow variable or `function` declarations in nested blocks",
 | 
						|
            recommended: true,
 | 
						|
            url: "https://eslint.org/docs/latest/rules/no-inner-declarations"
 | 
						|
        },
 | 
						|
 | 
						|
        schema: [
 | 
						|
            {
 | 
						|
                enum: ["functions", "both"]
 | 
						|
            }
 | 
						|
        ],
 | 
						|
 | 
						|
        messages: {
 | 
						|
            moveDeclToRoot: "Move {{type}} declaration to {{body}} root."
 | 
						|
        }
 | 
						|
    },
 | 
						|
 | 
						|
    create(context) {
 | 
						|
 | 
						|
        /**
 | 
						|
         * Ensure that a given node is at a program or function body's root.
 | 
						|
         * @param {ASTNode} node Declaration node to check.
 | 
						|
         * @returns {void}
 | 
						|
         */
 | 
						|
        function check(node) {
 | 
						|
            const parent = node.parent;
 | 
						|
 | 
						|
            if (
 | 
						|
                parent.type === "BlockStatement" && validBlockStatementParent.has(parent.parent.type)
 | 
						|
            ) {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if (validParent.has(parent.type)) {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            context.report({
 | 
						|
                node,
 | 
						|
                messageId: "moveDeclToRoot",
 | 
						|
                data: {
 | 
						|
                    type: (node.type === "FunctionDeclaration" ? "function" : "variable"),
 | 
						|
                    body: getAllowedBodyDescription(node)
 | 
						|
                }
 | 
						|
            });
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        return {
 | 
						|
 | 
						|
            FunctionDeclaration: check,
 | 
						|
            VariableDeclaration(node) {
 | 
						|
                if (context.options[0] === "both" && node.kind === "var") {
 | 
						|
                    check(node);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
        };
 | 
						|
 | 
						|
    }
 | 
						|
};
 |