mirror of
				https://git.proxmox.com/git/pve-eslint
				synced 2025-10-31 19:41:33 +00:00 
			
		
		
		
	 eb39fafa4f
			
		
	
	
		eb39fafa4f
		
	
	
	
	
		
			
			includes a (minimal) working wrapper Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
		
			
				
	
	
		
			173 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * @fileoverview Rule to flag when the same variable is declared more then once.
 | |
|  * @author Ilya Volodin
 | |
|  */
 | |
| 
 | |
| "use strict";
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Requirements
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| const astUtils = require("./utils/ast-utils");
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Rule Definition
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| module.exports = {
 | |
|     meta: {
 | |
|         type: "suggestion",
 | |
| 
 | |
|         docs: {
 | |
|             description: "disallow variable redeclaration",
 | |
|             category: "Best Practices",
 | |
|             recommended: true,
 | |
|             url: "https://eslint.org/docs/rules/no-redeclare"
 | |
|         },
 | |
| 
 | |
|         messages: {
 | |
|             redeclared: "'{{id}}' is already defined.",
 | |
|             redeclaredAsBuiltin: "'{{id}}' is already defined as a built-in global variable.",
 | |
|             redeclaredBySyntax: "'{{id}}' is already defined by a variable declaration."
 | |
|         },
 | |
| 
 | |
|         schema: [
 | |
|             {
 | |
|                 type: "object",
 | |
|                 properties: {
 | |
|                     builtinGlobals: { type: "boolean", default: true }
 | |
|                 },
 | |
|                 additionalProperties: false
 | |
|             }
 | |
|         ]
 | |
|     },
 | |
| 
 | |
|     create(context) {
 | |
|         const options = {
 | |
|             builtinGlobals: Boolean(
 | |
|                 context.options.length === 0 ||
 | |
|                 context.options[0].builtinGlobals
 | |
|             )
 | |
|         };
 | |
|         const sourceCode = context.getSourceCode();
 | |
| 
 | |
|         /**
 | |
|          * Iterate declarations of a given variable.
 | |
|          * @param {escope.variable} variable The variable object to iterate declarations.
 | |
|          * @returns {IterableIterator<{type:string,node:ASTNode,loc:SourceLocation}>} The declarations.
 | |
|          */
 | |
|         function *iterateDeclarations(variable) {
 | |
|             if (options.builtinGlobals && (
 | |
|                 variable.eslintImplicitGlobalSetting === "readonly" ||
 | |
|                 variable.eslintImplicitGlobalSetting === "writable"
 | |
|             )) {
 | |
|                 yield { type: "builtin" };
 | |
|             }
 | |
| 
 | |
|             for (const id of variable.identifiers) {
 | |
|                 yield { type: "syntax", node: id, loc: id.loc };
 | |
|             }
 | |
| 
 | |
|             if (variable.eslintExplicitGlobalComments) {
 | |
|                 for (const comment of variable.eslintExplicitGlobalComments) {
 | |
|                     yield {
 | |
|                         type: "comment",
 | |
|                         node: comment,
 | |
|                         loc: astUtils.getNameLocationInGlobalDirectiveComment(
 | |
|                             sourceCode,
 | |
|                             comment,
 | |
|                             variable.name
 | |
|                         )
 | |
|                     };
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Find variables in a given scope and flag redeclared ones.
 | |
|          * @param {Scope} scope An eslint-scope scope object.
 | |
|          * @returns {void}
 | |
|          * @private
 | |
|          */
 | |
|         function findVariablesInScope(scope) {
 | |
|             for (const variable of scope.variables) {
 | |
|                 const [
 | |
|                     declaration,
 | |
|                     ...extraDeclarations
 | |
|                 ] = iterateDeclarations(variable);
 | |
| 
 | |
|                 if (extraDeclarations.length === 0) {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 /*
 | |
|                  * If the type of a declaration is different from the type of
 | |
|                  * the first declaration, it shows the location of the first
 | |
|                  * declaration.
 | |
|                  */
 | |
|                 const detailMessageId = declaration.type === "builtin"
 | |
|                     ? "redeclaredAsBuiltin"
 | |
|                     : "redeclaredBySyntax";
 | |
|                 const data = { id: variable.name };
 | |
| 
 | |
|                 // Report extra declarations.
 | |
|                 for (const { type, node, loc } of extraDeclarations) {
 | |
|                     const messageId = type === declaration.type
 | |
|                         ? "redeclared"
 | |
|                         : detailMessageId;
 | |
| 
 | |
|                     context.report({ node, loc, messageId, data });
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Find variables in the current scope.
 | |
|          * @param {ASTNode} node The node of the current scope.
 | |
|          * @returns {void}
 | |
|          * @private
 | |
|          */
 | |
|         function checkForBlock(node) {
 | |
|             const scope = context.getScope();
 | |
| 
 | |
|             /*
 | |
|              * In ES5, some node type such as `BlockStatement` doesn't have that scope.
 | |
|              * `scope.block` is a different node in such a case.
 | |
|              */
 | |
|             if (scope.block === node) {
 | |
|                 findVariablesInScope(scope);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return {
 | |
|             Program() {
 | |
|                 const scope = context.getScope();
 | |
| 
 | |
|                 findVariablesInScope(scope);
 | |
| 
 | |
|                 // Node.js or ES modules has a special scope.
 | |
|                 if (
 | |
|                     scope.type === "global" &&
 | |
|                     scope.childScopes[0] &&
 | |
| 
 | |
|                     // The special scope's block is the Program node.
 | |
|                     scope.block === scope.childScopes[0].block
 | |
|                 ) {
 | |
|                     findVariablesInScope(scope.childScopes[0]);
 | |
|                 }
 | |
|             },
 | |
| 
 | |
|             FunctionDeclaration: checkForBlock,
 | |
|             FunctionExpression: checkForBlock,
 | |
|             ArrowFunctionExpression: checkForBlock,
 | |
| 
 | |
|             BlockStatement: checkForBlock,
 | |
|             ForStatement: checkForBlock,
 | |
|             ForInStatement: checkForBlock,
 | |
|             ForOfStatement: checkForBlock,
 | |
|             SwitchStatement: checkForBlock
 | |
|         };
 | |
|     }
 | |
| };
 |