Skip to content

Commit 1dc74f8

Browse files
committed
feat: add newlinesBetween option
1 parent 95619ca commit 1dc74f8

8 files changed

Lines changed: 1170 additions & 12 deletions

File tree

docs/content/rules/sort-named-exports.mdx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Specifies the sorting method.
107107
- `'natural'` — Sort items in a [natural](https://github.com/yobacca/natural-orderby) order (e.g., “item2” < “item10”).
108108
- `'line-length'` — Sort items by the length of the code line (shorter lines first).
109109
- `'custom'` — Sort items using the alphabet entered in the [`alphabet`](#alphabet) option.
110-
- `'unsorted'` — Do not sort items.
110+
- `'unsorted'` — Do not sort items. [`grouping`](#groups) and [`newlines behavior`](#newlinesbetween) are still enforced.
111111

112112
### order
113113

@@ -242,6 +242,22 @@ export {
242242

243243
Each group of members (separated by empty lines) is treated independently, and the order within each group is preserved.
244244

245+
### newlinesBetween
246+
247+
<sub>default: `'ignore'`</sub>
248+
249+
Specifies how new lines should be handled between groups.
250+
251+
- `ignore` — Do not report errors related to new lines.
252+
- `always` — Enforce one new line between each group, and forbid new lines inside a group.
253+
- `never` — No new lines are allowed.
254+
255+
You can also enforce the newline behavior between two specific groups through the `groups` options.
256+
257+
See the [`groups`](#newlines-between-groups) option.
258+
259+
This option is only applicable when `partitionByNewLine` is `false`.
260+
245261
### groups
246262

247263
<sub>
@@ -279,6 +295,25 @@ Example: `type-export`.
279295
Members that don’t fit into any group specified in the `groups` option will be placed in the `unknown` group. If the `unknown` group is not specified in the `groups` option,
280296
it will automatically be added to the end of the list.
281297

298+
##### Newlines between groups
299+
300+
You may place `newlinesBetween` objects between your groups to enforce the newline behavior between two specific groups.
301+
302+
See the [`newlinesBetween`](#newlinesbetween) option.
303+
304+
This feature is only applicable when `partitionByNewLine` is false.
305+
306+
```ts
307+
{
308+
newlinesBetween: 'always',
309+
groups: [
310+
'a',
311+
{ newlinesBetween: 'never' }, // Overrides the global newlinesBetween option
312+
'b',
313+
]
314+
}
315+
```
316+
282317
### customGroups
283318

284319
<sub>
@@ -366,6 +401,7 @@ Custom groups have a higher priority than any predefined group.
366401
groupKind: 'mixed',
367402
partitionByNewLine: false,
368403
partitionByComment: false,
404+
newlinesBetween: 'ignore',
369405
groups: [],
370406
customGroups: [],
371407
},
@@ -397,6 +433,7 @@ Custom groups have a higher priority than any predefined group.
397433
groupKind: 'mixed',
398434
partitionByNewLine: false,
399435
partitionByComment: false,
436+
newlinesBetween: 'ignore',
400437
groups: [],
401438
customGroups: [],
402439
},

docs/content/rules/sort-named-imports.mdx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ Specifies the sorting method.
108108
- `'natural'` — Sort items in a [natural](https://github.com/yobacca/natural-orderby) order (e.g., “item2” < “item10”).
109109
- `'line-length'` — Sort items by the length of the code line (shorter lines first).
110110
- `'custom'` — Sort items using the alphabet entered in the [`alphabet`](#alphabet) option.
111-
- `'unsorted'` — Do not sort items.
111+
- `'unsorted'` — Do not sort items. [`grouping`](#groups) and [`newlines behavior`](#newlinesbetween) are still enforced.
112112

113113
### order
114114

@@ -241,6 +241,22 @@ import {
241241
} from './devices'
242242
```
243243

244+
### newlinesBetween
245+
246+
<sub>default: `'ignore'`</sub>
247+
248+
Specifies how new lines should be handled between groups.
249+
250+
- `ignore` — Do not report errors related to new lines.
251+
- `always` — Enforce one new line between each group, and forbid new lines inside a group.
252+
- `never` — No new lines are allowed.
253+
254+
You can also enforce the newline behavior between two specific groups through the `groups` options.
255+
256+
See the [`groups`](#newlines-between-groups) option.
257+
258+
This option is only applicable when `partitionByNewLine` is `false`.
259+
244260
### groups
245261

246262
<sub>
@@ -278,6 +294,25 @@ Example: `type-import`.
278294
Members that don’t fit into any group specified in the `groups` option will be placed in the `unknown` group. If the `unknown` group is not specified in the `groups` option,
279295
it will automatically be added to the end of the list.
280296

297+
##### Newlines between groups
298+
299+
You may place `newlinesBetween` objects between your groups to enforce the newline behavior between two specific groups.
300+
301+
See the [`newlinesBetween`](#newlinesbetween) option.
302+
303+
This feature is only applicable when `partitionByNewLine` is false.
304+
305+
```ts
306+
{
307+
newlinesBetween: 'always',
308+
groups: [
309+
'a',
310+
{ newlinesBetween: 'never' }, // Overrides the global newlinesBetween option
311+
'b',
312+
]
313+
}
314+
```
315+
281316
### customGroups
282317

283318
<sub>
@@ -365,6 +400,7 @@ Custom groups have a higher priority than any predefined group.
365400
groupKind: 'mixed',
366401
partitionByNewLine: false,
367402
partitionByComment: false,
403+
newlinesBetween: 'ignore',
368404
groups: [],
369405
customGroups: [],
370406
},
@@ -396,6 +432,7 @@ Custom groups have a higher priority than any predefined group.
396432
groupKind: 'mixed',
397433
partitionByNewLine: false,
398434
partitionByComment: false,
435+
newlinesBetween: 'ignore',
399436
groups: [],
400437
customGroups: [],
401438
},

rules/sort-named-exports.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,17 @@ import {
99
buildCustomGroupsArrayJsonSchema,
1010
partitionByCommentJsonSchema,
1111
partitionByNewLineJsonSchema,
12+
newlinesBetweenJsonSchema,
1213
commonJsonSchemas,
1314
groupsJsonSchema,
1415
} from '../utils/common-json-schemas'
16+
import {
17+
MISSED_SPACING_ERROR,
18+
EXTRA_SPACING_ERROR,
19+
GROUP_ORDER_ERROR,
20+
ORDER_ERROR,
21+
} from '../utils/report-errors'
22+
import { validateNewlinesAndPartitionConfiguration } from '../utils/validate-newlines-and-partition-configuration'
1523
import {
1624
singleCustomGroupJsonSchema,
1725
allModifiers,
@@ -23,7 +31,6 @@ import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-c
2331
import { generatePredefinedGroups } from '../utils/generate-predefined-groups'
2432
import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines'
2533
import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled'
26-
import { GROUP_ORDER_ERROR, ORDER_ERROR } from '../utils/report-errors'
2734
import { doesCustomGroupMatch } from '../utils/does-custom-group-match'
2835
import { sortNodesByGroups } from '../utils/sort-nodes-by-groups'
2936
import { createEslintRule } from '../utils/create-eslint-rule'
@@ -37,6 +44,8 @@ import { complete } from '../utils/complete'
3744

3845
type MESSAGE_ID =
3946
| 'unexpectedNamedExportsGroupOrder'
47+
| 'missedSpacingBetweenNamedExports'
48+
| 'extraSpacingBetweenNamedExports'
4049
| 'unexpectedNamedExportsOrder'
4150

4251
/**
@@ -49,6 +58,7 @@ let defaultOptions: Required<Options[0]> = {
4958
specialCharacters: 'keep',
5059
partitionByNewLine: false,
5160
partitionByComment: false,
61+
newlinesBetween: 'ignore',
5262
type: 'alphabetical',
5363
ignoreAlias: false,
5464
groupKind: 'mixed',
@@ -75,6 +85,7 @@ export default createEslintRule<Options, MESSAGE_ID>({
7585
selectors: allSelectors,
7686
options,
7787
})
88+
validateNewlinesAndPartitionConfiguration(options)
7889

7990
let { sourceCode, id } = context
8091
let eslintDisabledLines = getEslintDisabledLines({
@@ -186,6 +197,8 @@ export default createEslintRule<Options, MESSAGE_ID>({
186197

187198
reportAllErrors<MESSAGE_ID>({
188199
availableMessageIds: {
200+
missedSpacingBetweenMembers: 'missedSpacingBetweenNamedExports',
201+
extraSpacingBetweenMembers: 'extraSpacingBetweenNamedExports',
189202
unexpectedGroupOrder: 'unexpectedNamedExportsGroupOrder',
190203
unexpectedOrder: 'unexpectedNamedExportsOrder',
191204
},
@@ -217,6 +230,7 @@ export default createEslintRule<Options, MESSAGE_ID>({
217230
}),
218231
partitionByComment: partitionByCommentJsonSchema,
219232
partitionByNewLine: partitionByNewLineJsonSchema,
233+
newlinesBetween: newlinesBetweenJsonSchema,
220234
groups: groupsJsonSchema,
221235
},
222236
additionalProperties: false,
@@ -225,15 +239,17 @@ export default createEslintRule<Options, MESSAGE_ID>({
225239
uniqueItems: true,
226240
type: 'array',
227241
},
242+
messages: {
243+
missedSpacingBetweenNamedExports: MISSED_SPACING_ERROR,
244+
extraSpacingBetweenNamedExports: EXTRA_SPACING_ERROR,
245+
unexpectedNamedExportsGroupOrder: GROUP_ORDER_ERROR,
246+
unexpectedNamedExportsOrder: ORDER_ERROR,
247+
},
228248
docs: {
229249
url: 'https://perfectionist.dev/rules/sort-named-exports',
230250
description: 'Enforce sorted named exports.',
231251
recommended: true,
232252
},
233-
messages: {
234-
unexpectedNamedExportsGroupOrder: GROUP_ORDER_ERROR,
235-
unexpectedNamedExportsOrder: ORDER_ERROR,
236-
},
237253
type: 'suggestion',
238254
fixable: 'code',
239255
},

rules/sort-named-exports/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { TSESTree } from '@typescript-eslint/types'
33

44
import type {
55
PartitionByCommentOption,
6+
NewlinesBetweenOption,
67
CustomGroupsOption,
78
CommonOptions,
89
GroupsOptions,
@@ -25,6 +26,7 @@ export type Options = Partial<
2526
groupKind: 'values-first' | 'types-first' | 'mixed'
2627
customGroups: CustomGroupsOption<SingleCustomGroup>
2728
partitionByComment: PartitionByCommentOption
29+
newlinesBetween: NewlinesBetweenOption
2830
groups: GroupsOptions<Group>
2931
partitionByNewLine: boolean
3032
ignoreAlias: boolean

rules/sort-named-imports.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,17 @@ import {
99
buildCustomGroupsArrayJsonSchema,
1010
partitionByCommentJsonSchema,
1111
partitionByNewLineJsonSchema,
12+
newlinesBetweenJsonSchema,
1213
commonJsonSchemas,
1314
groupsJsonSchema,
1415
} from '../utils/common-json-schemas'
16+
import {
17+
MISSED_SPACING_ERROR,
18+
EXTRA_SPACING_ERROR,
19+
GROUP_ORDER_ERROR,
20+
ORDER_ERROR,
21+
} from '../utils/report-errors'
22+
import { validateNewlinesAndPartitionConfiguration } from '../utils/validate-newlines-and-partition-configuration'
1523
import {
1624
singleCustomGroupJsonSchema,
1725
allModifiers,
@@ -23,7 +31,6 @@ import { validateCustomSortConfiguration } from '../utils/validate-custom-sort-c
2331
import { generatePredefinedGroups } from '../utils/generate-predefined-groups'
2432
import { getEslintDisabledLines } from '../utils/get-eslint-disabled-lines'
2533
import { isNodeEslintDisabled } from '../utils/is-node-eslint-disabled'
26-
import { GROUP_ORDER_ERROR, ORDER_ERROR } from '../utils/report-errors'
2734
import { doesCustomGroupMatch } from '../utils/does-custom-group-match'
2835
import { sortNodesByGroups } from '../utils/sort-nodes-by-groups'
2936
import { createEslintRule } from '../utils/create-eslint-rule'
@@ -37,6 +44,8 @@ import { complete } from '../utils/complete'
3744

3845
type MESSAGE_ID =
3946
| 'unexpectedNamedImportsGroupOrder'
47+
| 'missedSpacingBetweenNamedImports'
48+
| 'extraSpacingBetweenNamedImports'
4049
| 'unexpectedNamedImportsOrder'
4150

4251
/**
@@ -49,6 +58,7 @@ let defaultOptions: Required<Options[0]> = {
4958
specialCharacters: 'keep',
5059
partitionByNewLine: false,
5160
partitionByComment: false,
61+
newlinesBetween: 'ignore',
5262
type: 'alphabetical',
5363
ignoreAlias: false,
5464
groupKind: 'mixed',
@@ -78,6 +88,7 @@ export default createEslintRule<Options, MESSAGE_ID>({
7888
selectors: allSelectors,
7989
options,
8090
})
91+
validateNewlinesAndPartitionConfiguration(options)
8192

8293
let { sourceCode, id } = context
8394
let eslintDisabledLines = getEslintDisabledLines({
@@ -187,6 +198,8 @@ export default createEslintRule<Options, MESSAGE_ID>({
187198

188199
reportAllErrors<MESSAGE_ID>({
189200
availableMessageIds: {
201+
missedSpacingBetweenMembers: 'missedSpacingBetweenNamedImports',
202+
extraSpacingBetweenMembers: 'extraSpacingBetweenNamedImports',
190203
unexpectedGroupOrder: 'unexpectedNamedImportsGroupOrder',
191204
unexpectedOrder: 'unexpectedNamedImportsOrder',
192205
},
@@ -218,6 +231,7 @@ export default createEslintRule<Options, MESSAGE_ID>({
218231
}),
219232
partitionByComment: partitionByCommentJsonSchema,
220233
partitionByNewLine: partitionByNewLineJsonSchema,
234+
newlinesBetween: newlinesBetweenJsonSchema,
221235
groups: groupsJsonSchema,
222236
},
223237
additionalProperties: false,
@@ -226,15 +240,17 @@ export default createEslintRule<Options, MESSAGE_ID>({
226240
uniqueItems: true,
227241
type: 'array',
228242
},
243+
messages: {
244+
missedSpacingBetweenNamedImports: MISSED_SPACING_ERROR,
245+
extraSpacingBetweenNamedImports: EXTRA_SPACING_ERROR,
246+
unexpectedNamedImportsGroupOrder: GROUP_ORDER_ERROR,
247+
unexpectedNamedImportsOrder: ORDER_ERROR,
248+
},
229249
docs: {
230250
url: 'https://perfectionist.dev/rules/sort-named-imports',
231251
description: 'Enforce sorted named imports.',
232252
recommended: true,
233253
},
234-
messages: {
235-
unexpectedNamedImportsGroupOrder: GROUP_ORDER_ERROR,
236-
unexpectedNamedImportsOrder: ORDER_ERROR,
237-
},
238254
type: 'suggestion',
239255
fixable: 'code',
240256
},

rules/sort-named-imports/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { TSESTree } from '@typescript-eslint/types'
33

44
import type {
55
PartitionByCommentOption,
6+
NewlinesBetweenOption,
67
CustomGroupsOption,
78
CommonOptions,
89
GroupsOptions,
@@ -25,6 +26,7 @@ export type Options = Partial<
2526
groupKind: 'values-first' | 'types-first' | 'mixed'
2627
customGroups: CustomGroupsOption<SingleCustomGroup>
2728
partitionByComment: PartitionByCommentOption
29+
newlinesBetween: NewlinesBetweenOption
2830
groups: GroupsOptions<Group>
2931
partitionByNewLine: boolean
3032
ignoreAlias: boolean

0 commit comments

Comments
 (0)