global-require.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /**
  2. * @fileoverview Rule for disallowing require() outside of the top-level module context
  3. * @author Jamund Ferguson
  4. * @deprecated in ESLint v7.0.0
  5. */
  6. "use strict";
  7. const ACCEPTABLE_PARENTS = new Set([
  8. "AssignmentExpression",
  9. "VariableDeclarator",
  10. "MemberExpression",
  11. "ExpressionStatement",
  12. "CallExpression",
  13. "ConditionalExpression",
  14. "Program",
  15. "VariableDeclaration",
  16. "ChainExpression",
  17. ]);
  18. /**
  19. * Finds the eslint-scope reference in the given scope.
  20. * @param {Object} scope The scope to search.
  21. * @param {ASTNode} node The identifier node.
  22. * @returns {Reference|null} Returns the found reference or null if none were found.
  23. */
  24. function findReference(scope, node) {
  25. const references = scope.references.filter(
  26. reference =>
  27. reference.identifier.range[0] === node.range[0] &&
  28. reference.identifier.range[1] === node.range[1],
  29. );
  30. if (references.length === 1) {
  31. return references[0];
  32. }
  33. /* c8 ignore next */
  34. return null;
  35. }
  36. /**
  37. * Checks if the given identifier node is shadowed in the given scope.
  38. * @param {Object} scope The current scope.
  39. * @param {ASTNode} node The identifier node to check.
  40. * @returns {boolean} Whether or not the name is shadowed.
  41. */
  42. function isShadowed(scope, node) {
  43. const reference = findReference(scope, node);
  44. return (
  45. reference && reference.resolved && reference.resolved.defs.length > 0
  46. );
  47. }
  48. /** @type {import('../types').Rule.RuleModule} */
  49. module.exports = {
  50. meta: {
  51. deprecated: {
  52. message: "Node.js rules were moved out of ESLint core.",
  53. url: "https://eslint.org/docs/latest/use/migrating-to-7.0.0#deprecate-node-rules",
  54. deprecatedSince: "7.0.0",
  55. availableUntil: "11.0.0",
  56. replacedBy: [
  57. {
  58. message:
  59. "eslint-plugin-n now maintains deprecated Node.js-related rules.",
  60. plugin: {
  61. name: "eslint-plugin-n",
  62. url: "https://github.com/eslint-community/eslint-plugin-n",
  63. },
  64. rule: {
  65. name: "global-require",
  66. url: "https://github.com/eslint-community/eslint-plugin-n/tree/master/docs/rules/global-require.md",
  67. },
  68. },
  69. ],
  70. },
  71. type: "suggestion",
  72. docs: {
  73. description:
  74. "Require `require()` calls to be placed at top-level module scope",
  75. recommended: false,
  76. url: "https://eslint.org/docs/latest/rules/global-require",
  77. },
  78. schema: [],
  79. messages: {
  80. unexpected: "Unexpected require().",
  81. },
  82. },
  83. create(context) {
  84. const sourceCode = context.sourceCode;
  85. return {
  86. CallExpression(node) {
  87. const currentScope = sourceCode.getScope(node);
  88. if (
  89. node.callee.name === "require" &&
  90. !isShadowed(currentScope, node.callee)
  91. ) {
  92. const isGoodRequire = sourceCode
  93. .getAncestors(node)
  94. .every(parent => ACCEPTABLE_PARENTS.has(parent.type));
  95. if (!isGoodRequire) {
  96. context.report({ node, messageId: "unexpected" });
  97. }
  98. }
  99. },
  100. };
  101. },
  102. };