no-mixed-requires.js 7.2 KB

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