UNPKG

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