Skip to content

Commit 2143f34

Browse files
authored
feat: support AccessorProperty (#829)
1 parent c0a09fb commit 2143f34

24 files changed

+492
-103
lines changed

packages/eslint-plugin/rules/computed-property-spacing/computed-property-spacing.test.ts

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ import rule from './computed-property-spacing'
1010
run<RuleOptions, MessageIds>({
1111
name: 'computed-property-spacing',
1212
rule,
13-
1413
valid: [
15-
1614
// default - never
1715
'obj[foo]',
1816
'obj[\'foo\']',
@@ -72,106 +70,106 @@ run<RuleOptions, MessageIds>({
7270

7371
// explicitly disabled option
7472
{
75-
code: 'class A { [ a ](){} }',
73+
code: 'class A { [ a ](){} accessor [ b ] }',
7674
options: ['never', { enforceForClassMembers: false }],
7775
parserOptions: { ecmaVersion: 6 },
7876
},
7977
{
80-
code: 'A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }',
78+
code: 'A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} accessor [ g ] }',
8179
options: ['never', { enforceForClassMembers: false }],
8280
parserOptions: { ecmaVersion: 6 },
8381
},
8482
{
85-
code: 'A = class { [a](){} }',
83+
code: 'A = class { [a](){} accessor [b] = 1 }',
8684
options: ['always', { enforceForClassMembers: false }],
8785
parserOptions: { ecmaVersion: 6 },
8886
},
8987
{
90-
code: 'class A { [a](){} get [b](){} set [b](foo){} static [c](){} static get [d](){} static set [d](bar){} }',
88+
code: 'class A { [a](){} get [b](){} set [b](foo){} static [c](){} static get [d](){} static set [d](bar){} accessor [e] = 1 }',
9189
options: ['always', { enforceForClassMembers: false }],
9290
parserOptions: { ecmaVersion: 6 },
9391
},
9492
{
95-
code: 'class A { [ a ]; }',
93+
code: 'class A { [ a ]; accessor [ b ]; }',
9694
options: ['never', { enforceForClassMembers: false }],
9795
parserOptions: { ecmaVersion: 2022 },
9896
},
9997
{
100-
code: 'class A { [a]; }',
98+
code: 'class A { [a]; accessor [b]; }',
10199
options: ['always', { enforceForClassMembers: false }],
102100
parserOptions: { ecmaVersion: 2022 },
103101
},
104102

105103
// valid spacing
106104
{
107-
code: 'A = class { [a](){} }',
105+
code: 'A = class { [a](){} accessor [b] = 1 }',
108106
options: ['never', { enforceForClassMembers: true }],
109107
parserOptions: { ecmaVersion: 6 },
110108
},
111109
{
112-
code: 'class A { [a] ( ) { } }',
110+
code: 'class A { [a] ( ) { } accessor [b] = 1 }',
113111
options: ['never', { enforceForClassMembers: true }],
114112
parserOptions: { ecmaVersion: 6 },
115113
},
116114
{
117-
code: 'A = class { [ \n a \n ](){} }',
115+
code: 'A = class { [ \n a \n ](){} accessor [ \n b \n ] = 1 }',
118116
options: ['never', { enforceForClassMembers: true }],
119117
parserOptions: { ecmaVersion: 6 },
120118
},
121119
{
122-
code: 'class A { [a](){} get [b](){} set [b](foo){} static [c](){} static get [d](){} static set [d](bar){} }',
120+
code: 'class A { [a](){} get [b](){} set [b](foo){} static [c](){} static get [d](){} static set [d](bar){} accessor [e] = 1 }',
123121
options: ['never', { enforceForClassMembers: true }],
124122
parserOptions: { ecmaVersion: 6 },
125123
},
126124
{
127-
code: 'class A { [ a ](){} }',
125+
code: 'class A { [ a ](){} accessor [ b ] = 1 }',
128126
options: ['always', { enforceForClassMembers: true }],
129127
parserOptions: { ecmaVersion: 6 },
130128
},
131129
{
132-
code: 'class A { [ a ](){}[ b ](){} }',
130+
code: 'class A { [ a ](){}[ b ](){}\naccessor [ c ] = 1 }',
133131
options: ['always', { enforceForClassMembers: true }],
134132
parserOptions: { ecmaVersion: 6 },
135133
},
136134
{
137-
code: 'A = class { [\na\n](){} }',
135+
code: 'A = class { [\na\n](){} accessor [ b ] = 1 }',
138136
options: ['always', { enforceForClassMembers: true }],
139137
parserOptions: { ecmaVersion: 6 },
140138
},
141139
{
142-
code: 'A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} }',
140+
code: 'A = class { [ a ](){} get [ b ](){} set [ c ](foo){} static [ d ](){} static get [ e ](){} static set [ f ](bar){} accessor [ g ] = 1 }',
143141
options: ['always', { enforceForClassMembers: true }],
144142
parserOptions: { ecmaVersion: 6 },
145143
},
146144
{
147-
code: 'A = class { [a]; static [a]; [a] = 0; static [a] = 0; }',
145+
code: 'A = class { [a]; static [a]; [a] = 0; static [a] = 0; accessor [b] = 1 }',
148146
options: ['never', { enforceForClassMembers: true }],
149147
parserOptions: { ecmaVersion: 2022 },
150148
},
151149
{
152-
code: 'A = class { [ a ]; static [ a ]; [ a ] = 0; static [ a ] = 0; }',
150+
code: 'A = class { [ a ]; static [ a ]; [ a ] = 0; static [ a ] = 0; accessor [ b ] = 1 }',
153151
options: ['always', { enforceForClassMembers: true }],
154152
parserOptions: { ecmaVersion: 2022 },
155153
},
156154

157155
// non-computed
158156
{
159-
code: 'class A { a ( ) { } get b(){} set b ( foo ){} static c (){} static get d() {} static set d( bar ) {} }',
157+
code: 'class A { a ( ) { } get b(){} set b ( foo ){} static c (){} static get d() {} static set d( bar ) {} accessor e = 1 }',
160158
options: ['never', { enforceForClassMembers: true }],
161159
parserOptions: { ecmaVersion: 6 },
162160
},
163161
{
164-
code: 'A = class {a(){}get b(){}set b(foo){}static c(){}static get d(){}static set d(bar){}}',
162+
code: 'A = class {a(){}get b(){}set b(foo){}static c(){}static get d(){}static set d(bar){} accessor e = 1}',
165163
options: ['always', { enforceForClassMembers: true }],
166164
parserOptions: { ecmaVersion: 6 },
167165
},
168166
{
169-
code: 'A = class { foo; #a; static #b; #c = 0; static #d = 0; }',
167+
code: 'A = class { foo; #a; static #b; #c = 0; static #d = 0; accessor e = 1; }',
170168
options: ['never', { enforceForClassMembers: true }],
171169
parserOptions: { ecmaVersion: 2022 },
172170
},
173171
{
174-
code: 'A = class { foo; #a; static #b; #c = 0; static #d = 0; }',
172+
code: 'A = class { foo; #a; static #b; #c = 0; static #d = 0; accessor e = 1; }',
175173
options: ['always', { enforceForClassMembers: true }],
176174
parserOptions: { ecmaVersion: 2022 },
177175
},
@@ -1450,6 +1448,15 @@ run<RuleOptions, MessageIds>({
14501448
},
14511449
],
14521450
},
1451+
{
1452+
code: 'class A { accessor [ a ] = 0 }',
1453+
output: 'class A { accessor [a] = 0 }',
1454+
options: ['never', { enforceForClassMembers: true }],
1455+
errors: [
1456+
{ messageId: 'unexpectedSpaceAfter', column: 21, endColumn: 22 },
1457+
{ messageId: 'unexpectedSpaceBefore', column: 23, endColumn: 24 },
1458+
],
1459+
},
14531460

14541461
// always - classes
14551462
{
@@ -1694,6 +1701,15 @@ run<RuleOptions, MessageIds>({
16941701
},
16951702
],
16961703
},
1704+
{
1705+
code: 'class A { accessor [a] = 0 }',
1706+
output: 'class A { accessor [ a ] = 0 }',
1707+
options: ['always', { enforceForClassMembers: true }],
1708+
errors: [
1709+
{ messageId: 'missingSpaceAfter', column: 20, endColumn: 21 },
1710+
{ messageId: 'missingSpaceBefore', column: 22, endColumn: 23 },
1711+
],
1712+
},
16971713

16981714
// handling of parens and comments
16991715
{

packages/eslint-plugin/rules/computed-property-spacing/computed-property-spacing.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ export default createRule<RuleOptions, MessageIds>({
177177
type NodeType
178178
= | Tree.Property
179179
| Tree.PropertyDefinition
180+
| Tree.AccessorProperty
180181
| Tree.MemberExpression
181182
| Tree.MethodDefinition
182183

@@ -188,6 +189,7 @@ export default createRule<RuleOptions, MessageIds>({
188189
if (enforceForClassMembers) {
189190
listeners.MethodDefinition = checkSpacing<Tree.MethodDefinition>('key')
190191
listeners.PropertyDefinition = checkSpacing<Tree.PropertyDefinition>('key')
192+
listeners.AccessorProperty = checkSpacing<Tree.AccessorProperty>('key')
191193
}
192194

193195
return listeners

packages/eslint-plugin/rules/indent/indent._ts_.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,15 @@ run<RuleOptions, MessageIds>({
767767
type Bar = boolean
768768
}
769769
`,
770+
{
771+
code: $`
772+
class Foo {
773+
accessor [bar]: string
774+
accessor baz: number
775+
}
776+
`,
777+
options: [2],
778+
},
770779
{
771780
code: $`
772781
using a = foo(),
@@ -2060,6 +2069,25 @@ declare function h(x: number): number;
20602069
},
20612070
],
20622071
},
2072+
{
2073+
code: $`
2074+
class Foo {
2075+
accessor [bar]: string
2076+
accessor baz: number
2077+
}
2078+
`,
2079+
output: $`
2080+
class Foo {
2081+
accessor [bar]: string
2082+
accessor baz: number
2083+
}
2084+
`,
2085+
options: [2],
2086+
errors: [
2087+
{ messageId: 'wrongIndentation', data: { expected: '2 spaces', actual: 0 } },
2088+
{ messageId: 'wrongIndentation', data: { expected: '2 spaces', actual: 4 } },
2089+
],
2090+
},
20632091
{
20642092
code: $`
20652093
type A = number

packages/eslint-plugin/rules/indent/indent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const KNOWN_NODES = new Set([
5151
'Program',
5252
'Property',
5353
'PropertyDefinition',
54+
AST_NODE_TYPES.AccessorProperty,
5455
'RestElement',
5556
'ReturnStatement',
5657
'SequenceExpression',

packages/eslint-plugin/rules/keyword-spacing/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ However, if you want to enforce the style of following spacing cases, please ref
2929

3030
## Rule Details
3131

32-
This rule enforces consistent spacing around keywords and keyword-like tokens: `as` (in module declarations), `async` (of async functions), `await` (of await expressions), `break`, `case`, `catch`, `class`, `const`, `continue`, `debugger`, `default`, `delete`, `do`, `else`, `export`, `extends`, `finally`, `for`, `from` (in module declarations), `function`, `get` (of getters), `if`, `import`, `in` (in for-in statements), `let`, `new`, `of` (in for-of statements), `return`, `set` (of setters), `static`, `super`, `switch`, `this`, `throw`, `try`, `typeof`, `using`, `var`, `void`, `while`, `with`, and `yield`. This rule is designed carefully not to conflict with other spacing rules: it does not apply to spacing where other rules report problems.
32+
This rule enforces consistent spacing around keywords and keyword-like tokens: `accessor` (of accessor property), `as` (in module declarations), `async` (of async functions), `await` (of await expressions), `break`, `case`, `catch`, `class`, `const`, `continue`, `debugger`, `default`, `delete`, `do`, `else`, `export`, `extends`, `finally`, `for`, `from` (in module declarations), `function`, `get` (of getters), `if`, `import`, `in` (in for-in statements), `let`, `new`, `of` (in for-of statements), `return`, `set` (of setters), `static`, `super`, `switch`, `this`, `throw`, `try`, `typeof`, `using`, `var`, `void`, `while`, `with`, and `yield`. This rule is designed carefully not to conflict with other spacing rules: it does not apply to spacing where other rules report problems.
3333

3434
## Options
3535

packages/eslint-plugin/rules/keyword-spacing/keyword-spacing._ts_.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ run<RuleOptions, MessageIds>({
215215
options: [BOTH],
216216
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
217217
},
218+
{
219+
code: 'class C { @readonly accessor foo = 1 }',
220+
options: [NEITHER],
221+
},
218222
{
219223
code: 'export type { foo } from "foo";',
220224
options: [BOTH],
@@ -386,6 +390,12 @@ run<RuleOptions, MessageIds>({
386390
options: [{ overrides: { satisfies: {} } }],
387391
errors: expectedAfter('satisfies'),
388392
},
393+
{
394+
code: 'class C { @readonly() accessor foo = 1 }',
395+
output: 'class C { @readonly()accessor foo = 1 }',
396+
options: [NEITHER],
397+
errors: unexpectedBefore('accessor'),
398+
},
389399
{
390400
code: 'import type{ foo } from "foo";',
391401
output: 'import type { foo } from "foo";',

packages/eslint-plugin/rules/keyword-spacing/keyword-spacing.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const NEXT_TOKEN_M = /^[{*]$/u
1111
const TEMPLATE_OPEN_PAREN = /\$\{$/u
1212
const TEMPLATE_CLOSE_PAREN = /^\}/u
1313
const CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template|PrivateIdentifier)$/u
14-
const KEYS = KEYWORDS_JS.concat(['as', 'async', 'await', 'from', 'get', 'let', 'of', 'satisfies', 'set', 'using', 'yield', 'type'])
14+
const KEYS = KEYWORDS_JS.concat(['accessor', 'as', 'async', 'await', 'from', 'get', 'let', 'of', 'satisfies', 'set', 'using', 'yield', 'type'])
1515

1616
export default createRule<RuleOptions, MessageIds>({
1717
name: 'keyword-spacing',
@@ -443,12 +443,12 @@ export default createRule<RuleOptions, MessageIds>({
443443
}
444444

445445
/**
446-
* Reports `static`, `get`, and `set` keywords of a given node if usage of
446+
* Reports `accessor`, `static`, `get`, and `set` keywords of a given node if usage of
447447
* spacing around those keywords is invalid.
448448
* @param node A node to report.
449449
* @throws {Error} If unable to find token get, set, or async beside method name.
450450
*/
451-
function checkSpacingForProperty(node: Tree.MethodDefinition | Tree.PropertyDefinition | Tree.Property) {
451+
function checkSpacingForProperty(node: Tree.MethodDefinition | Tree.PropertyDefinition | Tree.AccessorProperty | Tree.Property) {
452452
if ('static' in node && node.static)
453453
checkSpacingAroundFirstToken(node)
454454

@@ -458,6 +458,7 @@ export default createRule<RuleOptions, MessageIds>({
458458
(('method' in node && node.method) || node.type === 'MethodDefinition')
459459
&& 'async' in node.value && node.value.async
460460
)
461+
|| node.type === AST_NODE_TYPES.AccessorProperty
461462
) {
462463
const token = sourceCode.getTokenBefore(
463464
node.key,
@@ -466,6 +467,7 @@ export default createRule<RuleOptions, MessageIds>({
466467
case 'get':
467468
case 'set':
468469
case 'async':
470+
case 'accessor':
469471
return true
470472
default:
471473
return false
@@ -602,6 +604,7 @@ export default createRule<RuleOptions, MessageIds>({
602604
},
603605
MethodDefinition: checkSpacingForProperty,
604606
PropertyDefinition: checkSpacingForProperty,
607+
AccessorProperty: checkSpacingForProperty,
605608
StaticBlock: checkSpacingAroundFirstToken,
606609
Property: checkSpacingForProperty,
607610

packages/eslint-plugin/rules/no-extra-parens/no-extra-parens._ts_.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,5 +479,10 @@ run<RuleOptions, MessageIds>({
479479
},
480480
],
481481
},
482+
{
483+
code: 'class A{ accessor [((foo))] = 1 }',
484+
output: 'class A{ accessor [(foo)] = 1 }',
485+
errors: [{ messageId: 'unexpected' }],
486+
},
482487
],
483488
})

packages/eslint-plugin/rules/no-extra-parens/no-extra-parens.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,14 @@ export default createRule<RuleOptions, MessageIds>({
908908
return checkArgumentWithPrecedence(node)
909909
}
910910

911+
function checkClassProperty(node: Tree.PropertyDefinition | Tree.AccessorProperty) {
912+
if (node.computed && hasExcessParensWithPrecedence(node.key, PRECEDENCE_OF_ASSIGNMENT_EXPR))
913+
report(node.key)
914+
915+
if (node.value && hasExcessParensWithPrecedence(node.value, PRECEDENCE_OF_ASSIGNMENT_EXPR))
916+
report(node.value)
917+
}
918+
911919
return {
912920
ArrayExpression(node) {
913921
node.elements
@@ -1339,13 +1347,8 @@ export default createRule<RuleOptions, MessageIds>({
13391347
report(key)
13401348
}
13411349
},
1342-
PropertyDefinition(node) {
1343-
if (node.computed && hasExcessParensWithPrecedence(node.key, PRECEDENCE_OF_ASSIGNMENT_EXPR))
1344-
report(node.key)
1345-
1346-
if (node.value && hasExcessParensWithPrecedence(node.value, PRECEDENCE_OF_ASSIGNMENT_EXPR))
1347-
report(node.value)
1348-
},
1350+
'PropertyDefinition': checkClassProperty,
1351+
'AccessorProperty': checkClassProperty,
13491352
RestElement(node) {
13501353
const argument = node.argument
13511354

0 commit comments

Comments
 (0)