1/** 2 * @fileoverview Restrict usage of specified globals. 3 * @author Benoît Zugmeyer 4 */ 5"use strict"; 6 7//------------------------------------------------------------------------------ 8// Rule Definition 9//------------------------------------------------------------------------------ 10 11module.exports = { 12 meta: { 13 type: "suggestion", 14 15 docs: { 16 description: "disallow specified global variables", 17 category: "Variables", 18 recommended: false, 19 url: "https://eslint.org/docs/rules/no-restricted-globals" 20 }, 21 22 schema: { 23 type: "array", 24 items: { 25 oneOf: [ 26 { 27 type: "string" 28 }, 29 { 30 type: "object", 31 properties: { 32 name: { type: "string" }, 33 message: { type: "string" } 34 }, 35 required: ["name"], 36 additionalProperties: false 37 } 38 ] 39 }, 40 uniqueItems: true, 41 minItems: 0 42 }, 43 44 messages: { 45 defaultMessage: "Unexpected use of '{{name}}'.", 46 // eslint-disable-next-line eslint-plugin/report-message-format 47 customMessage: "Unexpected use of '{{name}}'. {{customMessage}}" 48 } 49 }, 50 51 create(context) { 52 53 // If no globals are restricted, we don't need to do anything 54 if (context.options.length === 0) { 55 return {}; 56 } 57 58 const restrictedGlobalMessages = context.options.reduce((memo, option) => { 59 if (typeof option === "string") { 60 memo[option] = null; 61 } else { 62 memo[option.name] = option.message; 63 } 64 65 return memo; 66 }, {}); 67 68 /** 69 * Report a variable to be used as a restricted global. 70 * @param {Reference} reference the variable reference 71 * @returns {void} 72 * @private 73 */ 74 function reportReference(reference) { 75 const name = reference.identifier.name, 76 customMessage = restrictedGlobalMessages[name], 77 messageId = customMessage 78 ? "customMessage" 79 : "defaultMessage"; 80 81 context.report({ 82 node: reference.identifier, 83 messageId, 84 data: { 85 name, 86 customMessage 87 } 88 }); 89 } 90 91 /** 92 * Check if the given name is a restricted global name. 93 * @param {string} name name of a variable 94 * @returns {boolean} whether the variable is a restricted global or not 95 * @private 96 */ 97 function isRestricted(name) { 98 return Object.prototype.hasOwnProperty.call(restrictedGlobalMessages, name); 99 } 100 101 return { 102 Program() { 103 const scope = context.getScope(); 104 105 // Report variables declared elsewhere (ex: variables defined as "global" by eslint) 106 scope.variables.forEach(variable => { 107 if (!variable.defs.length && isRestricted(variable.name)) { 108 variable.references.forEach(reportReference); 109 } 110 }); 111 112 // Report variables not declared at all 113 scope.through.forEach(reference => { 114 if (isRestricted(reference.identifier.name)) { 115 reportReference(reference); 116 } 117 }); 118 119 } 120 }; 121 } 122}; 123