Skip to content

Commit 312a88f

Browse files
mdjermanovicKai Cataldo
authored andcommitted
New: Add grouped-accessor-pairs rule (fixes #12277) (#12331)
* New: Add grouped-accessor-pairs rule (fixes #12277) * Update docs/rules/grouped-accessor-pairs.md Co-Authored-By: Jordan Harband <[email protected]> * Fix JSDoc * Add related rules
1 parent 5c68f5f commit 312a88f

File tree

5 files changed

+992
-0
lines changed

5 files changed

+992
-0
lines changed
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
# Require grouped accessor pairs in object literals and classes (grouped-accessor-pairs)
2+
3+
A getter and setter for the same property don't necessarily have to be defined adjacent to each other.
4+
5+
For example, the following statements would create the same object:
6+
7+
```js
8+
var o = {
9+
get a() {
10+
return this.val;
11+
},
12+
set a(value) {
13+
this.val = value;
14+
},
15+
b: 1
16+
};
17+
18+
var o = {
19+
get a() {
20+
return this.val;
21+
},
22+
b: 1,
23+
set a(value) {
24+
this.val = value;
25+
}
26+
};
27+
```
28+
29+
While it is allowed to define the pair for a getter or a setter anywhere in an object or class definition, it's considered a best practice to group accessor functions for the same property.
30+
31+
In other words, if a property has a getter and a setter, the setter should be defined right after the getter, or vice versa.
32+
33+
## Rule Details
34+
35+
This rule requires grouped definitions of accessor functions for the same property in object literals, class declarations and class expressions.
36+
37+
Optionally, this rule can also enforce consistent order (`getBeforeSet` or `setBeforeGet`).
38+
39+
This rule does not enforce the existence of the pair for a getter or a setter. See [accessor-pairs](accessor-pairs.md) if you also want to enforce getter/setter pairs.
40+
41+
Examples of **incorrect** code for this rule:
42+
43+
```js
44+
/*eslint grouped-accessor-pairs: "error"*/
45+
46+
var foo = {
47+
get a() {
48+
return this.val;
49+
},
50+
b: 1,
51+
set a(value) {
52+
this.val = value;
53+
}
54+
};
55+
56+
var bar = {
57+
set b(value) {
58+
this.val = value;
59+
},
60+
a: 1,
61+
get b() {
62+
return this.val;
63+
}
64+
}
65+
66+
class Foo {
67+
set a(value) {
68+
this.val = value;
69+
}
70+
b(){}
71+
get a() {
72+
return this.val;
73+
}
74+
}
75+
76+
const Bar = class {
77+
static get a() {
78+
return this.val;
79+
}
80+
b(){}
81+
static set a(value) {
82+
this.val = value;
83+
}
84+
}
85+
```
86+
87+
Examples of **correct** code for this rule:
88+
89+
```js
90+
/*eslint grouped-accessor-pairs: "error"*/
91+
92+
var foo = {
93+
get a() {
94+
return this.val;
95+
},
96+
set a(value) {
97+
this.val = value;
98+
},
99+
b: 1
100+
};
101+
102+
var bar = {
103+
set b(value) {
104+
this.val = value;
105+
},
106+
get b() {
107+
return this.val;
108+
},
109+
a: 1
110+
}
111+
112+
class Foo {
113+
set a(value) {
114+
this.val = value;
115+
}
116+
get a() {
117+
return this.val;
118+
}
119+
b(){}
120+
}
121+
122+
const Bar = class {
123+
static get a() {
124+
return this.val;
125+
}
126+
static set a(value) {
127+
this.val = value;
128+
}
129+
b(){}
130+
}
131+
```
132+
133+
## Options
134+
135+
This rule has a string option:
136+
137+
* `"anyOrder"` (default) does not enforce order.
138+
* `"getBeforeSet"` if a property has both getter and setter, requires the getter to be defined before the setter.
139+
* `"setBeforeGet"` if a property has both getter and setter, requires the setter to be defined before the getter.
140+
141+
### getBeforeSet
142+
143+
Examples of **incorrect** code for this rule with the `"getBeforeSet"` option:
144+
145+
```js
146+
/*eslint grouped-accessor-pairs: ["error", "getBeforeSet"]*/
147+
148+
var foo = {
149+
set a(value) {
150+
this.val = value;
151+
},
152+
get a() {
153+
return this.val;
154+
}
155+
};
156+
157+
class Foo {
158+
set a(value) {
159+
this.val = value;
160+
}
161+
get a() {
162+
return this.val;
163+
}
164+
}
165+
166+
const Bar = class {
167+
static set a(value) {
168+
this.val = value;
169+
}
170+
static get a() {
171+
return this.val;
172+
}
173+
}
174+
```
175+
176+
Examples of **correct** code for this rule with the `"getBeforeSet"` option:
177+
178+
```js
179+
/*eslint grouped-accessor-pairs: ["error", "getBeforeSet"]*/
180+
181+
var foo = {
182+
get a() {
183+
return this.val;
184+
},
185+
set a(value) {
186+
this.val = value;
187+
}
188+
};
189+
190+
class Foo {
191+
get a() {
192+
return this.val;
193+
}
194+
set a(value) {
195+
this.val = value;
196+
}
197+
}
198+
199+
const Bar = class {
200+
static get a() {
201+
return this.val;
202+
}
203+
static set a(value) {
204+
this.val = value;
205+
}
206+
}
207+
```
208+
209+
### setBeforeGet
210+
211+
Examples of **incorrect** code for this rule with the `"setBeforeGet"` option:
212+
213+
```js
214+
/*eslint grouped-accessor-pairs: ["error", "setBeforeGet"]*/
215+
216+
var foo = {
217+
get a() {
218+
return this.val;
219+
},
220+
set a(value) {
221+
this.val = value;
222+
}
223+
};
224+
225+
class Foo {
226+
get a() {
227+
return this.val;
228+
}
229+
set a(value) {
230+
this.val = value;
231+
}
232+
}
233+
234+
const Bar = class {
235+
static get a() {
236+
return this.val;
237+
}
238+
static set a(value) {
239+
this.val = value;
240+
}
241+
}
242+
```
243+
244+
Examples of **correct** code for this rule with the `"setBeforeGet"` option:
245+
246+
```js
247+
/*eslint grouped-accessor-pairs: ["error", "setBeforeGet"]*/
248+
249+
var foo = {
250+
set a(value) {
251+
this.val = value;
252+
},
253+
get a() {
254+
return this.val;
255+
}
256+
};
257+
258+
class Foo {
259+
set a(value) {
260+
this.val = value;
261+
}
262+
get a() {
263+
return this.val;
264+
}
265+
}
266+
267+
const Bar = class {
268+
static set a(value) {
269+
this.val = value;
270+
}
271+
static get a() {
272+
return this.val;
273+
}
274+
}
275+
```
276+
277+
## Known Limitations
278+
279+
Due to the limits of static analysis, this rule does not account for possible side effects and in certain cases
280+
might require or miss to require grouping or order for getters/setters that have a computed key, like in the following example:
281+
282+
```js
283+
/*eslint grouped-accessor-pairs: "error"*/
284+
285+
var a = 1;
286+
287+
// false warning (false positive)
288+
var foo = {
289+
get [a++]() {
290+
return this.val;
291+
},
292+
b: 1,
293+
set [a++](value) {
294+
this.val = value;
295+
}
296+
};
297+
298+
// missed warning (false negative)
299+
var bar = {
300+
get [++a]() {
301+
return this.val;
302+
},
303+
b: 1,
304+
set [a](value) {
305+
this.val = value;
306+
}
307+
};
308+
```
309+
310+
Also, this rule does not report any warnings for properties that have duplicate getters or setters.
311+
312+
See [no-dupe-keys](no-dupe-keys.md) if you also want to disallow duplicate keys in object literals.
313+
314+
See [no-dupe-class-members](no-dupe-class-members.md) if you also want to disallow duplicate names in class definitions.
315+
316+
## Further Reading
317+
318+
* [Object Setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set)
319+
* [Object Getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)
320+
* [Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)
321+
322+
## Related Rules
323+
324+
* [accessor-pairs](accessor-pairs.md)
325+
* [no-dupe-keys](no-dupe-keys.md)
326+
* [no-dupe-class-members](no-dupe-class-members.md)

0 commit comments

Comments
 (0)