UNPKG

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