@@ -4,6 +4,7 @@ import type { SortingNode } from '../types/sorting-node'
4
4
5
5
import {
6
6
specialCharactersJsonSchema ,
7
+ newlinesBetweenJsonSchema ,
7
8
customGroupsJsonSchema ,
8
9
ignoreCaseJsonSchema ,
9
10
buildTypeJsonSchema ,
@@ -18,6 +19,8 @@ import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines'
18
19
import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled'
19
20
import { createNodeIndexMap } from '../utils/create-node-index-map'
20
21
import { sortNodesByGroups } from '../utils/sort-nodes-by-groups'
22
+ import { getNewlinesErrors } from '../utils/get-newlines-errors'
23
+ import { makeNewlinesFixes } from '../utils/make-newlines-fixes'
21
24
import { createEslintRule } from '../utils/create-eslint-rule'
22
25
import { getGroupNumber } from '../utils/get-group-number'
23
26
import { getSourceCode } from '../utils/get-source-code'
@@ -32,28 +35,38 @@ import { matches } from '../utils/matches'
32
35
33
36
type Options < T extends string [ ] > = [
34
37
Partial < {
38
+ groups : (
39
+ | { newlinesBetween : 'ignore' | 'always' | 'never' }
40
+ | Group < T > [ ]
41
+ | Group < T >
42
+ ) [ ]
35
43
type : 'alphabetical' | 'line-length' | 'natural' | 'custom'
36
44
customGroups : Record < T [ number ] , string [ ] | string >
45
+ newlinesBetween : 'ignore' | 'always' | 'never'
37
46
specialCharacters : 'remove' | 'trim' | 'keep'
38
47
locales : NonNullable < Intl . LocalesArgument >
39
- groups : ( Group < T > [ ] | Group < T > ) [ ]
40
48
ignorePattern : string [ ]
41
49
order : 'desc' | 'asc'
42
50
ignoreCase : boolean
43
51
alphabet : string
44
52
} > ,
45
53
]
46
54
55
+ type MESSAGE_ID =
56
+ | 'missedSpacingBetweenJSXPropsMembers'
57
+ | 'extraSpacingBetweenJSXPropsMembers'
58
+ | 'unexpectedJSXPropsGroupOrder'
59
+ | 'unexpectedJSXPropsOrder'
60
+
47
61
type Group < T extends string [ ] > =
48
62
| 'multiline'
49
63
| 'shorthand'
50
64
| 'unknown'
51
65
| T [ number ]
52
66
53
- type MESSAGE_ID = 'unexpectedJSXPropsGroupOrder' | 'unexpectedJSXPropsOrder'
54
-
55
67
let defaultOptions : Required < Options < string [ ] > [ 0 ] > = {
56
68
specialCharacters : 'keep' ,
69
+ newlinesBetween : 'ignore' ,
57
70
type : 'alphabetical' ,
58
71
ignorePattern : [ ] ,
59
72
ignoreCase : true ,
@@ -158,35 +171,64 @@ export default createEslintRule<Options<string[]>, MESSAGE_ID>({
158
171
159
172
let indexOfRightExcludingEslintDisabled =
160
173
sortedNodesExcludingEslintDisabled . indexOf ( right )
161
- if (
162
- leftIndex < rightIndex &&
163
- leftIndex < indexOfRightExcludingEslintDisabled
164
- ) {
165
- return
166
- }
167
174
168
175
let leftNumber = getGroupNumber ( options . groups , left )
169
176
let rightNumber = getGroupNumber ( options . groups , right )
170
- context . report ( {
171
- fix : fixer =>
172
- makeFixes ( {
173
- sortedNodes : sortedNodesExcludingEslintDisabled ,
174
- sourceCode,
175
- fixer,
176
- nodes,
177
- } ) ,
178
- data : {
179
- rightGroup : right . group ,
180
- leftGroup : left . group ,
181
- right : right . name ,
182
- left : left . name ,
183
- } ,
184
- messageId :
177
+
178
+ let messageIds : MESSAGE_ID [ ] = [ ]
179
+
180
+ if (
181
+ leftIndex > rightIndex ||
182
+ leftIndex >= indexOfRightExcludingEslintDisabled
183
+ ) {
184
+ messageIds . push (
185
185
leftNumber === rightNumber
186
186
? 'unexpectedJSXPropsOrder'
187
187
: 'unexpectedJSXPropsGroupOrder' ,
188
- node : right . node ,
189
- } )
188
+ )
189
+ }
190
+
191
+ messageIds = [
192
+ ...messageIds ,
193
+ ...getNewlinesErrors ( {
194
+ missedSpacingError : 'missedSpacingBetweenJSXPropsMembers' ,
195
+ extraSpacingError : 'extraSpacingBetweenJSXPropsMembers' ,
196
+ rightNum : rightNumber ,
197
+ leftNum : leftNumber ,
198
+ sourceCode,
199
+ options,
200
+ right,
201
+ left,
202
+ } ) ,
203
+ ]
204
+
205
+ for ( let messageId of messageIds ) {
206
+ context . report ( {
207
+ fix : fixer => [
208
+ ...makeFixes ( {
209
+ sortedNodes : sortedNodesExcludingEslintDisabled ,
210
+ sourceCode,
211
+ fixer,
212
+ nodes,
213
+ } ) ,
214
+ ...makeNewlinesFixes ( {
215
+ sortedNodes : sortedNodesExcludingEslintDisabled ,
216
+ sourceCode,
217
+ options,
218
+ fixer,
219
+ nodes,
220
+ } ) ,
221
+ ] ,
222
+ data : {
223
+ rightGroup : right . group ,
224
+ leftGroup : left . group ,
225
+ right : right . name ,
226
+ left : left . name ,
227
+ } ,
228
+ node : right . node ,
229
+ messageId,
230
+ } )
231
+ }
190
232
} )
191
233
}
192
234
} ,
@@ -204,6 +246,7 @@ export default createEslintRule<Options<string[]>, MESSAGE_ID>({
204
246
type : 'array' ,
205
247
} ,
206
248
specialCharacters : specialCharactersJsonSchema ,
249
+ newlinesBetween : newlinesBetweenJsonSchema ,
207
250
customGroups : customGroupsJsonSchema ,
208
251
ignoreCase : ignoreCaseJsonSchema ,
209
252
alphabet : alphabetJsonSchema ,
@@ -219,6 +262,10 @@ export default createEslintRule<Options<string[]>, MESSAGE_ID>({
219
262
messages : {
220
263
unexpectedJSXPropsGroupOrder :
221
264
'Expected "{{right}}" ({{rightGroup}}) to come before "{{left}}" ({{leftGroup}}).' ,
265
+ missedSpacingBetweenJSXPropsMembers :
266
+ 'Missed spacing between "{{left}}" and "{{right}}" props.' ,
267
+ extraSpacingBetweenJSXPropsMembers :
268
+ 'Extra spacing between "{{left}}" and "{{right}}" props.' ,
222
269
unexpectedJSXPropsOrder :
223
270
'Expected "{{right}}" to come before "{{left}}".' ,
224
271
} ,
0 commit comments