]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/no-redeclare.js
3de4397b1b0e15fdbd4290340d92f62fe8795dc0
[pve-eslint.git] / eslint / lib / rules / no-redeclare.js
1 /**
2 * @fileoverview Rule to flag when the same variable is declared more then once.
3 * @author Ilya Volodin
4 */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const astUtils = require("./utils/ast-utils");
13
14 //------------------------------------------------------------------------------
15 // Rule Definition
16 //------------------------------------------------------------------------------
17
18 module.exports = {
19 meta: {
20 type: "suggestion",
21
22 docs: {
23 description: "disallow variable redeclaration",
24 recommended: true,
25 url: "https://eslint.org/docs/rules/no-redeclare"
26 },
27
28 messages: {
29 redeclared: "'{{id}}' is already defined.",
30 redeclaredAsBuiltin: "'{{id}}' is already defined as a built-in global variable.",
31 redeclaredBySyntax: "'{{id}}' is already defined by a variable declaration."
32 },
33
34 schema: [
35 {
36 type: "object",
37 properties: {
38 builtinGlobals: { type: "boolean", default: true }
39 },
40 additionalProperties: false
41 }
42 ]
43 },
44
45 create(context) {
46 const options = {
47 builtinGlobals: Boolean(
48 context.options.length === 0 ||
49 context.options[0].builtinGlobals
50 )
51 };
52 const sourceCode = context.getSourceCode();
53
54 /**
55 * Iterate declarations of a given variable.
56 * @param {escope.variable} variable The variable object to iterate declarations.
57 * @returns {IterableIterator<{type:string,node:ASTNode,loc:SourceLocation}>} The declarations.
58 */
59 function *iterateDeclarations(variable) {
60 if (options.builtinGlobals && (
61 variable.eslintImplicitGlobalSetting === "readonly" ||
62 variable.eslintImplicitGlobalSetting === "writable"
63 )) {
64 yield { type: "builtin" };
65 }
66
67 for (const id of variable.identifiers) {
68 yield { type: "syntax", node: id, loc: id.loc };
69 }
70
71 if (variable.eslintExplicitGlobalComments) {
72 for (const comment of variable.eslintExplicitGlobalComments) {
73 yield {
74 type: "comment",
75 node: comment,
76 loc: astUtils.getNameLocationInGlobalDirectiveComment(
77 sourceCode,
78 comment,
79 variable.name
80 )
81 };
82 }
83 }
84 }
85
86 /**
87 * Find variables in a given scope and flag redeclared ones.
88 * @param {Scope} scope An eslint-scope scope object.
89 * @returns {void}
90 * @private
91 */
92 function findVariablesInScope(scope) {
93 for (const variable of scope.variables) {
94 const [
95 declaration,
96 ...extraDeclarations
97 ] = iterateDeclarations(variable);
98
99 if (extraDeclarations.length === 0) {
100 continue;
101 }
102
103 /*
104 * If the type of a declaration is different from the type of
105 * the first declaration, it shows the location of the first
106 * declaration.
107 */
108 const detailMessageId = declaration.type === "builtin"
109 ? "redeclaredAsBuiltin"
110 : "redeclaredBySyntax";
111 const data = { id: variable.name };
112
113 // Report extra declarations.
114 for (const { type, node, loc } of extraDeclarations) {
115 const messageId = type === declaration.type
116 ? "redeclared"
117 : detailMessageId;
118
119 context.report({ node, loc, messageId, data });
120 }
121 }
122 }
123
124 /**
125 * Find variables in the current scope.
126 * @param {ASTNode} node The node of the current scope.
127 * @returns {void}
128 * @private
129 */
130 function checkForBlock(node) {
131 const scope = context.getScope();
132
133 /*
134 * In ES5, some node type such as `BlockStatement` doesn't have that scope.
135 * `scope.block` is a different node in such a case.
136 */
137 if (scope.block === node) {
138 findVariablesInScope(scope);
139 }
140 }
141
142 return {
143 Program() {
144 const scope = context.getScope();
145
146 findVariablesInScope(scope);
147
148 // Node.js or ES modules has a special scope.
149 if (
150 scope.type === "global" &&
151 scope.childScopes[0] &&
152
153 // The special scope's block is the Program node.
154 scope.block === scope.childScopes[0].block
155 ) {
156 findVariablesInScope(scope.childScopes[0]);
157 }
158 },
159
160 FunctionDeclaration: checkForBlock,
161 FunctionExpression: checkForBlock,
162 ArrowFunctionExpression: checkForBlock,
163
164 StaticBlock: checkForBlock,
165
166 BlockStatement: checkForBlock,
167 ForStatement: checkForBlock,
168 ForInStatement: checkForBlock,
169 ForOfStatement: checkForBlock,
170 SwitchStatement: checkForBlock
171 };
172 }
173 };