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