[d565449] | 1 | /**
|
---|
| 2 | * @fileoverview Rule to enforce declarations in program or function body root.
|
---|
| 3 | * @author Brandon Mills
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | "use strict";
|
---|
| 7 |
|
---|
| 8 | //------------------------------------------------------------------------------
|
---|
| 9 | // Requirements
|
---|
| 10 | //------------------------------------------------------------------------------
|
---|
| 11 |
|
---|
| 12 | const astUtils = require("./utils/ast-utils");
|
---|
| 13 |
|
---|
| 14 | //------------------------------------------------------------------------------
|
---|
| 15 | // Rule Definition
|
---|
| 16 | //------------------------------------------------------------------------------
|
---|
| 17 |
|
---|
| 18 | const validParent = new Set(["Program", "StaticBlock", "ExportNamedDeclaration", "ExportDefaultDeclaration"]);
|
---|
| 19 | const validBlockStatementParent = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
|
---|
| 20 |
|
---|
| 21 | /**
|
---|
| 22 | * Finds the nearest enclosing context where this rule allows declarations and returns its description.
|
---|
| 23 | * @param {ASTNode} node Node to search from.
|
---|
| 24 | * @returns {string} Description. One of "program", "function body", "class static block body".
|
---|
| 25 | */
|
---|
| 26 | function getAllowedBodyDescription(node) {
|
---|
| 27 | let { parent } = node;
|
---|
| 28 |
|
---|
| 29 | while (parent) {
|
---|
| 30 |
|
---|
| 31 | if (parent.type === "StaticBlock") {
|
---|
| 32 | return "class static block body";
|
---|
| 33 | }
|
---|
| 34 |
|
---|
| 35 | if (astUtils.isFunction(parent)) {
|
---|
| 36 | return "function body";
|
---|
| 37 | }
|
---|
| 38 |
|
---|
| 39 | ({ parent } = parent);
|
---|
| 40 | }
|
---|
| 41 |
|
---|
| 42 | return "program";
|
---|
| 43 | }
|
---|
| 44 |
|
---|
| 45 | /** @type {import('../shared/types').Rule} */
|
---|
| 46 | module.exports = {
|
---|
| 47 | meta: {
|
---|
| 48 | type: "problem",
|
---|
| 49 |
|
---|
| 50 | docs: {
|
---|
| 51 | description: "Disallow variable or `function` declarations in nested blocks",
|
---|
| 52 | recommended: true,
|
---|
| 53 | url: "https://eslint.org/docs/latest/rules/no-inner-declarations"
|
---|
| 54 | },
|
---|
| 55 |
|
---|
| 56 | schema: [
|
---|
| 57 | {
|
---|
| 58 | enum: ["functions", "both"]
|
---|
| 59 | }
|
---|
| 60 | ],
|
---|
| 61 |
|
---|
| 62 | messages: {
|
---|
| 63 | moveDeclToRoot: "Move {{type}} declaration to {{body}} root."
|
---|
| 64 | }
|
---|
| 65 | },
|
---|
| 66 |
|
---|
| 67 | create(context) {
|
---|
| 68 |
|
---|
| 69 | /**
|
---|
| 70 | * Ensure that a given node is at a program or function body's root.
|
---|
| 71 | * @param {ASTNode} node Declaration node to check.
|
---|
| 72 | * @returns {void}
|
---|
| 73 | */
|
---|
| 74 | function check(node) {
|
---|
| 75 | const parent = node.parent;
|
---|
| 76 |
|
---|
| 77 | if (
|
---|
| 78 | parent.type === "BlockStatement" && validBlockStatementParent.has(parent.parent.type)
|
---|
| 79 | ) {
|
---|
| 80 | return;
|
---|
| 81 | }
|
---|
| 82 |
|
---|
| 83 | if (validParent.has(parent.type)) {
|
---|
| 84 | return;
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 | context.report({
|
---|
| 88 | node,
|
---|
| 89 | messageId: "moveDeclToRoot",
|
---|
| 90 | data: {
|
---|
| 91 | type: (node.type === "FunctionDeclaration" ? "function" : "variable"),
|
---|
| 92 | body: getAllowedBodyDescription(node)
|
---|
| 93 | }
|
---|
| 94 | });
|
---|
| 95 | }
|
---|
| 96 |
|
---|
| 97 |
|
---|
| 98 | return {
|
---|
| 99 |
|
---|
| 100 | FunctionDeclaration: check,
|
---|
| 101 | VariableDeclaration(node) {
|
---|
| 102 | if (context.options[0] === "both" && node.kind === "var") {
|
---|
| 103 | check(node);
|
---|
| 104 | }
|
---|
| 105 | }
|
---|
| 106 |
|
---|
| 107 | };
|
---|
| 108 |
|
---|
| 109 | }
|
---|
| 110 | };
|
---|