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