You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							115 lines
						
					
					
						
							3.6 KiB
						
					
					
				
			
		
		
	
	
							115 lines
						
					
					
						
							3.6 KiB
						
					
					
				/** | 
						|
 * @fileoverview A rule to disallow duplicate name in class members. | 
						|
 * @author Toru Nagashima | 
						|
 */ | 
						|
 | 
						|
"use strict"; | 
						|
 | 
						|
//------------------------------------------------------------------------------ | 
						|
// Rule Definition | 
						|
//------------------------------------------------------------------------------ | 
						|
 | 
						|
module.exports = { | 
						|
    meta: { | 
						|
        type: "problem", | 
						|
 | 
						|
        docs: { | 
						|
            description: "disallow duplicate class members", | 
						|
            category: "ECMAScript 6", | 
						|
            recommended: true, | 
						|
            url: "https://eslint.org/docs/rules/no-dupe-class-members" | 
						|
        }, | 
						|
 | 
						|
        schema: [], | 
						|
 | 
						|
        messages: { | 
						|
            unexpected: "Duplicate name '{{name}}'." | 
						|
        } | 
						|
    }, | 
						|
 | 
						|
    create(context) { | 
						|
        let stack = []; | 
						|
 | 
						|
        /** | 
						|
         * Gets state of a given member name. | 
						|
         * @param {string} name A name of a member. | 
						|
         * @param {boolean} isStatic A flag which specifies that is a static member. | 
						|
         * @returns {Object} A state of a given member name. | 
						|
         *   - retv.init {boolean} A flag which shows the name is declared as normal member. | 
						|
         *   - retv.get {boolean} A flag which shows the name is declared as getter. | 
						|
         *   - retv.set {boolean} A flag which shows the name is declared as setter. | 
						|
         */ | 
						|
        function getState(name, isStatic) { | 
						|
            const stateMap = stack[stack.length - 1]; | 
						|
            const key = `$${name}`; // to avoid "__proto__". | 
						|
 | 
						|
            if (!stateMap[key]) { | 
						|
                stateMap[key] = { | 
						|
                    nonStatic: { init: false, get: false, set: false }, | 
						|
                    static: { init: false, get: false, set: false } | 
						|
                }; | 
						|
            } | 
						|
 | 
						|
            return stateMap[key][isStatic ? "static" : "nonStatic"]; | 
						|
        } | 
						|
 | 
						|
        /** | 
						|
         * Gets the name text of a given node. | 
						|
         * @param {ASTNode} node A node to get the name. | 
						|
         * @returns {string} The name text of the node. | 
						|
         */ | 
						|
        function getName(node) { | 
						|
            switch (node.type) { | 
						|
                case "Identifier": return node.name; | 
						|
                case "Literal": return String(node.value); | 
						|
 | 
						|
                /* istanbul ignore next: syntax error */ | 
						|
                default: return ""; | 
						|
            } | 
						|
        } | 
						|
 | 
						|
        return { | 
						|
 | 
						|
            // Initializes the stack of state of member declarations. | 
						|
            Program() { | 
						|
                stack = []; | 
						|
            }, | 
						|
 | 
						|
            // Initializes state of member declarations for the class. | 
						|
            ClassBody() { | 
						|
                stack.push(Object.create(null)); | 
						|
            }, | 
						|
 | 
						|
            // Disposes the state for the class. | 
						|
            "ClassBody:exit"() { | 
						|
                stack.pop(); | 
						|
            }, | 
						|
 | 
						|
            // Reports the node if its name has been declared already. | 
						|
            MethodDefinition(node) { | 
						|
                if (node.computed) { | 
						|
                    return; | 
						|
                } | 
						|
 | 
						|
                const name = getName(node.key); | 
						|
                const state = getState(name, node.static); | 
						|
                let isDuplicate = false; | 
						|
 | 
						|
                if (node.kind === "get") { | 
						|
                    isDuplicate = (state.init || state.get); | 
						|
                    state.get = true; | 
						|
                } else if (node.kind === "set") { | 
						|
                    isDuplicate = (state.init || state.set); | 
						|
                    state.set = true; | 
						|
                } else { | 
						|
                    isDuplicate = (state.init || state.get || state.set); | 
						|
                    state.init = true; | 
						|
                } | 
						|
 | 
						|
                if (isDuplicate) { | 
						|
                    context.report({ node, messageId: "unexpected", data: { name } }); | 
						|
                } | 
						|
            } | 
						|
        }; | 
						|
    } | 
						|
};
 | 
						|
 |