Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds customGroup.newlinesInside option #428

Merged
merged 13 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/content/rules/sort-classes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,7 @@ interface CustomGroupDefinition {
groupName: string
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
order?: 'asc' | 'desc'
newlinesInside?: 'always' | 'never'
selector?: string
modifiers?: string[]
elementNamePattern?: string
Expand All @@ -615,6 +616,7 @@ interface CustomGroupAnyOfDefinition {
groupName: string
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
order?: 'asc' | 'desc'
newlinesInside?: 'always' | 'never'
anyOf: Array<{
selector?: string
modifiers?: string[]
Expand All @@ -637,6 +639,7 @@ A class member will match a `CustomGroupAnyOfDefinition` group if it matches all
- `decoratorNamePattern`: If entered, will check that at least one `decorator` matches the pattern entered.
- `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group.
- `order`: Overrides the sort order for that custom group
- `newlinesInside`: Enforces a specific newline behavior between elements of the group.

#### Match importance

Expand Down
1 change: 1 addition & 0 deletions docs/content/rules/sort-interfaces.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ An interface member will match a `CustomGroupAnyOfDefinition` group if it matche
- `elementNamePattern`: If entered, will check that the name of the element matches the pattern entered.
- `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group.
- `order`: Overrides the sort order for that custom group
- `newlinesInside`: Enforces a specific newline behavior between elements of the group.

#### Match importance

Expand Down
1 change: 1 addition & 0 deletions docs/content/rules/sort-modules.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ A module member will match a `CustomGroupAnyOfDefinition` group if it matches al
- `decoratorNamePattern`: If entered, will check that at least one `decorator` matches the pattern entered.
- `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group.
- `order`: Overrides the sort order for that custom group
- `newlinesInside`: Enforces a specific newline behavior between elements of the group.

#### Match importance

Expand Down
1 change: 1 addition & 0 deletions docs/content/rules/sort-object-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ An object type will match a `CustomGroupAnyOfDefinition` group if it matches all
- `elementNamePattern`: If entered, will check that the name of the element matches the pattern entered.
- `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group.
- `order`: Overrides the sort order for that custom group
- `newlinesInside`: Enforces a specific newline behavior between elements of the group.

#### Match importance

Expand Down
26 changes: 13 additions & 13 deletions rules/sort-classes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ export type SingleCustomGroup =
| BaseSingleCustomGroup<ConstructorSelector>
| AdvancedSingleCustomGroup<MethodSelector>

export type CustomGroup = (
| {
order?: SortClassesOptions[0]['order']
type?: SortClassesOptions[0]['type']
}
| {
type?: 'unsorted'
}
) & {
newlinesInside?: 'always' | 'never'
groupName: string
} & (SingleCustomGroup | AnyOfCustomGroup)

export type NonDeclarePropertyGroup = JoinWithDash<
[
PublicOrProtectedOrPrivateModifier,
Expand Down Expand Up @@ -202,19 +215,6 @@ type Group =
| 'unknown'
| string

type CustomGroup = (
| {
order?: SortClassesOptions[0]['order']
type?: SortClassesOptions[0]['type']
}
| {
type?: 'unsorted'
}
) &
(SingleCustomGroup | AnyOfCustomGroup) & {
groupName: string
}

type AdvancedSingleCustomGroup<T extends Selector> = {
decoratorNamePattern?: string
elementValuePattern?: string
Expand Down
10 changes: 8 additions & 2 deletions rules/sort-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,12 +537,15 @@ export default createEslintRule<Options<string[]>, MESSAGE_ID>({
messageIds = [
...messageIds,
...getNewlinesErrors({
options: {
...options,
customGroups: [],
},
missedSpacingError: 'missedSpacingBetweenImports',
extraSpacingError: 'extraSpacingBetweenImports',
rightNum: rightNumber,
leftNum: leftNumber,
sourceCode,
options,
right,
left,
}),
Expand All @@ -559,10 +562,13 @@ export default createEslintRule<Options<string[]>, MESSAGE_ID>({
fixer,
}),
...makeNewlinesFixes({
options: {
...options,
customGroups: [],
},
sortedNodes: sortedNodesExcludingEslintDisabled,
nodes: nodeList,
sourceCode,
options,
fixer,
}),
],
Expand Down
8 changes: 4 additions & 4 deletions rules/sort-modules/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ type CustomGroup = (
| {
type?: 'unsorted'
}
) &
(SingleCustomGroup | AnyOfCustomGroup) & {
groupName: string
}
) & {
newlinesInside?: 'always' | 'never'
groupName: string
} & (SingleCustomGroup | AnyOfCustomGroup)
/**
* Only used in code, so I don't know if it's worth maintaining this.
*/
Expand Down
8 changes: 4 additions & 4 deletions rules/sort-object-types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ type CustomGroup = (
| {
type?: 'unsorted'
}
) &
(SingleCustomGroup | AnyOfCustomGroup) & {
groupName: string
}
) & {
newlinesInside?: 'always' | 'never'
groupName: string
} & (SingleCustomGroup | AnyOfCustomGroup)

type IndexSignatureGroup = JoinWithDash<
[
Expand Down
205 changes: 205 additions & 0 deletions test/get-newlines-between-option.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import { describe, expect, it } from 'vitest'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move this file to test/utils/?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@azat-io Oops, rebase from #425 didn't move it 😅. Moved in f4b4ad5.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!


import type { GetNewlinesBetweenOptionParameters } from '../utils/get-newlines-between-option'
import type { SortingNode } from '../types/sorting-node'

import { getNewlinesBetweenOption } from '../utils/get-newlines-between-option'

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('should return "ignore" if "newlinesBetween" is "ignore"', () => {
expect(
getNewlinesBetweenOption(
buildParameters({
newlinesBetween: 'ignore',
}),
),
).toBe('ignore')
})

it('should return "never" if "newlinesBetween" is "never"', () => {
expect(
getNewlinesBetweenOption(
buildParameters({
newlinesBetween: 'never',
}),
),
).toBe('never')
})

it('should return "always" if "newlinesBetween" is "always" and nodeGroupNumber !== nextNodeGroupNumber', () => {
expect(
getNewlinesBetweenOption({
options: {
groups: ['group1', 'group2'],
newlinesBetween: 'always',
},
nextSortingNode: generateSortingNodeWithGroup('group1'),
sortingNode: generateSortingNodeWithGroup('group2'),
}),
).toBe('always')
})

it('should return "never" if "newlinesBetween" is "always" and nodeGroupNumber === nextNodeGroupNumber', () => {
expect(
getNewlinesBetweenOption({
options: {
newlinesBetween: 'always',
groups: ['group1'],
},
nextSortingNode: generateSortingNodeWithGroup('group1'),
sortingNode: generateSortingNodeWithGroup('group1'),
}),
).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', () => {
expect(
getNewlinesBetweenOption(
buildParameters({
...parameters,
customGroups: [
{
newlinesInside: 'always',
groupName: 'group1',
},
],
}),
),
).toBe('always')
})

it('should return the global option if the "newlinesInside" option is not defined', () => {
expect(
getNewlinesBetweenOption(
buildParameters({
...parameters,
customGroups: [
{
groupName: 'group1',
},
],
}),
),
).toBe('never')
})
})

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')
})
})
})

let buildParameters = ({
nextSortingNodeGroup,
sortingNodeGroup,
newlinesBetween,
customGroups,
groups,
}: {
newlinesBetween: GetNewlinesBetweenOptionParameters['options']['newlinesBetween']
customGroups?: GetNewlinesBetweenOptionParameters['options']['customGroups']
groups?: GetNewlinesBetweenOptionParameters['options']['groups']
nextSortingNodeGroup?: string
sortingNodeGroup?: string
}): GetNewlinesBetweenOptionParameters => ({
options: {
groups: groups ?? ['group1', 'group2'],
newlinesBetween,
customGroups,
},
nextSortingNode: generateSortingNodeWithGroup(
nextSortingNodeGroup ?? 'group2',
),
sortingNode: generateSortingNodeWithGroup(sortingNodeGroup ?? 'group1'),
})

let generateSortingNodeWithGroup = (group: string): SortingNode =>
({
group,
}) as SortingNode
})
Loading
Loading