]>
Commit | Line | Data |
---|---|---|
eb39fafa DC |
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 | // Rule Definition | |
10 | //------------------------------------------------------------------------------ | |
11 | ||
12 | module.exports = { | |
13 | meta: { | |
14 | type: "problem", | |
15 | ||
16 | docs: { | |
17 | description: "disallow variable or `function` declarations in nested blocks", | |
18 | category: "Possible Errors", | |
19 | recommended: true, | |
20 | url: "https://eslint.org/docs/rules/no-inner-declarations" | |
21 | }, | |
22 | ||
23 | schema: [ | |
24 | { | |
25 | enum: ["functions", "both"] | |
26 | } | |
27 | ], | |
28 | ||
29 | messages: { | |
30 | moveDeclToRoot: "Move {{type}} declaration to {{body}} root." | |
31 | } | |
32 | }, | |
33 | ||
34 | create(context) { | |
35 | ||
36 | /** | |
37 | * Find the nearest Program or Function ancestor node. | |
38 | * @returns {Object} Ancestor's type and distance from node. | |
39 | */ | |
40 | function nearestBody() { | |
41 | const ancestors = context.getAncestors(); | |
42 | let ancestor = ancestors.pop(), | |
43 | generation = 1; | |
44 | ||
45 | while (ancestor && ["Program", "FunctionDeclaration", | |
46 | "FunctionExpression", "ArrowFunctionExpression" | |
47 | ].indexOf(ancestor.type) < 0) { | |
48 | generation += 1; | |
49 | ancestor = ancestors.pop(); | |
50 | } | |
51 | ||
52 | return { | |
53 | ||
54 | // Type of containing ancestor | |
55 | type: ancestor.type, | |
56 | ||
57 | // Separation between ancestor and node | |
58 | distance: generation | |
59 | }; | |
60 | } | |
61 | ||
62 | /** | |
63 | * Ensure that a given node is at a program or function body's root. | |
64 | * @param {ASTNode} node Declaration node to check. | |
65 | * @returns {void} | |
66 | */ | |
67 | function check(node) { | |
68 | const body = nearestBody(), | |
69 | valid = ((body.type === "Program" && body.distance === 1) || | |
70 | body.distance === 2); | |
71 | ||
72 | if (!valid) { | |
73 | context.report({ | |
74 | node, | |
75 | messageId: "moveDeclToRoot", | |
76 | data: { | |
77 | type: (node.type === "FunctionDeclaration" ? "function" : "variable"), | |
78 | body: (body.type === "Program" ? "program" : "function body") | |
79 | } | |
80 | }); | |
81 | } | |
82 | } | |
83 | ||
84 | return { | |
85 | ||
86 | FunctionDeclaration: check, | |
87 | VariableDeclaration(node) { | |
88 | if (context.options[0] === "both" && node.kind === "var") { | |
89 | check(node); | |
90 | } | |
91 | } | |
92 | ||
93 | }; | |
94 | ||
95 | } | |
96 | }; |