Skip to content

Commit a95d3fa

Browse files
committed
feat(sort-jsx-props): adds newlinesBetween
1 parent 69edb80 commit a95d3fa

File tree

2 files changed

+94
-26
lines changed

2 files changed

+94
-26
lines changed

docs/content/rules/sort-jsx-props.mdx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,25 @@ Within a given group, members will be sorted according to the `type`, `order`, `
225225
Individual groups can be combined together by placing them in an array. The order of groups in that array does not matter.
226226
All members of the groups in the array will be sorted together as if they were part of a single group.
227227

228+
#### Newlines between groups
229+
230+
You may place `newlinesBetween` objects between your groups to enforce the newline behavior between two specific groups.
231+
232+
See the [`newlinesBetween`](#newlinesbetween) option.
233+
234+
This feature is only applicable when `partitionByNewLine` is false.
235+
236+
```ts
237+
{
238+
newlinesBetween: 'always',
239+
groups: [
240+
'a',
241+
{ newlinesBetween: 'never' }, // Overrides the global newlinesBetween option
242+
'b',
243+
]
244+
}
245+
```
246+
228247
### customGroups
229248

230249
<sub>
@@ -280,6 +299,7 @@ Custom group matching takes precedence over predefined group matching.
280299
ignoreCase: true,
281300
specialCharacters: 'keep',
282301
ignorePattern: [],
302+
newlinesBetween: 'ignore',
283303
groups: [],
284304
customGroups: {},
285305
},
@@ -307,6 +327,7 @@ Custom group matching takes precedence over predefined group matching.
307327
ignoreCase: true,
308328
specialCharacters: 'keep',
309329
ignorePattern: [],
330+
newlinesBetween: 'ignore',
310331
groups: [],
311332
customGroups: {},
312333
},

rules/sort-jsx-props.ts

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { SortingNode } from '../types/sorting-node'
44

55
import {
66
specialCharactersJsonSchema,
7+
newlinesBetweenJsonSchema,
78
customGroupsJsonSchema,
89
ignoreCaseJsonSchema,
910
buildTypeJsonSchema,
@@ -18,6 +19,8 @@ import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines'
1819
import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled'
1920
import { createNodeIndexMap } from '../utils/create-node-index-map'
2021
import { sortNodesByGroups } from '../utils/sort-nodes-by-groups'
22+
import { getNewlinesErrors } from '../utils/get-newlines-errors'
23+
import { makeNewlinesFixes } from '../utils/make-newlines-fixes'
2124
import { createEslintRule } from '../utils/create-eslint-rule'
2225
import { getGroupNumber } from '../utils/get-group-number'
2326
import { getSourceCode } from '../utils/get-source-code'
@@ -32,28 +35,38 @@ import { matches } from '../utils/matches'
3235

3336
type Options<T extends string[]> = [
3437
Partial<{
38+
groups: (
39+
| { newlinesBetween: 'ignore' | 'always' | 'never' }
40+
| Group<T>[]
41+
| Group<T>
42+
)[]
3543
type: 'alphabetical' | 'line-length' | 'natural' | 'custom'
3644
customGroups: Record<T[number], string[] | string>
45+
newlinesBetween: 'ignore' | 'always' | 'never'
3746
specialCharacters: 'remove' | 'trim' | 'keep'
3847
locales: NonNullable<Intl.LocalesArgument>
39-
groups: (Group<T>[] | Group<T>)[]
4048
ignorePattern: string[]
4149
order: 'desc' | 'asc'
4250
ignoreCase: boolean
4351
alphabet: string
4452
}>,
4553
]
4654

55+
type MESSAGE_ID =
56+
| 'missedSpacingBetweenJSXPropsMembers'
57+
| 'extraSpacingBetweenJSXPropsMembers'
58+
| 'unexpectedJSXPropsGroupOrder'
59+
| 'unexpectedJSXPropsOrder'
60+
4761
type Group<T extends string[]> =
4862
| 'multiline'
4963
| 'shorthand'
5064
| 'unknown'
5165
| T[number]
5266

53-
type MESSAGE_ID = 'unexpectedJSXPropsGroupOrder' | 'unexpectedJSXPropsOrder'
54-
5567
let defaultOptions: Required<Options<string[]>[0]> = {
5668
specialCharacters: 'keep',
69+
newlinesBetween: 'ignore',
5770
type: 'alphabetical',
5871
ignorePattern: [],
5972
ignoreCase: true,
@@ -158,35 +171,64 @@ export default createEslintRule<Options<string[]>, MESSAGE_ID>({
158171

159172
let indexOfRightExcludingEslintDisabled =
160173
sortedNodesExcludingEslintDisabled.indexOf(right)
161-
if (
162-
leftIndex < rightIndex &&
163-
leftIndex < indexOfRightExcludingEslintDisabled
164-
) {
165-
return
166-
}
167174

168175
let leftNumber = getGroupNumber(options.groups, left)
169176
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(
185185
leftNumber === rightNumber
186186
? 'unexpectedJSXPropsOrder'
187187
: '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+
}
190232
})
191233
}
192234
},
@@ -204,6 +246,7 @@ export default createEslintRule<Options<string[]>, MESSAGE_ID>({
204246
type: 'array',
205247
},
206248
specialCharacters: specialCharactersJsonSchema,
249+
newlinesBetween: newlinesBetweenJsonSchema,
207250
customGroups: customGroupsJsonSchema,
208251
ignoreCase: ignoreCaseJsonSchema,
209252
alphabet: alphabetJsonSchema,
@@ -219,6 +262,10 @@ export default createEslintRule<Options<string[]>, MESSAGE_ID>({
219262
messages: {
220263
unexpectedJSXPropsGroupOrder:
221264
'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.',
222269
unexpectedJSXPropsOrder:
223270
'Expected "{{right}}" to come before "{{left}}".',
224271
},

0 commit comments

Comments
 (0)