]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-implicit-globals.js
import 8.41.0 source
[pve-eslint.git] / eslint / lib / rules / no-implicit-globals.js
1 /**
2 * @fileoverview Rule to check for implicit global variables, functions and classes.
3 * @author Joshua Peek
4 */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 /** @type {import('../shared/types').Rule} */
13 module.exports = {
14 meta: {
15 type: "suggestion",
16
17 docs: {
18 description: "Disallow declarations in the global scope",
19 recommended: false,
20 url: "https://eslint.org/docs/latest/rules/no-implicit-globals"
21 },
22
23 schema: [{
24 type: "object",
25 properties: {
26 lexicalBindings: {
27 type: "boolean",
28 default: false
29 }
30 },
31 additionalProperties: false
32 }],
33
34 messages: {
35 globalNonLexicalBinding: "Unexpected {{kind}} declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable.",
36 globalLexicalBinding: "Unexpected {{kind}} declaration in the global scope, wrap in a block or in an IIFE.",
37 globalVariableLeak: "Global variable leak, declare the variable if it is intended to be local.",
38 assignmentToReadonlyGlobal: "Unexpected assignment to read-only global variable.",
39 redeclarationOfReadonlyGlobal: "Unexpected redeclaration of read-only global variable."
40 }
41 },
42
43 create(context) {
44
45 const checkLexicalBindings = context.options[0] && context.options[0].lexicalBindings === true;
46 const sourceCode = context.sourceCode;
47
48 /**
49 * Reports the node.
50 * @param {ASTNode} node Node to report.
51 * @param {string} messageId Id of the message to report.
52 * @param {string|undefined} kind Declaration kind, can be 'var', 'const', 'let', function or class.
53 * @returns {void}
54 */
55 function report(node, messageId, kind) {
56 context.report({
57 node,
58 messageId,
59 data: {
60 kind
61 }
62 });
63 }
64
65 return {
66 Program(node) {
67 const scope = sourceCode.getScope(node);
68
69 scope.variables.forEach(variable => {
70
71 // Only ESLint global variables have the `writable` key.
72 const isReadonlyEslintGlobalVariable = variable.writeable === false;
73 const isWritableEslintGlobalVariable = variable.writeable === true;
74
75 if (isWritableEslintGlobalVariable) {
76
77 // Everything is allowed with writable ESLint global variables.
78 return;
79 }
80
81 // Variables exported by "exported" block comments
82 if (variable.eslintExported) {
83 return;
84 }
85
86 variable.defs.forEach(def => {
87 const defNode = def.node;
88
89 if (def.type === "FunctionName" || (def.type === "Variable" && def.parent.kind === "var")) {
90 if (isReadonlyEslintGlobalVariable) {
91 report(defNode, "redeclarationOfReadonlyGlobal");
92 } else {
93 report(
94 defNode,
95 "globalNonLexicalBinding",
96 def.type === "FunctionName" ? "function" : `'${def.parent.kind}'`
97 );
98 }
99 }
100
101 if (checkLexicalBindings) {
102 if (def.type === "ClassName" ||
103 (def.type === "Variable" && (def.parent.kind === "let" || def.parent.kind === "const"))) {
104 if (isReadonlyEslintGlobalVariable) {
105 report(defNode, "redeclarationOfReadonlyGlobal");
106 } else {
107 report(
108 defNode,
109 "globalLexicalBinding",
110 def.type === "ClassName" ? "class" : `'${def.parent.kind}'`
111 );
112 }
113 }
114 }
115 });
116 });
117
118 // Undeclared assigned variables.
119 scope.implicit.variables.forEach(variable => {
120 const scopeVariable = scope.set.get(variable.name);
121 let messageId;
122
123 if (scopeVariable) {
124
125 // ESLint global variable
126 if (scopeVariable.writeable) {
127 return;
128 }
129 messageId = "assignmentToReadonlyGlobal";
130
131 } else {
132
133 // Reference to an unknown variable, possible global leak.
134 messageId = "globalVariableLeak";
135 }
136
137 // def.node is an AssignmentExpression, ForInStatement or ForOfStatement.
138 variable.defs.forEach(def => {
139 report(def.node, messageId);
140 });
141 });
142 }
143 };
144
145 }
146 };