minor adjustment to readme
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-mixed-requires.js
1 /**
2  * @fileoverview Rule to enforce grouped require statements for Node.JS
3  * @author Raphael Pigulla
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 module.exports = {
13     meta: {
14         type: "suggestion",
15
16         docs: {
17             description: "disallow `require` calls to be mixed with regular variable declarations",
18             category: "Node.js and CommonJS",
19             recommended: false,
20             url: "https://eslint.org/docs/rules/no-mixed-requires"
21         },
22
23         schema: [
24             {
25                 oneOf: [
26                     {
27                         type: "boolean"
28                     },
29                     {
30                         type: "object",
31                         properties: {
32                             grouping: {
33                                 type: "boolean"
34                             },
35                             allowCall: {
36                                 type: "boolean"
37                             }
38                         },
39                         additionalProperties: false
40                     }
41                 ]
42             }
43         ]
44     },
45
46     create(context) {
47
48         const options = context.options[0];
49         let grouping = false,
50             allowCall = false;
51
52         if (typeof options === "object") {
53             grouping = options.grouping;
54             allowCall = options.allowCall;
55         } else {
56             grouping = !!options;
57         }
58
59         /**
60          * Returns the list of built-in modules.
61          * @returns {string[]} An array of built-in Node.js modules.
62          */
63         function getBuiltinModules() {
64
65             /*
66              * This list is generated using:
67              * `require("repl")._builtinLibs.concat('repl').sort()`
68              * This particular list is as per nodejs v0.12.2 and iojs v0.7.1
69              */
70             return [
71                 "assert", "buffer", "child_process", "cluster", "crypto",
72                 "dgram", "dns", "domain", "events", "fs", "http", "https",
73                 "net", "os", "path", "punycode", "querystring", "readline",
74                 "repl", "smalloc", "stream", "string_decoder", "tls", "tty",
75                 "url", "util", "v8", "vm", "zlib"
76             ];
77         }
78
79         const BUILTIN_MODULES = getBuiltinModules();
80
81         const DECL_REQUIRE = "require",
82             DECL_UNINITIALIZED = "uninitialized",
83             DECL_OTHER = "other";
84
85         const REQ_CORE = "core",
86             REQ_FILE = "file",
87             REQ_MODULE = "module",
88             REQ_COMPUTED = "computed";
89
90         /**
91          * Determines the type of a declaration statement.
92          * @param {ASTNode} initExpression The init node of the VariableDeclarator.
93          * @returns {string} The type of declaration represented by the expression.
94          */
95         function getDeclarationType(initExpression) {
96             if (!initExpression) {
97
98                 // "var x;"
99                 return DECL_UNINITIALIZED;
100             }
101
102             if (initExpression.type === "CallExpression" &&
103                 initExpression.callee.type === "Identifier" &&
104                 initExpression.callee.name === "require"
105             ) {
106
107                 // "var x = require('util');"
108                 return DECL_REQUIRE;
109             }
110             if (allowCall &&
111                 initExpression.type === "CallExpression" &&
112                 initExpression.callee.type === "CallExpression"
113             ) {
114
115                 // "var x = require('diagnose')('sub-module');"
116                 return getDeclarationType(initExpression.callee);
117             }
118             if (initExpression.type === "MemberExpression") {
119
120                 // "var x = require('glob').Glob;"
121                 return getDeclarationType(initExpression.object);
122             }
123
124             // "var x = 42;"
125             return DECL_OTHER;
126         }
127
128         /**
129          * Determines the type of module that is loaded via require.
130          * @param {ASTNode} initExpression The init node of the VariableDeclarator.
131          * @returns {string} The module type.
132          */
133         function inferModuleType(initExpression) {
134             if (initExpression.type === "MemberExpression") {
135
136                 // "var x = require('glob').Glob;"
137                 return inferModuleType(initExpression.object);
138             }
139             if (initExpression.arguments.length === 0) {
140
141                 // "var x = require();"
142                 return REQ_COMPUTED;
143             }
144
145             const arg = initExpression.arguments[0];
146
147             if (arg.type !== "Literal" || typeof arg.value !== "string") {
148
149                 // "var x = require(42);"
150                 return REQ_COMPUTED;
151             }
152
153             if (BUILTIN_MODULES.indexOf(arg.value) !== -1) {
154
155                 // "var fs = require('fs');"
156                 return REQ_CORE;
157             }
158             if (/^\.{0,2}\//u.test(arg.value)) {
159
160                 // "var utils = require('./utils');"
161                 return REQ_FILE;
162             }
163
164             // "var async = require('async');"
165             return REQ_MODULE;
166
167         }
168
169         /**
170          * Check if the list of variable declarations is mixed, i.e. whether it
171          * contains both require and other declarations.
172          * @param {ASTNode} declarations The list of VariableDeclarators.
173          * @returns {boolean} True if the declarations are mixed, false if not.
174          */
175         function isMixed(declarations) {
176             const contains = {};
177
178             declarations.forEach(declaration => {
179                 const type = getDeclarationType(declaration.init);
180
181                 contains[type] = true;
182             });
183
184             return !!(
185                 contains[DECL_REQUIRE] &&
186                 (contains[DECL_UNINITIALIZED] || contains[DECL_OTHER])
187             );
188         }
189
190         /**
191          * Check if all require declarations in the given list are of the same
192          * type.
193          * @param {ASTNode} declarations The list of VariableDeclarators.
194          * @returns {boolean} True if the declarations are grouped, false if not.
195          */
196         function isGrouped(declarations) {
197             const found = {};
198
199             declarations.forEach(declaration => {
200                 if (getDeclarationType(declaration.init) === DECL_REQUIRE) {
201                     found[inferModuleType(declaration.init)] = true;
202                 }
203             });
204
205             return Object.keys(found).length <= 1;
206         }
207
208
209         return {
210
211             VariableDeclaration(node) {
212
213                 if (isMixed(node.declarations)) {
214                     context.report({ node, message: "Do not mix 'require' and other declarations." });
215                 } else if (grouping && !isGrouped(node.declarations)) {
216                     context.report({ node, message: "Do not mix core, module, file and computed requires." });
217                 }
218             }
219         };
220
221     }
222 };