UNPKG

3.64 kBJavaScriptView Raw
1/**
2 * @fileoverview A rule to disallow duplicate name in class members.
3 * @author Toru Nagashima
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Rule Definition
10//------------------------------------------------------------------------------
11
12module.exports = {
13 meta: {
14 docs: {
15 description: "disallow duplicate class members",
16 category: "ECMAScript 6",
17 recommended: true,
18 url: "https://eslint.org/docs/rules/no-dupe-class-members"
19 },
20
21 schema: [],
22
23 messages: {
24 unexpected: "Duplicate name '{{name}}'."
25 }
26 },
27
28 create(context) {
29 let stack = [];
30
31 /**
32 * Gets state of a given member name.
33 * @param {string} name - A name of a member.
34 * @param {boolean} isStatic - A flag which specifies that is a static member.
35 * @returns {Object} A state of a given member name.
36 * - retv.init {boolean} A flag which shows the name is declared as normal member.
37 * - retv.get {boolean} A flag which shows the name is declared as getter.
38 * - retv.set {boolean} A flag which shows the name is declared as setter.
39 */
40 function getState(name, isStatic) {
41 const stateMap = stack[stack.length - 1];
42 const key = `$${name}`; // to avoid "__proto__".
43
44 if (!stateMap[key]) {
45 stateMap[key] = {
46 nonStatic: { init: false, get: false, set: false },
47 static: { init: false, get: false, set: false }
48 };
49 }
50
51 return stateMap[key][isStatic ? "static" : "nonStatic"];
52 }
53
54 /**
55 * Gets the name text of a given node.
56 *
57 * @param {ASTNode} node - A node to get the name.
58 * @returns {string} The name text of the node.
59 */
60 function getName(node) {
61 switch (node.type) {
62 case "Identifier": return node.name;
63 case "Literal": return String(node.value);
64
65 /* istanbul ignore next: syntax error */
66 default: return "";
67 }
68 }
69
70 return {
71
72 // Initializes the stack of state of member declarations.
73 Program() {
74 stack = [];
75 },
76
77 // Initializes state of member declarations for the class.
78 ClassBody() {
79 stack.push(Object.create(null));
80 },
81
82 // Disposes the state for the class.
83 "ClassBody:exit"() {
84 stack.pop();
85 },
86
87 // Reports the node if its name has been declared already.
88 MethodDefinition(node) {
89 if (node.computed) {
90 return;
91 }
92
93 const name = getName(node.key);
94 const state = getState(name, node.static);
95 let isDuplicate = false;
96
97 if (node.kind === "get") {
98 isDuplicate = (state.init || state.get);
99 state.get = true;
100 } else if (node.kind === "set") {
101 isDuplicate = (state.init || state.set);
102 state.set = true;
103 } else {
104 isDuplicate = (state.init || state.get || state.set);
105 state.init = true;
106 }
107
108 if (isDuplicate) {
109 context.report({ node, messageId: "unexpected", data: { name } });
110 }
111 }
112 };
113 }
114};