1 | /**
|
2 | * @fileoverview Rule to enforce declarations in program or function body root.
|
3 | * @author Brandon Mills
|
4 | * @copyright 2014 Brandon Mills. All rights reserved.
|
5 | */
|
6 |
|
7 | ;
|
8 |
|
9 | //------------------------------------------------------------------------------
|
10 | // Rule Definition
|
11 | //------------------------------------------------------------------------------
|
12 |
|
13 | module.exports = function(context) {
|
14 |
|
15 | /**
|
16 | * Find the nearest Program or Function ancestor node.
|
17 | * @returns {Object} Ancestor's type and distance from node.
|
18 | */
|
19 | function nearestBody() {
|
20 | var ancestors = context.getAncestors(),
|
21 | ancestor = ancestors.pop(),
|
22 | generation = 1;
|
23 |
|
24 | while (ancestor && ["Program", "FunctionDeclaration",
|
25 | "FunctionExpression", "ArrowFunctionExpression"
|
26 | ].indexOf(ancestor.type) < 0) {
|
27 | generation += 1;
|
28 | ancestor = ancestors.pop();
|
29 | }
|
30 |
|
31 | return {
|
32 | // Type of containing ancestor
|
33 | type: ancestor.type,
|
34 | // Separation between ancestor and node
|
35 | distance: generation
|
36 | };
|
37 | }
|
38 |
|
39 | /**
|
40 | * Ensure that a given node is at a program or function body's root.
|
41 | * @param {ASTNode} node Declaration node to check.
|
42 | * @returns {void}
|
43 | */
|
44 | function check(node) {
|
45 | var body = nearestBody(node),
|
46 | valid = ((body.type === "Program" && body.distance === 1) ||
|
47 | body.distance === 2);
|
48 |
|
49 | if (!valid) {
|
50 | context.report(node, "Move {{type}} declaration to {{body}} root.",
|
51 | {
|
52 | type: (node.type === "FunctionDeclaration" ?
|
53 | "function" : "variable"),
|
54 | body: (body.type === "Program" ?
|
55 | "program" : "function body")
|
56 | }
|
57 | );
|
58 | }
|
59 | }
|
60 |
|
61 | return {
|
62 |
|
63 | "FunctionDeclaration": check,
|
64 | "VariableDeclaration": function(node) {
|
65 | if (context.options[0] === "both" && node.kind === "var") {
|
66 | check(node);
|
67 | }
|
68 | }
|
69 |
|
70 | };
|
71 |
|
72 | };
|
73 |
|
74 | module.exports.schema = [
|
75 | {
|
76 | "enum": ["functions", "both"]
|
77 | }
|
78 | ];
|