Repository: azat-io/eslint-plugin-perfectionist (ts)

Issue:
Feature: sort-imports - add option to sort within sub groups or remove new line between some groups
### What rule do you want to change?

sort-imports

### Describe the problem

I'm not sure if anything like this is possible right now. I couldn't find it in the docs.
Probably a new option is needed e.g. sort only within sub groups, or remove new line between defined groups

I want to achieve something like this:

```
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import classNames from 'classnames';
import { dequal } from 'dequal';
import omit from 'lodash/omit';
import PropTypes from 'prop-types';
```



### Code example

I have `customGroup` for react-related imports called `react`,
I want to position it with first group:
```
 groups: [['react', 'builtin', 'external', 'internal'], ['parent', 'sibling', 'index'], 'unknown'],
 type: 'natural',
```

now my imports are sorted like this:

```
import classNames from 'classnames';
import { dequal } from 'dequal';
import omit from 'lodash/omit';
import PropTypes from 'prop-types';
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
```

I could change groups to:
```
 groups: ['react', ['builtin', 'external', 'internal'], ['parent', 'sibling', 'index'], 'unknown'],
```

to get:
```
import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';

import classNames from 'classnames';
import { dequal } from 'dequal';
import omit from 'lodash/omit';
import PropTypes from 'prop-types';
```

But I cannot get what I want.

The issue is that ['react', 'builtin', 'external', 'internal'] is treated as 1 group for sorting, and I'd like to get sorting within `react` separately from the rest. Maybe some syntax like this could help:
```
groups: [['react', ['builtin', 'external', 'internal']], ['parent', 'sibling', 'index'], 'unknown'],
``` 
Entries in the main array are separated by new line as defined in `newlinesBetween`, but further divisions decide about what is sorted together - just an idea.

### Additional comments

_No response_

### Validations

- [X] Read the [docs](https://perfectionist.dev).
- [X] Check that there isn't [already an issue](https://github.com/azat-io/eslint-plugin-perfectionist/issues) that reports the same bug to avoid creating a duplicate.

Pull request:
feat: allows users to enter  `{ newlinesBetween }`  in `groups`
Resolves #401
Continuation of #428.

- ✅ **PR 1**: Add `customGroup.newlinesInside` option. We will take the opportunity to create a `getNewlinesBetweenOption` method that will help us later to precisely customize newline behavior between two specific groups. 
- ⚙️ **PR 2 (this)**: Add a way to choose a specific newline behavior between two groups. See the proposals [here](https://github.com/azat-io/eslint-plugin-perfectionist/issues/401#issuecomment-2558581331).
  - Proposal **2** is implemented here.

# Description

Allows users to enter `{ newlinesBetween: 'always' | 'never' | 'ignore' }` between elements of the `groups` option. This enables precisely setting/overriding the newline behavior between two groups.

Example:

```ts
{
  newlinesBetween: "always", // Default behavior
  groups: [
    "public-property",
    { newlinesBetween: "never" }, // Will override the default behavior
    "protected-property",
    { newlinesBetween: "never" },
    "private-property",
    // Will enforce a newline here because of the default behavior
    "method",
  ]
}
```

-  `{ newlinesBetween: 'ignore' }` is only useful if a `newlinesBetween` option different from `ignore` is set.
- Entering two consecutive `{ newlinesBetween }` objects in a group configuration will raise an error: `Consecutive 'newlinesBetween' objects are not allowed`.

# Impacted rules

-  `sort-imports`
- `sort-intersection-types`
- `sort-union-types`
- `sort-classes`
- `sort-modules`
- `sort-object-types`
- `sort-interfaces`

# Additional notes

## ❓ Is this better than proposal 1 ?

Proposal 1:

> Adds `customGroups.newlinesAbove` and `customGroups.newlinesUnder` options

You can see a proof of concept PR [here](https://github.com/hugop95/eslint-plugin-perfectionist/pull/7).

I believe the current implementation is superior:
- Implementing proposal 1 means handling cases where the below group has a `newlinesAbove` incompatible with the `newlinesUnder` of the above group.
- It's not as easy to read the newline configuration. This implementation allows users to quickly see where newlines are enforced (or not) by looking at `groups`.
- Proposal 1 can co-exist with proposal 2, so it's always theoretically possible to have both implementations later if really needed.

## ❓ Why not use string tokens instead of an object, such as `"newlinesBetween:always"` ?

I believe that an object gives us more flexibility in the future if we want to allow users to pass additional options.
It's also easy to distinguish those objects from the group names.

# What is the purpose of this pull request?

- [x] New Feature


Patch:
diff --git a/docs/content/rules/sort-classes.mdx b/docs/content/rules/sort-classes.mdx
index a7a450b..7dc0337 100644
--- a/docs/content/rules/sort-classes.mdx
+++ b/docs/content/rules/sort-classes.mdx
@@ -266,7 +266,7 @@ Specifies how new lines should be handled between class member groups.
 - `always` — Enforce one new line between each group, and forbid new lines inside a group.
 - `never` — No new lines are allowed in object types.
 
-This options is only applicable when `partitionByNewLine` is `false`.
+This option is only applicable when `partitionByNewLine` is `false`.
 
 ### ignoreCallbackDependenciesPatterns
 
diff --git a/docs/content/rules/sort-imports.mdx b/docs/content/rules/sort-imports.mdx
index 8ae738b..3ee4650 100644
--- a/docs/content/rules/sort-imports.mdx
+++ b/docs/content/rules/sort-imports.mdx
@@ -227,7 +227,11 @@ Specifies how new lines should be handled between import groups.
 - `always` — Enforce one new line between each group, and forbid new lines inside a group.
 - `never` — No new lines are allowed in the entire import section.
 
-This options is only applicable when `partitionByNewLine` is `false`.
+You can also enforce the newline behavior between two specific groups through the `groups` options.
+
+See the [`groups`](#newlines-between-groups) option.
+
+This option is only applicable when `partitionByNewLine` is `false`.
 
 ### maxLineLength
 
@@ -333,6 +337,25 @@ import type { Details } from './data'
 import type { BaseOptions } from './index.d.ts'
 ```
 
+#### Newlines between groups
+
+You may place `newlinesBetween` objects between your groups to enforce the newline behavior between two specific groups.
+
+See the [`newlinesBetween`](#newlinesbetween) option.
+
+This feature is only applicable when `partitionByNewLine` is false.
+
+```ts
+{
+  newlinesBetween: 'always',
+  groups: [
+    'a',
+    { newlinesBetween: 'never' }, // Overrides the global newlinesBetween option
+    'b',
+  ]
+}
+```
+
 ### customGroups
 
 <sub>
diff --git a/docs/content/rules/sort-interfaces.mdx b/docs/content/rules/sort-interfaces.mdx
index 5a31bd7..2fbe08d 100644
--- a/docs/content/rules/sort-interfaces.mdx
+++ b/docs/content/rules/sort-interfaces.mdx
@@ -248,7 +248,7 @@ Specifies how new lines should be handled between interface groups.
 - `always` — Enforce one new line between each group, and forbid new lines inside a group.
 - `never` — No new lines are allowed between interface members.
 
-This options is only applicable when `partitionByNewLine` is `false`.
+This option is only applicable when `partitionByNewLine` is `false`.
 
 ### [DEPRECATED] groupKind
 
diff --git a/docs/content/rules/sort-intersection-types.mdx b/docs/content/rules/sort-intersection-types.mdx
index 396d563..ae214ff 100644
--- a/docs/content/rules/sort-intersection-types.mdx
+++ b/docs/content/rules/sort-intersection-types.mdx
@@ -176,7 +176,7 @@ Specifies how new lines should be handled between intersection type groups.
 - `always` — Enforce one new line between each group, and forbid new lines inside a group.
 - `never` — No new lines are allowed in intersection types.
 
-This options is only applicable when `partitionByNewLine` is `false`.
+This option is only applicable when `partitionByNewLine` is `false`.
 
 ### groups
 
diff --git a/docs/content/rules/sort-modules.mdx b/docs/content/rules/sort-modules.mdx
index 246c3d4..aee5345 100644
--- a/docs/content/rules/sort-modules.mdx
+++ b/docs/content/rules/sort-modules.mdx
@@ -290,7 +290,7 @@ Specifies how new lines should be handled between module member groups.
 - `always` — Enforce one new line between each group, and forbid new lines inside a group.
 - `never` — No new lines are allowed in object types.
 
-This options is only applicable when `partitionByNewLine` is `false`.
+This option is only applicable when `partitionByNewLine` is `false`.
 
 ### groups
 
diff --git a/docs/content/rules/sort-object-types.mdx b/docs/content/rules/sort-object-types.mdx
index 3dce69c..b90dabd 100644
--- a/docs/content/rules/sort-object-types.mdx
+++ b/docs/content/rules/sort-object-types.mdx
@@ -213,7 +213,7 @@ Specifies how new lines should be handled between object type groups.
 - `always` — Enforce one new line between each group, and forbid new lines inside a group.
 - `never` — No new lines are allowed in object types.
 
-This options is only applicable when `partitionByNewLine` is `false`.
+This option is only applicable when `partitionByNewLine` is `false`.
 
 ### [DEPRECATED] groupKind
 
diff --git a/docs/content/rules/sort-objects.mdx b/docs/content/rules/sort-objects.mdx
index 953a1db..7165f45 100644
--- a/docs/content/rules/sort-objects.mdx
+++ b/docs/content/rules/sort-objects.mdx
@@ -258,7 +258,7 @@ Specifies how new lines should be handled between object groups.
 - `always` — Enforce one new line between each group, and forbid new lines inside a group.
 - `never` — No new lines are allowed in objects.
 
-This options is only applicable when `partitionByNewLine` is `false`.
+This option is only applicable when `partitionByNewLine` is `false`.
 
 ### styledComponents
 
diff --git a/docs/content/rules/sort-union-types.mdx b/docs/content/rules/sort-union-types.mdx
index ff22df3..100f406 100644
--- a/docs/content/rules/sort-union-types.mdx
+++ b/docs/content/rules/sort-union-types.mdx
@@ -196,7 +196,7 @@ Specifies how new lines should be handled 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`.
+This option is only applicable when `partitionByNewLine` is `false`.
 
 ### groups
 
diff --git a/rules/sort-classes/types.ts b/rules/sort-classes/types.ts
index 386b50d..c83a8b6 100644
--- a/rules/sort-classes/types.ts
+++ b/rules/sort-classes/types.ts
@@ -18,6 +18,11 @@ export type SortClassesOptions = [
       | string[]
       | boolean
       | string
+    groups: (
+      | { newlinesBetween: 'ignore' | 'always' | 'never' }
+      | Group[]
+      | Group
+    )[]
     type: 'alphabetical' | 'line-length' | 'natural' | 'custom'
     newlinesBetween: 'ignore' | 'always' | 'never'
     specialCharacters: 'remove' | 'trim' | 'keep'
@@ -25,7 +30,6 @@ export type SortClassesOptions = [
     locales: NonNullable<Intl.LocalesArgument>
     partitionByNewLine: boolean
     customGroups: CustomGroup[]
-    groups: (Group[] | Group)[]
     order: 'desc' | 'asc'
     ignoreCase: boolean
     alphabet: string
diff --git a/rules/sort-imports.ts b/rules/sort-imports.ts
index 264893a..a9eaf16 100644
--- a/rules/sort-imports.ts
+++ b/rules/sort-imports.ts
@@ -57,11 +57,15 @@ export type Options<T extends string[]> = [
       value?: Record<T[number], string[] | string>
       type?: Record<T[number], string[] | string>
     }
+    groups: (
+      | { newlinesBetween: 'ignore' | 'always' | 'never' }
+      | Group<T>[]
+      | Group<T>
+    )[]
     type: 'alphabetical' | 'line-length' | 'natural' | 'custom'
     newlinesBetween: 'ignore' | 'always' | 'never'
     specialCharacters: 'remove' | 'trim' | 'keep'
     locales: NonNullable<Intl.LocalesArgument>
-    groups: (Group<T>[] | Group<T>)[]
     environment: 'node' | 'bun'
     partitionByNewLine: boolean
     internalPattern: string[]
@@ -177,9 +181,13 @@ export default createEslintRule<Options<string[]>, MESSAGE_ID>({
       : null
 
     let isSideEffectOnlyGroup = (
-      group: undefined | string[] | string,
+      group:
+        | { newlinesBetween: 'ignore' | 'always' | 'never' }
+        | undefined
+        | string[]
+        | string,
     ): boolean => {
-      if (!group) {
+      if (!group || (typeof group === 'object' && 'newlinesBetween' in group)) {
         return false
       }
       if (typeof group === 'string') {
diff --git a/rules/sort-intersection-types.ts b/rules/sort-intersection-types.ts
index 8b28e7a..5bd14e3 100644
--- a/rules/sort-intersection-types.ts
+++ b/rules/sort-intersection-types.ts
@@ -45,11 +45,15 @@ type Options = [
       | string[]
       | boolean
       | string
+    groups: (
+      | { newlinesBetween: 'ignore' | 'always' | 'never' }
+      | Group[]
+      | Group
+    )[]
     type: 'alphabetical' | 'line-length' | 'natural' | 'custom'
     newlinesBetween: 'ignore' | 'always' | 'never'
     specialCharacters: 'remove' | 'trim' | 'keep'
     locales: NonNullable<Intl.LocalesArgument>
-    groups: (Group[] | Group)[]
     partitionByNewLine: boolean
     order: 'desc' | 'asc'
     ignoreCase: boolean
diff --git a/rules/sort-modules/types.ts b/rules/sort-modules/types.ts
index 2d01cdc..532d4a4 100644
--- a/rules/sort-modules/types.ts
+++ b/rules/sort-modules/types.ts
@@ -18,12 +18,16 @@ export type SortModulesOptions = [
       | string[]
       | boolean
       | string
+    groups: (
+      | { newlinesBetween: 'ignore' | 'always' | 'never' }
+      | Group[]
+      | Group
+    )[]
     type: 'alphabetical' | 'line-length' | 'natural' | 'custom'
     newlinesBetween: 'ignore' | 'always' | 'never'
     specialCharacters: 'remove' | 'trim' | 'keep'
     locales: NonNullable<Intl.LocalesArgument>
     customGroups: CustomGroup[]
-    groups: (Group[] | Group)[]
     partitionByNewLine: boolean
     order: 'desc' | 'asc'
     ignoreCase: boolean
diff --git a/rules/sort-object-types/types.ts b/rules/sort-object-types/types.ts
index 9f1c708..37cbf67 100644
--- a/rules/sort-object-types/types.ts
+++ b/rules/sort-object-types/types.ts
@@ -21,6 +21,11 @@ export type Options = Partial<{
     declarationMatchesPattern?: string
     allNamesMatchPattern?: string
   }
+  groups: (
+    | { newlinesBetween: 'ignore' | 'always' | 'never' }
+    | Group[]
+    | Group
+  )[]
   type: 'alphabetical' | 'line-length' | 'unsorted' | 'natural' | 'custom'
   customGroups: Record<string, string[] | string> | CustomGroup[]
   /**
@@ -30,7 +35,6 @@ export type Options = Partial<{
   newlinesBetween: 'ignore' | 'always' | 'never'
   specialCharacters: 'remove' | 'trim' | 'keep'
   locales: NonNullable<Intl.LocalesArgument>
-  groups: (Group[] | Group)[]
   partitionByNewLine: boolean
   /**
    * @deprecated for {@link `useConfigurationIf.declarationMatchesPattern`}
diff --git a/rules/sort-objects.ts b/rules/sort-objects.ts
index 1779639..84065ea 100644
--- a/rules/sort-objects.ts
+++ b/rules/sort-objects.ts
@@ -60,13 +60,17 @@ type Options = Partial<{
     callingFunctionNamePattern?: string
     allNamesMatchPattern?: string
   }
+  groups: (
+    | { newlinesBetween: 'ignore' | 'always' | 'never' }
+    | Group[]
+    | Group
+  )[]
   type: 'alphabetical' | 'line-length' | 'unsorted' | 'natural' | 'custom'
   destructuredObjects: { groups: boolean } | boolean
   customGroups: Record<string, string[] | string>
   newlinesBetween: 'ignore' | 'always' | 'never'
   specialCharacters: 'remove' | 'trim' | 'keep'
   locales: NonNullable<Intl.LocalesArgument>
-  groups: (Group[] | Group)[]
   partitionByNewLine: boolean
   objectDeclarations: boolean
   styledComponents: boolean
diff --git a/rules/sort-union-types.ts b/rules/sort-union-types.ts
index fd4e35c..39514f1 100644
--- a/rules/sort-union-types.ts
+++ b/rules/sort-union-types.ts
@@ -45,11 +45,15 @@ type Options = [
       | string[]
       | boolean
       | string
+    groups: (
+      | { newlinesBetween: 'ignore' | 'always' | 'never' }
+      | Group[]
+      | Group
+    )[]
     type: 'alphabetical' | 'line-length' | 'natural' | 'custom'
     newlinesBetween: 'ignore' | 'always' | 'never'
     specialCharacters: 'remove' | 'trim' | 'keep'
     locales: NonNullable<Intl.LocalesArgument>
-    groups: (Group[] | Group)[]
     partitionByNewLine: boolean
     order: 'desc' | 'asc'
     ignoreCase: boolean
diff --git a/utils/common-json-schemas.ts b/utils/common-json-schemas.ts
index 2c447fe..817fb1a 100644
--- a/utils/common-json-schemas.ts
+++ b/utils/common-json-schemas.ts
@@ -53,6 +53,12 @@ export let specialCharactersJsonSchema: JSONSchema4 = {
   type: 'string',
 }
 
+export let newlinesBetweenJsonSchema: JSONSchema4 = {
+  description: 'Specifies how new lines should be handled between groups.',
+  enum: ['ignore', 'always', 'never'],
+  type: 'string',
+}
+
 export let groupsJsonSchema: JSONSchema4 = {
   items: {
     oneOf: [
@@ -65,6 +71,12 @@ export let groupsJsonSchema: JSONSchema4 = {
         },
         type: 'array',
       },
+      {
+        properties: {
+          newlinesBetween: newlinesBetweenJsonSchema,
+        },
+        type: 'object',
+      },
     ],
   },
   description: 'Specifies the order of the groups.',
@@ -126,12 +138,6 @@ export let partitionByNewLineJsonSchema: JSONSchema4 = {
   type: 'boolean',
 }
 
-export let newlinesBetweenJsonSchema: JSONSchema4 = {
-  description: 'Specifies how new lines should be handled between groups.',
-  enum: ['ignore', 'always', 'never'],
-  type: 'string',
-}
-
 export let buildUseConfigurationIfJsonSchema = ({
   additionalProperties,
 }: {
diff --git a/utils/get-custom-groups-compare-options.ts b/utils/get-custom-groups-compare-options.ts
index 1b7244b..dcdabcc 100644
--- a/utils/get-custom-groups-compare-options.ts
+++ b/utils/get-custom-groups-compare-options.ts
@@ -2,11 +2,15 @@ import type { SortingNode } from '../types/sorting-node'
 import type { CompareOptions } from './compare'
 
 interface Options {
+  groups: (
+    | { newlinesBetween: 'ignore' | 'always' | 'never' }
+    | string[]
+    | string
+  )[]
   customGroups: Record<string, string[] | string> | CustomGroup[]
   type: 'alphabetical' | 'line-length' | 'natural' | 'custom'
   specialCharacters: 'remove' | 'trim' | 'keep'
   locales: NonNullable<Intl.LocalesArgument>
-  groups: (string[] | string)[]
   order: 'desc' | 'asc'
   ignoreCase: boolean
   alphabet: string
diff --git a/utils/get-group-number.ts b/utils/get-group-number.ts
index d5b2f54..2ffe6e1 100644
--- a/utils/get-group-number.ts
+++ b/utils/get-group-number.ts
@@ -1,9 +1,11 @@
 import type { SortingNode } from '../types/sorting-node'
 
-export let getGroupNumber = (
-  groups: (string[] | string)[],
-  node: SortingNode,
-): number => {
+type Group =
+  | { newlinesBetween: 'ignore' | 'always' | 'never' }
+  | string[]
+  | string
+
+export let getGroupNumber = (groups: Group[], node: SortingNode): number => {
   for (let max = groups.length, i = 0; i < max; i++) {
     let currentGroup = groups[i]
 
diff --git a/utils/get-newlines-between-option.ts b/utils/get-newlines-between-option.ts
index 4aefb81..39fe522 100644
--- a/utils/get-newlines-between-option.ts
+++ b/utils/get-newlines-between-option.ts
@@ -9,9 +9,13 @@ export interface GetNewlinesBetweenOptionParameters {
 }
 
 interface Options {
+  groups: (
+    | { newlinesBetween: 'ignore' | 'always' | 'never' }
+    | string[]
+    | string
+  )[]
   customGroups?: Record<string, string[] | string> | CustomGroup[]
   newlinesBetween: 'ignore' | 'always' | 'never'
-  groups: (string[] | string)[]
 }
 
 interface CustomGroup {
@@ -45,30 +49,38 @@ export let getNewlinesBetweenOption = ({
     nodeGroupNumber,
   })
 
-  if (!options.customGroups || !Array.isArray(options.customGroups)) {
-    return globalNewlinesBetweenOption
-  }
-
   let nodeGroup = options.groups[nodeGroupNumber]
   let nextNodeGroup = options.groups[nextNodeGroupNumber]
 
-  if (Array.isArray(nodeGroup) || Array.isArray(nextNodeGroup)) {
-    return globalNewlinesBetweenOption
-  }
-
-  let nodeCustomGroup = options.customGroups.find(
-    customGroup => customGroup.groupName === nodeGroup,
-  )
-  let nextNodeCustomGroup = options.customGroups.find(
-    customGroup => customGroup.groupName === nextNodeGroup,
-  )
-
+  // NewlinesInside check
   if (
-    nodeCustomGroup &&
-    nextNodeCustomGroup &&
-    nodeCustomGroup.groupName === nextNodeCustomGroup.groupName
+    Array.isArray(options.customGroups) &&
+    typeof nodeGroup === 'string' &&
+    typeof nextNodeGroup === 'string' &&
+    nodeGroup === nextNodeGroup
   ) {
-    return nodeCustomGroup.newlinesInside ?? globalNewlinesBetweenOption
+    let nodeCustomGroup = options.customGroups.find(
+      customGroup => customGroup.groupName === nodeGroup,
+    )
+    let nextNodeCustomGroup = options.customGroups.find(
+      customGroup => customGroup.groupName === nextNodeGroup,
+    )
+
+    if (
+      nodeCustomGroup &&
+      nextNodeCustomGroup &&
+      nodeCustomGroup.groupName === nextNodeCustomGroup.groupName
+    ) {
+      return nodeCustomGroup.newlinesInside ?? globalNewlinesBetweenOption
+    }
+  }
+
+  // Check if a specific newlinesBetween is defined between the two groups
+  if (nextNodeGroupNumber === nodeGroupNumber + 2) {
+    let groupBetween = options.groups[nodeGroupNumber + 1]
+    if (typeof groupBetween === 'object' && 'newlinesBetween' in groupBetween) {
+      return groupBetween.newlinesBetween
+    }
   }
 
   return globalNewlinesBetweenOption
diff --git a/utils/get-newlines-errors.ts b/utils/get-newlines-errors.ts
index 9ba0919..62504dd 100644
--- a/utils/get-newlines-errors.ts
+++ b/utils/get-newlines-errors.ts
@@ -7,9 +7,13 @@ import { getLinesBetween } from './get-lines-between'
 
 interface GetNewlinesErrorsParameters<T extends string> {
   options: {
+    groups: (
+      | { newlinesBetween: 'ignore' | 'always' | 'never' }
+      | string[]
+      | string
+    )[]
     customGroups?: Record<string, string[] | string> | CustomGroup[]
     newlinesBetween: 'ignore' | 'always' | 'never'
-    groups: (string[] | string)[]
   }
   sourceCode: TSESLint.SourceCode
   missedSpacingError: T
diff --git a/utils/get-options-with-clean-groups.ts b/utils/get-options-with-clean-groups.ts
index c2dae44..372d696 100644
--- a/utils/get-options-with-clean-groups.ts
+++ b/utils/get-options-with-clean-groups.ts
@@ -1,5 +1,9 @@
 interface GroupOptions {
-  groups: (string[] | string)[]
+  groups: (
+    | { newlinesBetween: 'ignore' | 'always' | 'never' }
+    | string[]
+    | string
+  )[]
 }
 
 export let getOptionsWithCleanGroups = <T extends GroupOptions>(
@@ -7,9 +11,9 @@ export let getOptionsWithCleanGroups = <T extends GroupOptions>(
 ): T => ({
   ...options,
   groups: options.groups
-    .filter(group => group.length > 0)
+    .filter(group => !Array.isArray(group) || group.length > 0)
     .map(group =>
-      typeof group === 'string' ? group : getCleanedNestedGroups(group),
+      Array.isArray(group) ? getCleanedNestedGroups(group) : group,
     ),
 })
 
diff --git a/utils/make-newlines-fixes.ts b/utils/make-newlines-fixes.ts
index cca9f99..17dbbd1 100644
--- a/utils/make-newlines-fixes.ts
+++ b/utils/make-newlines-fixes.ts
@@ -6,6 +6,16 @@ import { getNewlinesBetweenOption } from './get-newlines-between-option'
 import { getLinesBetween } from './get-lines-between'
 import { getNodeRange } from './get-node-range'
 
+interface Options {
+  groups: (
+    | { newlinesBetween: 'ignore' | 'always' | 'never' }
+    | string[]
+    | string
+  )[]
+  customGroups?: Record<string, string[] | string> | CustomGroup[]
+  newlinesBetween: 'ignore' | 'always' | 'never'
+}
+
 interface MakeNewlinesFixesParameters {
   sourceCode: TSESLint.SourceCode
   sortedNodes: SortingNode[]
@@ -14,12 +24,6 @@ interface MakeNewlinesFixesParameters {
   options: Options
 }
 
-interface Options {
-  customGroups?: Record<string, string[] | string> | CustomGroup[]
-  newlinesBetween: 'ignore' | 'always' | 'never'
-  groups: (string[] | string)[]
-}
-
 interface CustomGroup {
   newlinesInside?: 'always' | 'never'
   groupName: string
diff --git a/utils/sort-nodes-by-groups.ts b/utils/sort-nodes-by-groups.ts
index e2658de..610393b 100644
--- a/utils/sort-nodes-by-groups.ts
+++ b/utils/sort-nodes-by-groups.ts
@@ -15,7 +15,11 @@ interface ExtraOptions<T extends SortingNode> {
 }
 
 interface GroupOptions {
-  groups: (string[] | string)[]
+  groups: (
+    | { newlinesBetween: 'ignore' | 'always' | 'never' }
+    | string[]
+    | string
+  )[]
 }
 
 export let sortNodesByGroups = <T extends SortingNode>(
diff --git a/utils/use-groups.ts b/utils/use-groups.ts
index ae8c1a7..26a72c6 100644
--- a/utils/use-groups.ts
+++ b/utils/use-groups.ts
@@ -13,7 +13,11 @@ interface UseGroupsValue {
 }
 
 interface UseGroupProps {
-  groups: (string[] | string)[]
+  groups: (
+    | { newlinesBetween: 'ignore' | 'always' | 'never' }
+    | string[]
+    | string
+  )[]
 }
 
 export let useGroups = ({ groups }: UseGroupProps): UseGroupsValue => {
diff --git a/utils/validate-generated-groups-configuration.ts b/utils/validate-generated-groups-configuration.ts
index 0b05651..2858eae 100644
--- a/utils/validate-generated-groups-configuration.ts
+++ b/utils/validate-generated-groups-configuration.ts
@@ -1,12 +1,17 @@
 import { validateNoDuplicatedGroups } from './validate-groups-configuration'
 
-interface Props {
+interface ValidateGenerateGroupsConfigurationParameters {
   customGroups: Record<string, string[] | string> | BaseCustomGroup[]
-  groups: (string[] | string)[]
   selectors: string[]
   modifiers: string[]
+  groups: Group[]
 }
 
+type Group =
+  | { newlinesBetween: 'ignore' | 'always' | 'never' }
+  | string[]
+  | string
+
 interface BaseCustomGroup {
   groupName: string
 }
@@ -16,7 +21,7 @@ export let validateGeneratedGroupsConfiguration = ({
   selectors,
   modifiers,
   groups,
-}: Props): void => {
+}: ValidateGenerateGroupsConfigurationParameters): void => {
   let availableCustomGroupNames = new Set(
     Array.isArray(customGroups)
       ? customGroups.map(customGroup => customGroup.groupName)
@@ -24,6 +29,7 @@ export let validateGeneratedGroupsConfiguration = ({
   )
   let invalidGroups = groups
     .flat()
+    .filter(group => typeof group === 'string')
     .filter(
       group =>
         !isPredefinedGroup(selectors, modifiers, group) &&
diff --git a/utils/validate-groups-configuration.ts b/utils/validate-groups-configuration.ts
index 31af727..b9845bc 100644
--- a/utils/validate-groups-configuration.ts
+++ b/utils/validate-groups-configuration.ts
@@ -1,9 +1,14 @@
+type Group =
+  | { newlinesBetween: 'ignore' | 'always' | 'never' }
+  | string[]
+  | string
+
 /**
  * Throws an error if one of the following conditions is met:
  * - One or more groups specified in `groups` are not predefined nor specified
  * in `customGroups`
  * - A group is specified in `groups` more than once
- * @param {(string[] | string)[]} groups - The groups to validate.
+ * @param {Group[]} groups - The groups to validate.
  * @param {string[]} allowedPredefinedGroups - An array of predefined group
  * names that are considered valid.
  * @param {string[]} allowedCustomGroups - An array of custom group names that
@@ -11,7 +16,7 @@
  * @throws Will throw an error if invalid or duplicated groups are found.
  */
 export let validateGroupsConfiguration = (
-  groups: (string[] | string)[],
+  groups: Group[],
   allowedPredefinedGroups: string[],
   allowedCustomGroups: string[],
 ): void => {
@@ -19,9 +24,27 @@ export let validateGroupsConfiguration = (
     ...allowedPredefinedGroups,
     ...allowedCustomGroups,
   ])
-  let invalidGroups = groups
-    .flat()
-    .filter(group => !allowedGroupsSet.has(group))
+  let invalidGroups: string[] = []
+  let isPreviousElementNewlinesBetween = false
+  for (let groupElement of groups) {
+    if (typeof groupElement === 'object' && 'newlinesBetween' in groupElement) {
+      // There should not be two consecutive `newlinesBetween` objects
+      if (isPreviousElementNewlinesBetween) {
+        throw new Error("Consecutive 'newlinesBetween' objects are not allowed")
+      }
+      isPreviousElementNewlinesBetween = true
+    } else {
+      isPreviousElementNewlinesBetween = false
+      let groupElements = Array.isArray(groupElement)
+        ? groupElement
+        : [groupElement]
+      for (let group of groupElements) {
+        if (!allowedGroupsSet.has(group)) {
+          invalidGroups.push(group)
+        }
+      }
+    }
+  }
   if (invalidGroups.length) {
     throw new Error(`Invalid group(s): ${invalidGroups.join(', ')}`)
   }
@@ -30,17 +53,18 @@ export let validateGroupsConfiguration = (
 
 /**
  * Throws an error if a group is specified more than once
- * @param {(string[] | string)[]} groups - The groups to check for duplicates.
+ * @param {Group[]} groups - The groups to check for duplicates.
  * @throws Will throw an error if duplicated groups are found.
  */
-export let validateNoDuplicatedGroups = (
-  groups: (string[] | string)[],
-): void => {
+export let validateNoDuplicatedGroups = (groups: Group[]): void => {
   let flattenGroups = groups.flat()
   let seenGroups = new Set<string>()
   let duplicatedGroups = new Set<string>()
 
   for (let group of flattenGroups) {
+    if (typeof group === 'object' && 'newlinesBetween' in group) {
+      continue
+    }
     if (seenGroups.has(group)) {
       duplicatedGroups.add(group)
     } else {
diff --git a/utils/validate-newlines-and-partition-configuration.ts b/utils/validate-newlines-and-partition-configuration.ts
index 4cc0a1e..9bca8cd 100644
--- a/utils/validate-newlines-and-partition-configuration.ts
+++ b/utils/validate-newlines-and-partition-configuration.ts
@@ -1,15 +1,32 @@
 interface Options {
-  partitionByNewLine: string[] | boolean | string
+  groups: (
+    | { newlinesBetween: 'ignore' | 'always' | 'never' }
+    | string[]
+    | string
+  )[]
   newlinesBetween: 'ignore' | 'always' | 'never'
+  partitionByNewLine: boolean
 }
 
 export let validateNewlinesAndPartitionConfiguration = ({
   partitionByNewLine,
   newlinesBetween,
+  groups,
 }: Options): void => {
-  if (!!partitionByNewLine && newlinesBetween !== 'ignore') {
+  if (!partitionByNewLine) {
+    return
+  }
+  if (newlinesBetween !== 'ignore') {
     throw new Error(
       "The 'partitionByNewLine' and 'newlinesBetween' options cannot be used together",
     )
   }
+  let hasNewlinesBetweenGroup = groups.some(
+    group => typeof group === 'object' && 'newlinesBetween' in group,
+  )
+  if (hasNewlinesBetweenGroup) {
+    throw new Error(
+      "'newlinesBetween' objects can not be used in 'groups' alongside 'partitionByNewLine'",
+    )
+  }
 }


Test patch:
diff --git a/test/rules/sort-classes.test.ts b/test/rules/sort-classes.test.ts
index f619ece..387900b 100644
--- a/test/rules/sort-classes.test.ts
+++ b/test/rules/sort-classes.test.ts
@@ -4427,6 +4427,92 @@ describe(ruleName, () => {
           valid: [],
         },
       )
+
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use "newlinesBetween" inside groups`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  ...options,
+                  customGroups: [
+                    { elementNamePattern: 'a', groupName: 'a' },
+                    { elementNamePattern: 'b', groupName: 'b' },
+                    { elementNamePattern: 'c', groupName: 'c' },
+                    { elementNamePattern: 'd', groupName: 'd' },
+                    { elementNamePattern: 'e', groupName: 'e' },
+                  ],
+                  groups: [
+                    'a',
+                    { newlinesBetween: 'always' },
+                    'b',
+                    { newlinesBetween: 'always' },
+                    'c',
+                    { newlinesBetween: 'never' },
+                    'd',
+                    { newlinesBetween: 'ignore' },
+                    'e',
+                  ],
+                  newlinesBetween: 'always',
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    right: 'b',
+                    left: 'a',
+                  },
+                  messageId: 'missedSpacingBetweenClassMembers',
+                },
+                {
+                  data: {
+                    right: 'c',
+                    left: 'b',
+                  },
+                  messageId: 'extraSpacingBetweenClassMembers',
+                },
+                {
+                  data: {
+                    right: 'd',
+                    left: 'c',
+                  },
+                  messageId: 'extraSpacingBetweenClassMembers',
+                },
+              ],
+              output: dedent`
+                class Class {
+                  a: string
+
+                  b: string
+
+                  c: string
+                  d: string
+
+
+                  e: string
+                }
+              `,
+              code: dedent`
+                class Class {
+                  a: string
+                  b: string
+
+
+                  c: string
+
+                  d: string
+
+
+                  e: string
+                }
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
     })
 
     describe(`${ruleName}(${type}): sorts inline elements correctly`, () => {
diff --git a/test/rules/sort-imports.test.ts b/test/rules/sort-imports.test.ts
index d09cd87..65c77f8 100644
--- a/test/rules/sort-imports.test.ts
+++ b/test/rules/sort-imports.test.ts
@@ -2031,6 +2031,90 @@ describe(ruleName, () => {
           valid: [],
         },
       )
+
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use "newlinesBetween" inside groups`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  ...options,
+                  groups: [
+                    'a',
+                    { newlinesBetween: 'always' },
+                    'b',
+                    { newlinesBetween: 'always' },
+                    'c',
+                    { newlinesBetween: 'never' },
+                    'd',
+                    { newlinesBetween: 'ignore' },
+                    'e',
+                  ],
+                  customGroups: {
+                    value: {
+                      a: 'a',
+                      b: 'b',
+                      c: 'c',
+                      d: 'd',
+                      e: 'e',
+                    },
+                  },
+                  newlinesBetween: 'always',
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    right: 'b',
+                    left: 'a',
+                  },
+                  messageId: 'missedSpacingBetweenImports',
+                },
+                {
+                  data: {
+                    right: 'c',
+                    left: 'b',
+                  },
+                  messageId: 'extraSpacingBetweenImports',
+                },
+                {
+                  data: {
+                    right: 'd',
+                    left: 'c',
+                  },
+                  messageId: 'extraSpacingBetweenImports',
+                },
+              ],
+              output: dedent`
+                import { A } from 'a'
+
+                import { B } from 'b'
+
+                import { C } from 'c'
+                import { D } from 'd'
+
+
+                import { E } from 'e'
+              `,
+              code: dedent`
+                import { A } from 'a'
+                import { B } from 'b'
+
+
+                import { C } from 'c'
+
+                import { D } from 'd'
+
+
+                import { E } from 'e'
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
     })
 
     ruleTester.run(
diff --git a/test/rules/sort-interfaces.test.ts b/test/rules/sort-interfaces.test.ts
index d1ff6f3..363b0cf 100644
--- a/test/rules/sort-interfaces.test.ts
+++ b/test/rules/sort-interfaces.test.ts
@@ -2304,6 +2304,92 @@ describe(ruleName, () => {
           valid: [],
         },
       )
+
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use "newlinesBetween" inside groups`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  ...options,
+                  customGroups: [
+                    { elementNamePattern: 'a', groupName: 'a' },
+                    { elementNamePattern: 'b', groupName: 'b' },
+                    { elementNamePattern: 'c', groupName: 'c' },
+                    { elementNamePattern: 'd', groupName: 'd' },
+                    { elementNamePattern: 'e', groupName: 'e' },
+                  ],
+                  groups: [
+                    'a',
+                    { newlinesBetween: 'always' },
+                    'b',
+                    { newlinesBetween: 'always' },
+                    'c',
+                    { newlinesBetween: 'never' },
+                    'd',
+                    { newlinesBetween: 'ignore' },
+                    'e',
+                  ],
+                  newlinesBetween: 'always',
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    right: 'b',
+                    left: 'a',
+                  },
+                  messageId: 'missedSpacingBetweenInterfaceMembers',
+                },
+                {
+                  data: {
+                    right: 'c',
+                    left: 'b',
+                  },
+                  messageId: 'extraSpacingBetweenInterfaceMembers',
+                },
+                {
+                  data: {
+                    right: 'd',
+                    left: 'c',
+                  },
+                  messageId: 'extraSpacingBetweenInterfaceMembers',
+                },
+              ],
+              output: dedent`
+                interface Interface {
+                  a: string
+
+                  b: string
+
+                  c: string
+                  d: string
+
+
+                  e: string
+                }
+              `,
+              code: dedent`
+                interface Interface {
+                  a: string
+                  b: string
+
+
+                  c: string
+
+                  d: string
+
+
+                  e: string
+                }
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
     })
 
     ruleTester.run(
diff --git a/test/rules/sort-intersection-types.test.ts b/test/rules/sort-intersection-types.test.ts
index 7702953..24877ef 100644
--- a/test/rules/sort-intersection-types.test.ts
+++ b/test/rules/sort-intersection-types.test.ts
@@ -1121,6 +1121,83 @@ describe(ruleName, () => {
           valid: [],
         },
       )
+
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use "newlinesBetween" inside groups`,
+        rule,
+        {
+          invalid: [
+            {
+              errors: [
+                {
+                  data: {
+                    right: '{ a: string }',
+                    left: '() => void',
+                  },
+                  messageId: 'missedSpacingBetweenIntersectionTypes',
+                },
+                {
+                  data: {
+                    left: '{ a: string }',
+                    right: 'A',
+                  },
+                  messageId: 'extraSpacingBetweenIntersectionTypes',
+                },
+                {
+                  data: {
+                    right: '[A]',
+                    left: 'A',
+                  },
+                  messageId: 'extraSpacingBetweenIntersectionTypes',
+                },
+              ],
+              options: [
+                {
+                  ...options,
+                  groups: [
+                    'function',
+                    { newlinesBetween: 'always' },
+                    'object',
+                    { newlinesBetween: 'always' },
+                    'named',
+                    { newlinesBetween: 'never' },
+                    'tuple',
+                    { newlinesBetween: 'ignore' },
+                    'nullish',
+                  ],
+                  newlinesBetween: 'always',
+                },
+              ],
+              output: dedent`
+                type Type =
+                  (() => void) &
+
+                  { a: string } &
+
+                  A &
+                  [A] &
+
+
+                  null
+              `,
+              code: dedent`
+                type Type =
+                  (() => void) &
+                  { a: string } &
+
+
+                  A &
+
+                  [A] &
+
+
+                  null
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
     })
 
     ruleTester.run(
diff --git a/test/rules/sort-modules.test.ts b/test/rules/sort-modules.test.ts
index 9b8db87..237d322 100644
--- a/test/rules/sort-modules.test.ts
+++ b/test/rules/sort-modules.test.ts
@@ -2105,6 +2105,88 @@ describe(ruleName, () => {
           valid: [],
         },
       )
+
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use "newlinesBetween" inside groups`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  ...options,
+                  customGroups: [
+                    { elementNamePattern: 'a', groupName: 'a' },
+                    { elementNamePattern: 'b', groupName: 'b' },
+                    { elementNamePattern: 'c', groupName: 'c' },
+                    { elementNamePattern: 'd', groupName: 'd' },
+                    { elementNamePattern: 'e', groupName: 'e' },
+                  ],
+                  groups: [
+                    'a',
+                    { newlinesBetween: 'always' },
+                    'b',
+                    { newlinesBetween: 'always' },
+                    'c',
+                    { newlinesBetween: 'never' },
+                    'd',
+                    { newlinesBetween: 'ignore' },
+                    'e',
+                  ],
+                  newlinesBetween: 'always',
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    right: 'b',
+                    left: 'a',
+                  },
+                  messageId: 'missedSpacingBetweenModulesMembers',
+                },
+                {
+                  data: {
+                    right: 'c',
+                    left: 'b',
+                  },
+                  messageId: 'extraSpacingBetweenModulesMembers',
+                },
+                {
+                  data: {
+                    right: 'd',
+                    left: 'c',
+                  },
+                  messageId: 'extraSpacingBetweenModulesMembers',
+                },
+              ],
+              output: dedent`
+                function a() {}
+
+                function b() {}
+
+                function c() {}
+                function d() {}
+
+
+                function e() {}
+              `,
+              code: dedent`
+                function a() {}
+                function b() {}
+
+
+                function c() {}
+
+                function d() {}
+
+
+                function e() {}
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
     })
 
     describe(`${ruleName}(${type}): sorts inline elements correctly`, () => {
diff --git a/test/rules/sort-object-types.test.ts b/test/rules/sort-object-types.test.ts
index 6c6e84e..04b6a99 100644
--- a/test/rules/sort-object-types.test.ts
+++ b/test/rules/sort-object-types.test.ts
@@ -2100,6 +2100,92 @@ describe(ruleName, () => {
           valid: [],
         },
       )
+
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use "newlinesBetween" inside groups`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  ...options,
+                  customGroups: [
+                    { elementNamePattern: 'a', groupName: 'a' },
+                    { elementNamePattern: 'b', groupName: 'b' },
+                    { elementNamePattern: 'c', groupName: 'c' },
+                    { elementNamePattern: 'd', groupName: 'd' },
+                    { elementNamePattern: 'e', groupName: 'e' },
+                  ],
+                  groups: [
+                    'a',
+                    { newlinesBetween: 'always' },
+                    'b',
+                    { newlinesBetween: 'always' },
+                    'c',
+                    { newlinesBetween: 'never' },
+                    'd',
+                    { newlinesBetween: 'ignore' },
+                    'e',
+                  ],
+                  newlinesBetween: 'always',
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    right: 'b',
+                    left: 'a',
+                  },
+                  messageId: 'missedSpacingBetweenObjectTypeMembers',
+                },
+                {
+                  data: {
+                    right: 'c',
+                    left: 'b',
+                  },
+                  messageId: 'extraSpacingBetweenObjectTypeMembers',
+                },
+                {
+                  data: {
+                    right: 'd',
+                    left: 'c',
+                  },
+                  messageId: 'extraSpacingBetweenObjectTypeMembers',
+                },
+              ],
+              output: dedent`
+                type Type = {
+                  a: string
+
+                  b: string
+
+                  c: string
+                  d: string
+
+
+                  e: string
+                }
+              `,
+              code: dedent`
+                type Type = {
+                  a: string
+                  b: string
+
+
+                  c: string
+
+                  d: string
+
+
+                  e: string
+                }
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
     })
 
     ruleTester.run(
diff --git a/test/rules/sort-objects.test.ts b/test/rules/sort-objects.test.ts
index 18710ae..e0e270e 100644
--- a/test/rules/sort-objects.test.ts
+++ b/test/rules/sort-objects.test.ts
@@ -2044,6 +2044,92 @@ describe(ruleName, () => {
           valid: [],
         },
       )
+
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use "newlinesBetween" inside groups`,
+        rule,
+        {
+          invalid: [
+            {
+              options: [
+                {
+                  ...options,
+                  groups: [
+                    'a',
+                    { newlinesBetween: 'always' },
+                    'b',
+                    { newlinesBetween: 'always' },
+                    'c',
+                    { newlinesBetween: 'never' },
+                    'd',
+                    { newlinesBetween: 'ignore' },
+                    'e',
+                  ],
+                  customGroups: {
+                    a: 'a',
+                    b: 'b',
+                    c: 'c',
+                    d: 'd',
+                    e: 'e',
+                  },
+                  newlinesBetween: 'always',
+                },
+              ],
+              errors: [
+                {
+                  data: {
+                    right: 'b',
+                    left: 'a',
+                  },
+                  messageId: 'missedSpacingBetweenObjectMembers',
+                },
+                {
+                  data: {
+                    right: 'c',
+                    left: 'b',
+                  },
+                  messageId: 'extraSpacingBetweenObjectMembers',
+                },
+                {
+                  data: {
+                    right: 'd',
+                    left: 'c',
+                  },
+                  messageId: 'extraSpacingBetweenObjectMembers',
+                },
+              ],
+              output: dedent`
+                let obj = {
+                  a: 'a',
+
+                  b: 'b',
+
+                  c: 'c',
+                  d: 'd',
+
+
+                  e: 'e',
+                }
+              `,
+              code: dedent`
+                let obj = {
+                  a: 'a',
+                  b: 'b',
+
+
+                  c: 'c',
+
+                  d: 'd',
+
+
+                  e: 'e',
+                }
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
     })
 
     ruleTester.run(
diff --git a/test/rules/sort-union-types.test.ts b/test/rules/sort-union-types.test.ts
index fd058cb..39cb313 100644
--- a/test/rules/sort-union-types.test.ts
+++ b/test/rules/sort-union-types.test.ts
@@ -1124,6 +1124,83 @@ describe(ruleName, () => {
           valid: [],
         },
       )
+
+      ruleTester.run(
+        `${ruleName}(${type}): allows to use "newlinesBetween" inside groups`,
+        rule,
+        {
+          invalid: [
+            {
+              errors: [
+                {
+                  data: {
+                    right: '{ a: string }',
+                    left: '() => void',
+                  },
+                  messageId: 'missedSpacingBetweenUnionTypes',
+                },
+                {
+                  data: {
+                    left: '{ a: string }',
+                    right: 'A',
+                  },
+                  messageId: 'extraSpacingBetweenUnionTypes',
+                },
+                {
+                  data: {
+                    right: '[A]',
+                    left: 'A',
+                  },
+                  messageId: 'extraSpacingBetweenUnionTypes',
+                },
+              ],
+              options: [
+                {
+                  ...options,
+                  groups: [
+                    'function',
+                    { newlinesBetween: 'always' },
+                    'object',
+                    { newlinesBetween: 'always' },
+                    'named',
+                    { newlinesBetween: 'never' },
+                    'tuple',
+                    { newlinesBetween: 'ignore' },
+                    'nullish',
+                  ],
+                  newlinesBetween: 'always',
+                },
+              ],
+              output: dedent`
+                type Type =
+                  (() => void) |
+
+                  { a: string } |
+
+                  A |
+                  [A] |
+
+
+                  null
+              `,
+              code: dedent`
+                type Type =
+                  (() => void) |
+                  { a: string } |
+
+
+                  A |
+
+                  [A] |
+
+
+                  null
+              `,
+            },
+          ],
+          valid: [],
+        },
+      )
     })
 
     ruleTester.run(
diff --git a/test/utils/validate-groups-configuration.test.ts b/test/utils/validate-groups-configuration.test.ts
index 404a23e..50ffa47 100644
--- a/test/utils/validate-groups-configuration.test.ts
+++ b/test/utils/validate-groups-configuration.test.ts
@@ -31,4 +31,19 @@ describe('validate-groups-configuration', () => {
       )
     }).toThrow('Duplicated group(s): predefinedGroup')
   })
+
+  it('throws an error with consecutive newlines objects', () => {
+    expect(() => {
+      validateGroupsConfiguration(
+        [
+          'a',
+          { newlinesBetween: 'always' },
+          { newlinesBetween: 'always' },
+          'b',
+        ],
+        ['a', 'b'],
+        [],
+      )
+    }).toThrow("Consecutive 'newlinesBetween' objects are not allowed")
+  })
 })
diff --git a/test/utils/validate-newlines-and-partition-configuration.test.ts b/test/utils/validate-newlines-and-partition-configuration.test.ts
index e760d67..0f89307 100644
--- a/test/utils/validate-newlines-and-partition-configuration.test.ts
+++ b/test/utils/validate-newlines-and-partition-configuration.test.ts
@@ -3,41 +3,49 @@ import { describe, expect, it } from 'vitest'
 import { validateNewlinesAndPartitionConfiguration } from '../../utils/validate-newlines-and-partition-configuration'
 
 describe('validate-newlines-and-partition-configuration', () => {
-  let partitionByCommentValues: (string[] | boolean | string)[] = [
-    true,
-    'partitionComment',
-    ['partition1', 'partition2'],
-  ]
-
-  it("throws an error when 'partitionComment' is enabled and 'newlinesBetween' is not 'ignore'", () => {
+  it("throws an error when 'partitionByNewline' is enabled and 'newlinesBetween' is not 'ignore'", () => {
     let newlinesBetweenValues = ['always', 'never'] as const
 
     for (let newlinesBetween of newlinesBetweenValues) {
-      for (let partitionByComment of partitionByCommentValues) {
-        expect(() => {
-          validateNewlinesAndPartitionConfiguration({
-            partitionByNewLine: partitionByComment,
-            newlinesBetween,
-          })
-        }).toThrow(
-          "The 'partitionByNewLine' and 'newlinesBetween' options cannot be used together",
-        )
-      }
+      expect(() => {
+        validateNewlinesAndPartitionConfiguration({
+          partitionByNewLine: true,
+          newlinesBetween,
+          groups: [],
+        })
+      }).toThrow(
+        "The 'partitionByNewLine' and 'newlinesBetween' options cannot be used together",
+      )
     }
   })
 
-  it("allows 'partitionComment' when 'newlinesBetween' is 'ignore'", () => {
-    for (let partitionByComment of partitionByCommentValues) {
+  it("throws an error when 'partitionByNewline' is enabled and 'newlinesBetween' objects exist in 'groups'", () => {
+    let newlinesBetweenValues = ['always', 'never', 'ignore'] as const
+
+    for (let newlinesBetween of newlinesBetweenValues) {
       expect(() => {
         validateNewlinesAndPartitionConfiguration({
-          partitionByNewLine: partitionByComment,
+          groups: [{ newlinesBetween }],
           newlinesBetween: 'ignore',
+          partitionByNewLine: true,
         })
-      }).not.toThrow()
+      }).toThrow(
+        "'newlinesBetween' objects can not be used in 'groups' alongside 'partitionByNewLine'",
+      )
     }
   })
 
-  it("allows 'newlinesBetween' when 'partitionByComment' is 'false'", () => {
+  it("allows 'partitionByNewline' when 'newlinesBetween' is 'ignore'", () => {
+    expect(() => {
+      validateNewlinesAndPartitionConfiguration({
+        newlinesBetween: 'ignore',
+        partitionByNewLine: true,
+        groups: [],
+      })
+    }).not.toThrow()
+  })
+
+  it("allows 'newlinesBetween' when 'partitionByNewline' is 'false'", () => {
     let newlinesBetweenValues = ['always', 'never', 'ignore'] as const
 
     for (let newlinesBetween of newlinesBetweenValues) {
@@ -45,6 +53,7 @@ describe('validate-newlines-and-partition-configuration', () => {
         validateNewlinesAndPartitionConfiguration({
           partitionByNewLine: false,
           newlinesBetween,
+          groups: [],
         })
       }).not.toThrow()
     }