Repository: azat-io/eslint-plugin-perfectionist
Pull request #502: fix: fix invalid `newlinesBetween` result enforced
Author: login: hugop95
Created: 2025-03-30T09:57:28Z | Merged: 2025-03-31T06:29:42Z

Fixes #501

## Description

When two elements belong to different groups, we check all the `newlinesBetween` options in-between those groups to deduce if we should enforce a newline behavior or not.

A case was missing: when all in-between elements have `newlinesBetween: never`, we should enforce no newline.

## Bug severity

Low:
- Does not affect build/runtime.
- Appears in quite specific cases.

## What is the purpose of this pull request?

- [x] Bug fix


Linked issue #501: Bug: sort-imports: Using `newlinesBetween` more than once in `groups` unexpected behaviour
### Describe the bug

```js
'perfectionist/sort-imports: [
  'warn',
  {
    groups: [
      ['internal'],
      {newlinesBetween: 'never'},
      ['parent'],
      {newlinesBetween: 'never'},
      ['index', 'sibling'],
    ],
    internalPattern: ['^#'],
    newlinesBetween: 'always',
  },
],
```

With the config above, I would expect this to pass, but it doesn't:

```js
import something from '#src/something';
import another from './another'; // Warning: "Missed spacing between ..."
```

It appears that when no import occupies the `['parent']` group, the `['internal']` and `['index', 'sibling']` groups get split. See this example, which passes:

```js
import something from '#src/something';
import parent from '../parent';
import another from './another'; // No warnings!
```

I guess the correct behaviour would be: `{newlinesBetween: string}` should influence the gap between _all_ groups above and _all_ groups below, instead of just the adjacent two.

### Code example

See description

### ESLint version

9.23.0

### ESLint Plugin Perfectionist version

4.10.1

### 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.
Linked issue comments: user: login: brandongit2
created_at: 2025-04-01T03:19:32Z
body: That was so so so fast, @hugop95! Thanks!
author_association: NONE
user: login: azat-io
created_at: 2025-04-01T05:32:37Z
body: @hugop95 I think we can create release today?
author_association: OWNER
user: login: hugop95
created_at: 2025-04-01T05:59:35Z
body: @azat-io Sounds good to me
author_association: CONTRIBUTOR
user: login: azat-io
created_at: 2025-04-02T07:00:25Z
body: Fixed in e18a65aafea8b1f15c2a9ec59fecaea4d0540225.
Released in [v4.11.0](https://github.com/azat-io/eslint-plugin-perfectionist/releases/tag/v4.11.0).
author_association: OWNER

Diff:
diff --git a/test/rules/sort-array-includes.test.ts b/test/rules/sort-array-includes.test.ts
index 5942f1dac..e5e1da661 100644
--- a/test/rules/sort-array-includes.test.ts
+++ b/test/rules/sort-array-includes.test.ts
@@ -1808,6 +1808,67 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenArrayIncludesMembers',
+                      },
+                    ],
+                    output: dedent`
+                      [
+                        a,
+                        b,
+                      ].includes(value)
+                    `,
+                    code: dedent`
+                      [
+                        a,
+
+                        b,
+                      ].includes(value)
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-classes.test.ts b/test/rules/sort-classes.test.ts
index 143d2d51d..b9d78fb76 100644
--- a/test/rules/sort-classes.test.ts
+++ b/test/rules/sort-classes.test.ts
@@ -4651,6 +4651,67 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenClassMembers',
+                      },
+                    ],
+                    output: dedent`
+                      class Class {
+                        a
+                        b
+                      }
+                    `,
+                    code: dedent`
+                      class Class {
+                        a
+
+                        b
+                      }
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-enums.test.ts b/test/rules/sort-enums.test.ts
index d622cb0d9..6157a8269 100644
--- a/test/rules/sort-enums.test.ts
+++ b/test/rules/sort-enums.test.ts
@@ -1573,6 +1573,67 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'A', groupName: 'a' },
+                          { elementNamePattern: 'B', groupName: 'b' },
+                          { elementNamePattern: 'C', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'B',
+                          left: 'A',
+                        },
+                        messageId: 'extraSpacingBetweenEnumsMembers',
+                      },
+                    ],
+                    output: dedent`
+                      enum Enum {
+                        A = 'A',
+                        B = 'B',
+                      }
+                    `,
+                    code: dedent`
+                      enum Enum {
+                        A = 'A',
+
+                        B = 'B',
+                      }
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-exports.test.ts b/test/rules/sort-exports.test.ts
index 0d63e8c2e..8c5b84357 100644
--- a/test/rules/sort-exports.test.ts
+++ b/test/rules/sort-exports.test.ts
@@ -1471,6 +1471,63 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenExports',
+                      },
+                    ],
+                    output: dedent`
+                      export { a } from 'a'
+                      export { b } from 'b'
+                    `,
+                    code: dedent`
+                      export { a } from 'a'
+
+                      export { b } from 'b'
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-imports.test.ts b/test/rules/sort-imports.test.ts
index a2731ffce..f69bb3187 100644
--- a/test/rules/sort-imports.test.ts
+++ b/test/rules/sort-imports.test.ts
@@ -2199,6 +2199,65 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: {
+                          value: {
+                            unusedGroup: 'X',
+                            a: 'a',
+                            b: 'b',
+                            c: 'c',
+                          },
+                        },
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenImports',
+                      },
+                    ],
+                    output: dedent`
+                      import { a } from 'a';
+                      import { b } from 'b';
+                    `,
+                    code: dedent`
+                      import { a } from 'a';
+
+                      import { b } from 'b';
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-interfaces.test.ts b/test/rules/sort-interfaces.test.ts
index 8f8811c70..573d2ecff 100644
--- a/test/rules/sort-interfaces.test.ts
+++ b/test/rules/sort-interfaces.test.ts
@@ -2683,6 +2683,67 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenInterfaceMembers',
+                      },
+                    ],
+                    output: dedent`
+                      interface Interface {
+                        a: string
+                        b: string
+                      }
+                    `,
+                    code: dedent`
+                      interface Interface {
+                        a: string
+
+                        b: string
+                      }
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-intersection-types.test.ts b/test/rules/sort-intersection-types.test.ts
index 51540b031..c8d0367b3 100644
--- a/test/rules/sort-intersection-types.test.ts
+++ b/test/rules/sort-intersection-types.test.ts
@@ -1252,6 +1252,57 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'named',
+                          { newlinesBetween: 'never' },
+                          'tuple',
+                          { newlinesBetween: 'never' },
+                          'nullish',
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'null',
+                          left: 'A',
+                        },
+                        messageId: 'extraSpacingBetweenIntersectionTypes',
+                      },
+                    ],
+                    output: dedent`
+                      type T =
+                        A &
+                        null
+                    `,
+                    code: dedent`
+                      type T =
+                        A &
+
+                        null
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-jsx-props.test.ts b/test/rules/sort-jsx-props.test.ts
index d2f294465..8b523d9c7 100644
--- a/test/rules/sort-jsx-props.test.ts
+++ b/test/rules/sort-jsx-props.test.ts
@@ -1390,6 +1390,67 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenJSXPropsMembers',
+                      },
+                    ],
+                    output: dedent`
+                      <Component
+                        a
+                        b
+                      />
+                    `,
+                    code: dedent`
+                      <Component
+                        a
+
+                        b
+                      />
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-maps.test.ts b/test/rules/sort-maps.test.ts
index 5159ba872..122e4ce19 100644
--- a/test/rules/sort-maps.test.ts
+++ b/test/rules/sort-maps.test.ts
@@ -1402,6 +1402,67 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenMapElementsMembers',
+                      },
+                    ],
+                    output: dedent`
+                      new Map([
+                        [a, 'a'],
+                        [b, 'b'],
+                      ])
+                    `,
+                    code: dedent`
+                      new Map([
+                        [a, 'a'],
+
+                        [b, 'b'],
+                      ])
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-modules.test.ts b/test/rules/sort-modules.test.ts
index 092e7530f..a08cd3d1a 100644
--- a/test/rules/sort-modules.test.ts
+++ b/test/rules/sort-modules.test.ts
@@ -2360,6 +2360,63 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenModulesMembers',
+                      },
+                    ],
+                    output: dedent`
+                      function a() {}
+                      function b() {}
+                    `,
+                    code: dedent`
+                      function a() {}
+
+                      function b() {}
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-object-types.test.ts b/test/rules/sort-object-types.test.ts
index 5afef70e0..da0464227 100644
--- a/test/rules/sort-object-types.test.ts
+++ b/test/rules/sort-object-types.test.ts
@@ -2479,6 +2479,67 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenObjectTypeMembers',
+                      },
+                    ],
+                    output: dedent`
+                      type T = {
+                        a: string
+                        b: string
+                      }
+                    `,
+                    code: dedent`
+                      type T = {
+                        a: string
+
+                        b: string
+                      }
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-objects.test.ts b/test/rules/sort-objects.test.ts
index e4dd196f4..4d5b7bbf3 100644
--- a/test/rules/sort-objects.test.ts
+++ b/test/rules/sort-objects.test.ts
@@ -2423,6 +2423,67 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenObjectMembers',
+                      },
+                    ],
+                    output: dedent`
+                      let obj = {
+                        a: null,
+                        b: null,
+                      }
+                    `,
+                    code: dedent`
+                      let obj = {
+                        a: null,
+
+                        b: null,
+                      }
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-sets.test.ts b/test/rules/sort-sets.test.ts
index 5dfd768e4..e04b7d0c1 100644
--- a/test/rules/sort-sets.test.ts
+++ b/test/rules/sort-sets.test.ts
@@ -1755,6 +1755,67 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'a',
+                          { newlinesBetween: 'never' },
+                          'unusedGroup',
+                          { newlinesBetween: 'never' },
+                          'b',
+                          { newlinesBetween: 'always' },
+                          'c',
+                        ],
+                        customGroups: [
+                          { elementNamePattern: 'a', groupName: 'a' },
+                          { elementNamePattern: 'b', groupName: 'b' },
+                          { elementNamePattern: 'c', groupName: 'c' },
+                          { groupName: 'unusedGroup', elementNamePattern: 'X' },
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'b',
+                          left: 'a',
+                        },
+                        messageId: 'extraSpacingBetweenSetsMembers',
+                      },
+                    ],
+                    output: dedent`
+                      new Set([
+                        a,
+                        b,
+                      ])
+                    `,
+                    code: dedent`
+                      new Set([
+                        a,
+
+                        b,
+                      ])
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/rules/sort-union-types.test.ts b/test/rules/sort-union-types.test.ts
index ae9bc0b7a..170722eef 100644
--- a/test/rules/sort-union-types.test.ts
+++ b/test/rules/sort-union-types.test.ts
@@ -1255,6 +1255,57 @@ describe(ruleName, () => {
             )
           }
 
+          for (let globalNewlinesBetween of [
+            'always',
+            'ignore',
+            'never',
+          ] as const) {
+            ruleTester.run(
+              `${ruleName}(${type}): enforces no newline if the global option is "${globalNewlinesBetween}" and "newlinesBetween: never" exists between all groups`,
+              rule,
+              {
+                invalid: [
+                  {
+                    options: [
+                      {
+                        ...options,
+                        groups: [
+                          'named',
+                          { newlinesBetween: 'never' },
+                          'tuple',
+                          { newlinesBetween: 'never' },
+                          'nullish',
+                        ],
+                        newlinesBetween: globalNewlinesBetween,
+                      },
+                    ],
+                    errors: [
+                      {
+                        data: {
+                          right: 'null',
+                          left: 'A',
+                        },
+                        messageId: 'extraSpacingBetweenUnionTypes',
+                      },
+                    ],
+                    output: dedent`
+                      type T =
+                        A |
+                        null
+                    `,
+                    code: dedent`
+                      type T =
+                        A |
+
+                        null
+                    `,
+                  },
+                ],
+                valid: [],
+              },
+            )
+          }
+
           for (let [globalNewlinesBetween, groupNewlinesBetween] of [
             ['ignore', 'never'] as const,
             ['never', 'ignore'] as const,
diff --git a/test/utils/get-newlines-between-option.test.ts b/test/utils/get-newlines-between-option.test.ts
index 5cc7b5fb6..73efad972 100644
--- a/test/utils/get-newlines-between-option.test.ts
+++ b/test/utils/get-newlines-between-option.test.ts
@@ -7,46 +7,45 @@ import { getNewlinesBetweenOption } from '../../utils/get-newlines-between-optio
 
 describe('get-newlines-between-option', () => {
   describe('global "newlinesBetween" option', () => {
-    it('should return the global option if "customGroups" is not defined', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'ignore',
-          }),
-        ),
-      ).toBe('ignore')
-    })
-
-    it('should return the global option if "customGroups" is not an array', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'ignore',
-            customGroups: {},
-          }),
-        ),
-      ).toBe('ignore')
-    })
+    it.each(['always', 'ignore', 'never'] as const)(
+      'should return the global option (`%s`) if "customGroups" is not defined',
+      newlinesBetween => {
+        expect(
+          getNewlinesBetweenOption(
+            buildParameters({
+              newlinesBetween,
+            }),
+          ),
+        ).toBe(newlinesBetween)
+      },
+    )
 
-    it('should return "ignore" if "newlinesBetween" is "ignore"', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'ignore',
-          }),
-        ),
-      ).toBe('ignore')
-    })
+    it.each(['always', 'ignore', 'never'] as const)(
+      'should return the global option (`%s`) if "customGroups" is not an array',
+      newlinesBetween => {
+        expect(
+          getNewlinesBetweenOption(
+            buildParameters({
+              customGroups: {},
+              newlinesBetween,
+            }),
+          ),
+        ).toBe(newlinesBetween)
+      },
+    )
 
-    it('should return "never" if "newlinesBetween" is "never"', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'never',
-          }),
-        ),
-      ).toBe('never')
-    })
+    it.each(['ignore', 'never'] as const)(
+      'should return "%s" if "newlinesBetween" is "%s"',
+      newlinesBetween => {
+        expect(
+          getNewlinesBetweenOption(
+            buildParameters({
+              newlinesBetween,
+            }),
+          ),
+        ).toBe(newlinesBetween)
+      },
+    )
 
     it('should return "always" if "newlinesBetween" is "always" and nodeGroupNumber !== nextNodeGroupNumber', () => {
       expect(
@@ -74,120 +73,150 @@ describe('get-newlines-between-option', () => {
       ).toBe('never')
     })
 
-    it("should return the global option if the node's group is within an array", () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            customGroups: [
-              {
-                groupName: 'group1',
-              },
-            ],
-            groups: [['group1', 'group3'], 'group2'],
-            newlinesBetween: 'never',
-          }),
-        ),
-      ).toBe('never')
-    })
-
-    it("should return the global option if the next node's group is within an array", () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            customGroups: [
-              {
-                groupName: 'group1',
-              },
-            ],
-            groups: ['group1', ['group2', 'group3']],
-            newlinesBetween: 'never',
-          }),
-        ),
-      ).toBe('never')
-    })
-  })
-
-  describe('custom groups "newlinesBetween" option', () => {
-    describe('when the node and next node belong to the same custom group', () => {
-      let parameters = {
-        customGroups: [
-          {
-            newlinesInside: 'always',
-            groupName: 'group1',
-          },
-        ],
-        nextSortingNodeGroup: 'group1',
-        sortingNodeGroup: 'group1',
-        newlinesBetween: 'never',
-      } as const
-
-      it('should return the "newlinesInside" option if defined', () => {
+    it.each(['always', 'ignore', 'never'] as const)(
+      "should return the global option (`%s`) if the node's group is within an array",
+      newlinesBetween => {
         expect(
           getNewlinesBetweenOption(
             buildParameters({
-              ...parameters,
               customGroups: [
                 {
-                  newlinesInside: 'always',
                   groupName: 'group1',
                 },
               ],
+              groups: [['group1', 'group3'], 'group2'],
+              newlinesBetween,
             }),
           ),
-        ).toBe('always')
-      })
+        ).toBe(newlinesBetween)
+      },
+    )
 
-      it('should return the global option if the "newlinesInside" option is not defined', () => {
+    it.each(['always', 'ignore', 'never'] as const)(
+      "should return the global option (`%s`) if the next node's group is within an array",
+      newlinesBetween => {
         expect(
           getNewlinesBetweenOption(
             buildParameters({
-              ...parameters,
               customGroups: [
                 {
                   groupName: 'group1',
                 },
               ],
+              groups: ['group1', ['group2', 'group3']],
+              newlinesBetween,
             }),
           ),
-        ).toBe('never')
-      })
+        ).toBe(newlinesBetween)
+      },
+    )
+  })
+
+  describe('custom groups "newlinesBetween" option', () => {
+    describe('when the node and next node belong to the same custom group', () => {
+      let parameters = {
+        customGroups: [
+          {
+            newlinesInside: 'always',
+            groupName: 'group1',
+          },
+        ],
+        nextSortingNodeGroup: 'group1',
+        sortingNodeGroup: 'group1',
+      } as const
+
+      it.each(['always', 'never'] as const)(
+        'should return the "newlinesInside" option (`%s`) if defined',
+        newlinesInside => {
+          expect(
+            getNewlinesBetweenOption(
+              buildParameters({
+                ...parameters,
+                customGroups: [
+                  {
+                    groupName: 'group1',
+                    newlinesInside,
+                  },
+                ],
+                newlinesBetween: 'never',
+              }),
+            ),
+          ).toBe(newlinesInside)
+        },
+      )
+
+      it.each(['ignore', 'never'] as const)(
+        'should return the global option (`%s`) if the "newlinesInside" option is not defined',
+        newlinesBetween => {
+          expect(
+            getNewlinesBetweenOption(
+              buildParameters({
+                ...parameters,
+                customGroups: [
+                  {
+                    groupName: 'group1',
+                  },
+                ],
+                newlinesBetween,
+              }),
+            ),
+          ).toBe(newlinesBetween)
+        },
+      )
     })
 
     describe('when the node and next node do not belong to the same custom group', () => {
-      it('should return the global option', () => {
-        expect(
-          getNewlinesBetweenOption(
-            buildParameters({
-              customGroups: [
-                {
-                  groupName: 'group1',
-                },
-                {
-                  groupName: 'group2',
-                },
-              ],
-              newlinesBetween: 'never',
-            }),
-          ),
-        ).toBe('never')
-      })
+      it.each(['always', 'ignore', 'never'] as const)(
+        'should return the global option (`%s`)',
+        newlinesBetween => {
+          expect(
+            getNewlinesBetweenOption(
+              buildParameters({
+                customGroups: [
+                  {
+                    groupName: 'group1',
+                  },
+                  {
+                    groupName: 'group2',
+                  },
+                ],
+                newlinesBetween,
+              }),
+            ),
+          ).toBe(newlinesBetween)
+        },
+      )
     })
 
     describe('newlinesBetween option between two groups', () => {
-      it('should return the newlinesBetween option between two adjacent groups', () => {
-        expect(
-          getNewlinesBetweenOption(
-            buildParameters({
-              groups: ['group1', { newlinesBetween: 'always' }, 'group2'],
-              newlinesBetween: 'never',
-            }),
-          ),
-        ).toBe('always')
-      })
+      it.each([
+        { globalNewlinesBetween: 'always', newlinesBetween: 'always' },
+        { globalNewlinesBetween: 'always', newlinesBetween: 'ignore' },
+        { globalNewlinesBetween: 'always', newlinesBetween: 'never' },
+        { globalNewlinesBetween: 'ignore', newlinesBetween: 'always' },
+        { globalNewlinesBetween: 'ignore', newlinesBetween: 'ignore' },
+        { globalNewlinesBetween: 'ignore', newlinesBetween: 'never' },
+        { globalNewlinesBetween: 'never', newlinesBetween: 'always' },
+        { globalNewlinesBetween: 'never', newlinesBetween: 'ignore' },
+        { globalNewlinesBetween: 'never', newlinesBetween: 'never' },
+      ] as const)(
+        'should return the newlinesBetween option between two adjacent groups (%s)',
+        ({ globalNewlinesBetween, newlinesBetween }) => {
+          expect(
+            getNewlinesBetweenOption(
+              buildParameters({
+                groups: ['group1', { newlinesBetween }, 'group2'],
+                newlinesBetween: globalNewlinesBetween,
+              }),
+            ),
+          ).toBe(newlinesBetween)
+        },
+      )
 
       describe('non-adjacent groups', () => {
-        it('should return `always` if the global option is `always`', () => {
-          for (let newlinesBetween of ['always', 'ignore', 'never'] as const) {
+        it.each(['always', 'ignore', 'never'] as const)(
+          'should return `always` if the global option is `always`',
+          newlinesBetween => {
             expect(
               getNewlinesBetweenOption(
                 buildParameters({
@@ -201,45 +230,73 @@ describe('get-newlines-between-option', () => {
                 }),
               ),
             ).toBe('always')
-          }
-        })
+          },
+        )
 
-        it('should return `always` if `always` exists between the groups', () => {
-          expect(
-            getNewlinesBetweenOption(
-              buildParameters({
-                groups: [
-                  'group1',
-                  'someOtherGroup',
-                  { newlinesBetween: 'always' },
-                  'group2',
-                ],
-                newlinesBetween: 'never',
-              }),
-            ),
-          ).toBe('always')
-        })
+        it.each(['always', 'ignore', 'never'] as const)(
+          'should return `always` if `always` exists between the groups and global option is `%s`',
+          newlinesBetween => {
+            expect(
+              getNewlinesBetweenOption(
+                buildParameters({
+                  groups: [
+                    'group1',
+                    'someOtherGroup',
+                    { newlinesBetween: 'always' },
+                    'group2',
+                  ],
+                  newlinesBetween,
+                }),
+              ),
+            ).toBe('always')
+          },
+        )
 
-        it('should return `ignore` if `ignore` exists between the groups', () => {
-          expect(
-            getNewlinesBetweenOption(
-              buildParameters({
-                groups: [
-                  'group1',
-                  'someOtherGroup',
-                  { newlinesBetween: 'ignore' },
-                  'group2',
-                  { newlinesBetween: 'always' },
-                  'someOtherGroup2',
-                ],
-                newlinesBetween: 'never',
-              }),
-            ),
-          ).toBe('ignore')
-        })
+        it.each(['ignore', 'never'] as const)(
+          'should return `ignore` if `ignore` exists between the groups and not `always` with global option `%s`',
+          newlinesBetween => {
+            expect(
+              getNewlinesBetweenOption(
+                buildParameters({
+                  groups: [
+                    'group1',
+                    'someOtherGroup',
+                    { newlinesBetween: 'ignore' },
+                    'group2',
+                    { newlinesBetween: 'always' },
+                    'someOtherGroup2',
+                  ],
+                  newlinesBetween,
+                }),
+              ),
+            ).toBe('ignore')
+          },
+        )
 
-        it('should return the global option if no `ignore` or `always` exist', () => {
-          for (let newlinesBetween of ['always', 'ignore', 'never'] as const) {
+        it.each(['always', 'ignore', 'never'] as const)(
+          'should return `never` if there are only `never` between all groups and global option is `%s`',
+          newlinesBetween => {
+            expect(
+              getNewlinesBetweenOption(
+                buildParameters({
+                  groups: [
+                    'group1',
+                    { newlinesBetween: 'never' },
+                    'someOtherGroup',
+                    { newlinesBetween: 'never' },
+                    'group2',
+                    'someOtherGroup2',
+                  ],
+                  newlinesBetween,
+                }),
+              ),
+            ).toBe('never')
+          },
+        )
+
+        it.each(['always', 'ignore', 'never'] as const)(
+          'should return the global option (`%s`) if no `ignore` or `always` exist',
+          newlinesBetween => {
             expect(
               getNewlinesBetweenOption(
                 buildParameters({
@@ -255,8 +312,8 @@ describe('get-newlines-between-option', () => {
                 }),
               ),
             ).toBe(newlinesBetween)
-          }
-        })
+          },
+        )
       })
     })
   })
diff --git a/test/utils/validate-custom-sort-configuration.test.ts b/test/utils/validate-custom-sort-configuration.test.ts
index 9efb5b7ea..38a6c4d85 100644
--- a/test/utils/validate-custom-sort-configuration.test.ts
+++ b/test/utils/validate-custom-sort-configuration.test.ts
@@ -3,16 +3,17 @@ import { describe, expect, it } from 'vitest'
 import { validateCustomSortConfiguration } from '../../utils/validate-custom-sort-configuration'
 
 describe('validate-custom-sort-configuration', () => {
-  it('accepts empty alphabet when type is not `custom`', () => {
-    for (let type of ['alphabetical', 'line-length', 'natural'] as const) {
+  it.each(['alphabetical', 'line-length', 'natural'] as const)(
+    'accepts empty alphabet when type is `%s`',
+    type => {
       expect(() =>
         validateCustomSortConfiguration({
           alphabet: '',
           type,
         }),
       ).not.toThrow()
-    }
-  })
+    },
+  )
 
   it('throws when an empty alphabet is entered while type is `custom`', () => {
     expect(() =>
diff --git a/test/utils/validate-newlines-and-partition-configuration.test.ts b/test/utils/validate-newlines-and-partition-configuration.test.ts
index 0f89307c9..e31e708c1 100644
--- a/test/utils/validate-newlines-and-partition-configuration.test.ts
+++ b/test/utils/validate-newlines-and-partition-configuration.test.ts
@@ -3,10 +3,9 @@ import { describe, expect, it } from 'vitest'
 import { validateNewlinesAndPartitionConfiguration } from '../../utils/validate-newlines-and-partition-configuration'
 
 describe('validate-newlines-and-partition-configuration', () => {
-  it("throws an error when 'partitionByNewline' is enabled and 'newlinesBetween' is not 'ignore'", () => {
-    let newlinesBetweenValues = ['always', 'never'] as const
-
-    for (let newlinesBetween of newlinesBetweenValues) {
+  it.each(['always', 'never'] as const)(
+    "throws an error when 'partitionByNewline' is enabled and 'newlinesBetween' is '%s'",
+    newlinesBetween => {
       expect(() => {
         validateNewlinesAndPartitionConfiguration({
           partitionByNewLine: true,
@@ -16,13 +15,12 @@ describe('validate-newlines-and-partition-configuration', () => {
       }).toThrow(
         "The 'partitionByNewLine' and 'newlinesBetween' options cannot be used together",
       )
-    }
-  })
-
-  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) {
+  it.each(['always', 'never', 'ignore'] as const)(
+    "throws an error when 'partitionByNewline' is enabled and `newlinesBetween: '%s'` objects exist in 'groups'",
+    newlinesBetween => {
       expect(() => {
         validateNewlinesAndPartitionConfiguration({
           groups: [{ newlinesBetween }],
@@ -32,8 +30,8 @@ describe('validate-newlines-and-partition-configuration', () => {
       }).toThrow(
         "'newlinesBetween' objects can not be used in 'groups' alongside 'partitionByNewLine'",
       )
-    }
-  })
+    },
+  )
 
   it("allows 'partitionByNewline' when 'newlinesBetween' is 'ignore'", () => {
     expect(() => {
@@ -45,10 +43,9 @@ describe('validate-newlines-and-partition-configuration', () => {
     }).not.toThrow()
   })
 
-  it("allows 'newlinesBetween' when 'partitionByNewline' is 'false'", () => {
-    let newlinesBetweenValues = ['always', 'never', 'ignore'] as const
-
-    for (let newlinesBetween of newlinesBetweenValues) {
+  it.each(['always', 'never', 'ignore'] as const)(
+    "allows `newlinesBetween: '%s'` when 'partitionByNewline' is 'false'",
+    newlinesBetween => {
       expect(() => {
         validateNewlinesAndPartitionConfiguration({
           partitionByNewLine: false,
@@ -56,6 +53,6 @@ describe('validate-newlines-and-partition-configuration', () => {
           groups: [],
         })
       }).not.toThrow()
-    }
-  })
+    },
+  )
 })
diff --git a/utils/get-newlines-between-option.ts b/utils/get-newlines-between-option.ts
index 82a5d0d94..26db69be3 100644
--- a/utils/get-newlines-between-option.ts
+++ b/utils/get-newlines-between-option.ts
@@ -79,17 +79,28 @@ export let getNewlinesBetweenOption = ({
         return groupBetween.newlinesBetween
       }
     } else {
-      if (globalNewlinesBetweenOption === 'always') {
+      let relevantGroups = options.groups.slice(
+        nodeGroupNumber,
+        nextNodeGroupNumber + 1,
+      )
+      let groupsWithAllNewlinesBetween = buildGroupsWithAllNewlinesBetween(
+        relevantGroups,
+        globalNewlinesBetweenOption,
+      )
+      let newlinesBetweenOptions = new Set(
+        groupsWithAllNewlinesBetween
+          .filter(isNewlinesBetweenOption)
+          .map(group => group.newlinesBetween),
+      )
+
+      if (newlinesBetweenOptions.has('always')) {
         return 'always'
       }
-      for (let i = nodeGroupNumber + 2; i < nextNodeGroupNumber; i++) {
-        let groupBetween = options.groups[i]!
-        if (
-          isNewlinesBetweenOption(groupBetween) &&
-          groupBetween.newlinesBetween !== 'never'
-        ) {
-          return groupBetween.newlinesBetween
-        }
+      if (newlinesBetweenOptions.has('ignore')) {
+        return 'ignore'
+      }
+      if (newlinesBetweenOptions.has('never')) {
+        return 'never'
       }
     }
   }
@@ -114,3 +125,23 @@ let getGlobalNewlinesBetweenOption = ({
   }
   return nodeGroupNumber === nextNodeGroupNumber ? 'never' : 'always'
 }
+
+let buildGroupsWithAllNewlinesBetween = (
+  groups: GroupsOptions<string>,
+  globalNewlinesBetweenOption: NewlinesBetweenOption,
+): GroupsOptions<string> => {
+  let returnValue: GroupsOptions<string> = []
+  for (let i = 0; i < groups.length; i++) {
+    let group = groups[i]!
+    if (isNewlinesBetweenOption(group)) {
+      returnValue.push(group)
+    } else {
+      let previousGroup = groups[i - 1]
+      if (previousGroup && !isNewlinesBetweenOption(previousGroup)) {
+        returnValue.push({ newlinesBetween: globalNewlinesBetweenOption })
+      }
+      returnValue.push(group)
+    }
+  }
+  return returnValue
+}


Reviews:
user: login: hugop95
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-30T10:42:43Z
user: login: hugop95
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-30T15:22:44Z
user: login: azat-io
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-31T06:27:05Z
user: login: azat-io
state: APPROVED
author_association: OWNER
submitted_at: 2025-03-31T06:28:23Z

Review comments:
diff_hunk: @@ -7,46 +7,45 @@ import { getNewlinesBetweenOption } from '../../utils/get-newlines-between-optio
 
 describe('get-newlines-between-option', () => {
   describe('global "newlinesBetween" option', () => {
-    it('should return the global option if "customGroups" is not defined', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'ignore',
-          }),
-        ),
-      ).toBe('ignore')
-    })
-
-    it('should return the global option if "customGroups" is not an array', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'ignore',
-            customGroups: {},
-          }),
-        ),
-      ).toBe('ignore')
-    })
+    it.each(['always', 'ignore', 'never'] as const)(
path: test/utils/get-newlines-between-option.test.ts
user: login: hugop95
body: ℹ️ Hide whitespace changes for this commit.
created_at: 2025-03-30T10:42:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,46 +7,45 @@ import { getNewlinesBetweenOption } from '../../utils/get-newlines-between-optio
 
 describe('get-newlines-between-option', () => {
   describe('global "newlinesBetween" option', () => {
-    it('should return the global option if "customGroups" is not defined', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'ignore',
-          }),
-        ),
-      ).toBe('ignore')
-    })
-
-    it('should return the global option if "customGroups" is not an array', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'ignore',
-            customGroups: {},
-          }),
-        ),
-      ).toBe('ignore')
-    })
+    it.each(['always', 'ignore', 'never'] as const)(
+      'should return the global option (`%s`) if "customGroups" is not defined',
+      newlinesBetween => {
+        expect(
+          getNewlinesBetweenOption(
+            buildParameters({
+              newlinesBetween,
+            }),
+          ),
+        ).toBe(newlinesBetween)
+      },
+    )
 
-    it('should return "ignore" if "newlinesBetween" is "ignore"', () => {
path: test/utils/get-newlines-between-option.test.ts
user: login: hugop95
body: This test was merged with the one below:

`should return "%s" if "newlinesBetween" is "%s"`
created_at: 2025-03-30T15:22:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -7,46 +7,45 @@ import { getNewlinesBetweenOption } from '../../utils/get-newlines-between-optio
 
 describe('get-newlines-between-option', () => {
   describe('global "newlinesBetween" option', () => {
-    it('should return the global option if "customGroups" is not defined', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'ignore',
-          }),
-        ),
-      ).toBe('ignore')
-    })
-
-    it('should return the global option if "customGroups" is not an array', () => {
-      expect(
-        getNewlinesBetweenOption(
-          buildParameters({
-            newlinesBetween: 'ignore',
-            customGroups: {},
-          }),
-        ),
-      ).toBe('ignore')
-    })
+    it.each(['always', 'ignore', 'never'] as const)(
+      'should return the global option (`%s`) if "customGroups" is not defined',
+      newlinesBetween => {
+        expect(
+          getNewlinesBetweenOption(
+            buildParameters({
+              newlinesBetween,
+            }),
+          ),
+        ).toBe(newlinesBetween)
+      },
+    )
 
-    it('should return "ignore" if "newlinesBetween" is "ignore"', () => {
path: test/utils/get-newlines-between-option.test.ts
user: login: azat-io
body: 👍 
created_at: 2025-03-31T06:27:05Z
author_association: OWNER

PR comments:
user: login: codecov[bot]
created_at: 2025-03-30T09:59:04Z
body: ## [Codecov](https://app.codecov.io/gh/azat-io/eslint-plugin-perfectionist/pull/502?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`3e500d0`)](https://app.codecov.io/gh/azat-io/eslint-plugin-perfectionist/commit/3e500d00d2ba6fe45360fc8ff76daa1d7b6d86f4?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.) to head [(`484fbd6`)](https://app.codecov.io/gh/azat-io/eslint-plugin-perfectionist/commit/484fbd60770dd12ac70e90b8ff487dfc0767e1d6?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.).
> Report is 3 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##              main      #502   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           91        91           
  Lines         7593      7622   +29     
  Branches      1581      1586    +5     
=========================================
+ Hits          7593      7622   +29     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/azat-io/eslint-plugin-perfectionist/pull/502?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Azat+S.).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE
user: login: azat-io
created_at: 2025-03-31T06:28:32Z
body: Thanks!
author_association: OWNER