diff --git a/docs/content/rules/sort-union-types.mdx b/docs/content/rules/sort-union-types.mdx
index afa3a6df..e057dc31 100644
--- a/docs/content/rules/sort-union-types.mdx
+++ b/docs/content/rules/sort-union-types.mdx
@@ -165,6 +165,18 @@ type CarBrand =
Each group of union types (separated by empty lines) is treated independently, and the order within each group is preserved.
+### newlinesBetween
+
+default: `'ignore'`
+
+Specifies how new lines should be handled between union type groups.
+
+- `ignore` — Do not report errors related to new lines between union type groups.
+- `always` — Enforce one new line between each group, and forbid new lines inside a group.
+- `never` — No new lines are allowed in union types.
+
+This options is only applicable when `partitionByNewLine` is `false`.
+
### groups
@@ -314,8 +326,9 @@ Determines the matcher used for patterns in the `partitionByComment` option.
order: 'asc',
ignoreCase: true,
specialCharacters: 'keep',
- partitionByNewLine: false,
partitionByComment: false,
+ partitionByNewLine: false,
+ newlinesBetween: 'ignore',
matcher: 'minimatch',
groups: [],
},
@@ -342,8 +355,9 @@ Determines the matcher used for patterns in the `partitionByComment` option.
order: 'asc',
ignoreCase: true,
specialCharacters: 'keep',
- partitionByNewLine: false,
partitionByComment: false,
+ partitionByNewLine: false,
+ newlinesBetween: 'ignore',
matcher: 'minimatch',
groups: [],
},
diff --git a/rules/sort-union-types.ts b/rules/sort-union-types.ts
index 4532526e..c79feaa1 100644
--- a/rules/sort-union-types.ts
+++ b/rules/sort-union-types.ts
@@ -1,9 +1,12 @@
import type { SortingNode } from '../typings'
+import { validateNewlinesAndPartitionConfiguration } from '../utils/validate-newlines-and-partition-configuration'
import { validateGroupsConfiguration } from '../utils/validate-groups-configuration'
import { hasPartitionComment } from '../utils/is-partition-comment'
import { sortNodesByGroups } from '../utils/sort-nodes-by-groups'
import { getCommentsBefore } from '../utils/get-comments-before'
+import { makeNewlinesFixes } from '../utils/make-newlines-fixes'
+import { getNewlinesErrors } from '../utils/get-newlines-errors'
import { createEslintRule } from '../utils/create-eslint-rule'
import { getLinesBetween } from '../utils/get-lines-between'
import { getGroupNumber } from '../utils/get-group-number'
@@ -16,7 +19,11 @@ import { makeFixes } from '../utils/make-fixes'
import { complete } from '../utils/complete'
import { pairwise } from '../utils/pairwise'
-type MESSAGE_ID = 'unexpectedUnionTypesGroupOrder' | 'unexpectedUnionTypesOrder'
+type MESSAGE_ID =
+ | 'missedSpacingBetweenUnionTypes'
+ | 'unexpectedUnionTypesGroupOrder'
+ | 'extraSpacingBetweenUnionTypes'
+ | 'unexpectedUnionTypesOrder'
type Group =
| 'intersection'
@@ -37,6 +44,7 @@ type Options = [
Partial<{
type: 'alphabetical' | 'line-length' | 'natural'
partitionByComment: string[] | boolean | string
+ newlinesBetween: 'ignore' | 'always' | 'never'
specialCharacters: 'remove' | 'trim' | 'keep'
matcher: 'minimatch' | 'regex'
groups: (Group[] | Group)[]
@@ -125,6 +133,12 @@ export default createEslintRule({
'Allows to use spaces to separate the nodes into logical groups.',
type: 'boolean',
},
+ newlinesBetween: {
+ description:
+ 'Specifies how new lines should be handled between object types groups.',
+ enum: ['ignore', 'always', 'never'],
+ type: 'string',
+ },
},
additionalProperties: false,
},
@@ -134,6 +148,10 @@ export default createEslintRule({
'Expected "{{right}}" ({{rightGroup}}) to come before "{{left}}" ({{leftGroup}}).',
unexpectedUnionTypesOrder:
'Expected "{{right}}" to come before "{{left}}".',
+ missedSpacingBetweenUnionTypes:
+ 'Missed spacing between "{{left}}" and "{{right}}" types.',
+ extraSpacingBetweenUnionTypes:
+ 'Extra spacing between "{{left}}" and "{{right}}" types.',
},
},
defaultOptions: [
@@ -159,6 +177,7 @@ export default createEslintRule({
order: 'asc',
groups: [],
matcher: 'minimatch',
+ newlinesBetween: 'ignore',
partitionByNewLine: false,
partitionByComment: false,
} as const)
@@ -182,6 +201,7 @@ export default createEslintRule({
],
[],
)
+ validateNewlinesAndPartitionConfiguration(options)
let sourceCode = getSourceCode(context)
let partitionComment = options.partitionByComment
@@ -277,17 +297,41 @@ export default createEslintRule({
for (let nodes of formattedMembers) {
let sortedNodes = sortNodesByGroups(nodes, options)
+
pairwise(nodes, (left, right) => {
+ let leftNum = getGroupNumber(options.groups, left)
+ let rightNum = getGroupNumber(options.groups, right)
+
let indexOfLeft = sortedNodes.indexOf(left)
let indexOfRight = sortedNodes.indexOf(right)
+
+ let messageIds: MESSAGE_ID[] = []
+
if (indexOfLeft > indexOfRight) {
- let leftNum = getGroupNumber(options.groups, left)
- let rightNum = getGroupNumber(options.groups, right)
+ messageIds.push(
+ leftNum !== rightNum
+ ? 'unexpectedUnionTypesGroupOrder'
+ : 'unexpectedUnionTypesOrder',
+ )
+ }
+
+ messageIds = [
+ ...messageIds,
+ ...getNewlinesErrors({
+ left,
+ leftNum,
+ right,
+ rightNum,
+ sourceCode,
+ missedSpacingError: 'missedSpacingBetweenUnionTypes',
+ extraSpacingError: 'extraSpacingBetweenUnionTypes',
+ options,
+ }),
+ ]
+
+ for (let messageId of messageIds) {
context.report({
- messageId:
- leftNum !== rightNum
- ? 'unexpectedUnionTypesGroupOrder'
- : 'unexpectedUnionTypesOrder',
+ messageId,
data: {
left: toSingleLine(left.name),
leftGroup: left.group,
@@ -295,8 +339,16 @@ export default createEslintRule({
rightGroup: right.group,
},
node: right.node,
- fix: fixer =>
- makeFixes(fixer, nodes, sortedNodes, sourceCode, options),
+ fix: fixer => [
+ ...makeFixes(fixer, nodes, sortedNodes, sourceCode, options),
+ ...makeNewlinesFixes(
+ fixer,
+ nodes,
+ sortedNodes,
+ sourceCode,
+ options,
+ ),
+ ],
})
}
})