.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / vars-on-top.js
1 /**
2  * @fileoverview Rule to enforce var declarations are only at the top of a function.
3  * @author Danny Fritz
4  * @author Gyandeep Singh
5  */
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 module.exports = {
13     meta: {
14         type: "suggestion",
15
16         docs: {
17             description: "require `var` declarations be placed at the top of their containing scope",
18             category: "Best Practices",
19             recommended: false,
20             url: "https://eslint.org/docs/rules/vars-on-top"
21         },
22
23         schema: [],
24         messages: {
25             top: "All 'var' declarations must be at the top of the function scope."
26         }
27     },
28
29     create(context) {
30
31         //--------------------------------------------------------------------------
32         // Helpers
33         //--------------------------------------------------------------------------
34
35         // eslint-disable-next-line jsdoc/require-description
36         /**
37          * @param {ASTNode} node any node
38          * @returns {boolean} whether the given node structurally represents a directive
39          */
40         function looksLikeDirective(node) {
41             return node.type === "ExpressionStatement" &&
42                 node.expression.type === "Literal" && typeof node.expression.value === "string";
43         }
44
45         /**
46          * Check to see if its a ES6 import declaration
47          * @param {ASTNode} node any node
48          * @returns {boolean} whether the given node represents a import declaration
49          */
50         function looksLikeImport(node) {
51             return node.type === "ImportDeclaration" || node.type === "ImportSpecifier" ||
52                 node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier";
53         }
54
55         /**
56          * Checks whether a given node is a variable declaration or not.
57          * @param {ASTNode} node any node
58          * @returns {boolean} `true` if the node is a variable declaration.
59          */
60         function isVariableDeclaration(node) {
61             return (
62                 node.type === "VariableDeclaration" ||
63                 (
64                     node.type === "ExportNamedDeclaration" &&
65                     node.declaration &&
66                     node.declaration.type === "VariableDeclaration"
67                 )
68             );
69         }
70
71         /**
72          * Checks whether this variable is on top of the block body
73          * @param {ASTNode} node The node to check
74          * @param {ASTNode[]} statements collection of ASTNodes for the parent node block
75          * @returns {boolean} True if var is on top otherwise false
76          */
77         function isVarOnTop(node, statements) {
78             const l = statements.length;
79             let i = 0;
80
81             // skip over directives
82             for (; i < l; ++i) {
83                 if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) {
84                     break;
85                 }
86             }
87
88             for (; i < l; ++i) {
89                 if (!isVariableDeclaration(statements[i])) {
90                     return false;
91                 }
92                 if (statements[i] === node) {
93                     return true;
94                 }
95             }
96
97             return false;
98         }
99
100         /**
101          * Checks whether variable is on top at the global level
102          * @param {ASTNode} node The node to check
103          * @param {ASTNode} parent Parent of the node
104          * @returns {void}
105          */
106         function globalVarCheck(node, parent) {
107             if (!isVarOnTop(node, parent.body)) {
108                 context.report({ node, messageId: "top" });
109             }
110         }
111
112         /**
113          * Checks whether variable is on top at functional block scope level
114          * @param {ASTNode} node The node to check
115          * @param {ASTNode} parent Parent of the node
116          * @param {ASTNode} grandParent Parent of the node's parent
117          * @returns {void}
118          */
119         function blockScopeVarCheck(node, parent, grandParent) {
120             if (!(/Function/u.test(grandParent.type) &&
121                     parent.type === "BlockStatement" &&
122                     isVarOnTop(node, parent.body))) {
123                 context.report({ node, messageId: "top" });
124             }
125         }
126
127         //--------------------------------------------------------------------------
128         // Public API
129         //--------------------------------------------------------------------------
130
131         return {
132             "VariableDeclaration[kind='var']"(node) {
133                 if (node.parent.type === "ExportNamedDeclaration") {
134                     globalVarCheck(node.parent, node.parent.parent);
135                 } else if (node.parent.type === "Program") {
136                     globalVarCheck(node, node.parent);
137                 } else {
138                     blockScopeVarCheck(node, node.parent, node.parent.parent);
139                 }
140             }
141         };
142
143     }
144 };