1/** 2 * @fileoverview Rule for disallowing require() outside of the top-level module context 3 * @author Jamund Ferguson 4 */ 5 6"use strict"; 7 8const ACCEPTABLE_PARENTS = [ 9 "AssignmentExpression", 10 "VariableDeclarator", 11 "MemberExpression", 12 "ExpressionStatement", 13 "CallExpression", 14 "ConditionalExpression", 15 "Program", 16 "VariableDeclaration", 17 "ChainExpression" 18]; 19 20/** 21 * Finds the eslint-scope reference in the given scope. 22 * @param {Object} scope The scope to search. 23 * @param {ASTNode} node The identifier node. 24 * @returns {Reference|null} Returns the found reference or null if none were found. 25 */ 26function findReference(scope, node) { 27 const references = scope.references.filter(reference => reference.identifier.range[0] === node.range[0] && 28 reference.identifier.range[1] === node.range[1]); 29 30 /* istanbul ignore else: correctly returns null */ 31 if (references.length === 1) { 32 return references[0]; 33 } 34 return null; 35 36} 37 38/** 39 * Checks if the given identifier node is shadowed in the given scope. 40 * @param {Object} scope The current scope. 41 * @param {ASTNode} node The identifier node to check. 42 * @returns {boolean} Whether or not the name is shadowed. 43 */ 44function isShadowed(scope, node) { 45 const reference = findReference(scope, node); 46 47 return reference && reference.resolved && reference.resolved.defs.length > 0; 48} 49 50module.exports = { 51 meta: { 52 deprecated: true, 53 54 replacedBy: [], 55 56 type: "suggestion", 57 58 docs: { 59 description: "require `require()` calls to be placed at top-level module scope", 60 category: "Node.js and CommonJS", 61 recommended: false, 62 url: "https://eslint.org/docs/rules/global-require" 63 }, 64 65 schema: [], 66 messages: { 67 unexpected: "Unexpected require()." 68 } 69 }, 70 71 create(context) { 72 return { 73 CallExpression(node) { 74 const currentScope = context.getScope(); 75 76 if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) { 77 const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.indexOf(parent.type) > -1); 78 79 if (!isGoodRequire) { 80 context.report({ node, messageId: "unexpected" }); 81 } 82 } 83 } 84 }; 85 } 86}; 87