Skip to content

Commit

Permalink
feat: add missing newlines between validation in groups
Browse files Browse the repository at this point in the history
  • Loading branch information
hugop95 authored Feb 8, 2025
1 parent e667433 commit e6e0588
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 101 deletions.
10 changes: 5 additions & 5 deletions rules/sort-decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ export default createEslintRule<Options, MESSAGE_ID>({

let options = complete(context.options.at(0), settings, defaultOptions)
validateCustomSortConfiguration(options)
validateGroupsConfiguration(
options.groups,
['unknown'],
Object.keys(options.customGroups),
)
validateGroupsConfiguration({
allowedCustomGroups: Object.keys(options.customGroups),
allowedPredefinedGroups: ['unknown'],
options,
})

return {
Decorator: decorator => {
Expand Down
10 changes: 5 additions & 5 deletions rules/sort-heritage-clauses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ export default createEslintRule<Options, MESSAGE_ID>({

let options = complete(context.options.at(0), settings, defaultOptions)
validateCustomSortConfiguration(options)
validateGroupsConfiguration(
options.groups,
['unknown'],
Object.keys(options.customGroups),
)
validateGroupsConfiguration({
allowedCustomGroups: Object.keys(options.customGroups),
allowedPredefinedGroups: ['unknown'],
options,
})

return {
TSInterfaceDeclaration: declaration =>
Expand Down
10 changes: 5 additions & 5 deletions rules/sort-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,8 @@ export default createEslintRule<Options, MESSAGE_ID>({
} as const),
)

validateGroupsConfiguration(
options.groups,
[
validateGroupsConfiguration({
allowedPredefinedGroups: [
'side-effect-style',
'external-type',
'internal-type',
Expand All @@ -157,11 +156,12 @@ export default createEslintRule<Options, MESSAGE_ID>({
'style',
'type',
],
[
allowedCustomGroups: [
...Object.keys(options.customGroups.type ?? {}),
...Object.keys(options.customGroups.value ?? {}),
],
)
options,
})
validateCustomSortConfiguration(options)
validateNewlinesAndPartitionConfiguration(options)

Expand Down
10 changes: 5 additions & 5 deletions rules/sort-jsx-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ export default createEslintRule<Options, MESSAGE_ID>({
let settings = getSettings(context.settings)
let options = complete(context.options.at(0), settings, defaultOptions)
validateCustomSortConfiguration(options)
validateGroupsConfiguration(
options.groups,
['multiline', 'shorthand', 'unknown'],
Object.keys(options.customGroups),
)
validateGroupsConfiguration({
allowedPredefinedGroups: ['multiline', 'shorthand', 'unknown'],
allowedCustomGroups: Object.keys(options.customGroups),
options,
})
validateNewlinesAndPartitionConfiguration(options)

let sourceCode = getSourceCode(context)
Expand Down
10 changes: 5 additions & 5 deletions rules/sort-union-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,8 @@ export let sortUnionOrIntersectionTypes = <MessageIds extends string>({

let options = complete(context.options.at(0), settings, defaultOptions)
validateCustomSortConfiguration(options)
validateGroupsConfiguration(
options.groups,
[
validateGroupsConfiguration({
allowedPredefinedGroups: [
'intersection',
'conditional',
'function',
Expand All @@ -172,8 +171,9 @@ export let sortUnionOrIntersectionTypes = <MessageIds extends string>({
'tuple',
'union',
],
[],
)
allowedCustomGroups: [],
options,
})
validateNewlinesAndPartitionConfiguration(options)

let sourceCode = getSourceCode(context)
Expand Down
16 changes: 16 additions & 0 deletions test/utils/validate-generated-groups-configuration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@ describe('validate-generated-groups-configuration', () => {
}),
).toThrow('Invalid group(s): myCustomGroup')
})

it('throws an error with consecutive newlines objects', () => {
expect(() => {
validateGeneratedGroupsConfiguration({
options: {
groups: [
{ newlinesBetween: 'always' },
{ newlinesBetween: 'always' },
],
customGroups: [],
},
selectors: [],
modifiers: [],
})
}).toThrow("Consecutive 'newlinesBetween' objects are not allowed")
})
})

let getAllNonEmptyCombinations = (array: string[]): string[][] => {
Expand Down
50 changes: 30 additions & 20 deletions test/utils/validate-groups-configuration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,46 @@ import { validateGroupsConfiguration } from '../../utils/validate-groups-configu
describe('validate-groups-configuration', () => {
it('throws an error when an invalid group is provided', () => {
expect(() => {
validateGroupsConfiguration(
['predefinedGroup', ['customGroup', 'invalidGroup1'], 'invalidGroup2'],
['predefinedGroup'],
['customGroup'],
)
validateGroupsConfiguration({
options: {
groups: [
'predefinedGroup',
['customGroup', 'invalidGroup1'],
'invalidGroup2',
],
},
allowedPredefinedGroups: ['predefinedGroup'],
allowedCustomGroups: ['customGroup'],
})
}).toThrow('Invalid group(s): invalidGroup1, invalidGroup2')
})

it('throws an error when a duplicate group is provided', () => {
expect(() => {
validateGroupsConfiguration(
['predefinedGroup', 'predefinedGroup'],
['predefinedGroup'],
[],
)
validateGroupsConfiguration({
options: {
groups: ['predefinedGroup', 'predefinedGroup'],
},
allowedPredefinedGroups: ['predefinedGroup'],
allowedCustomGroups: [],
})
}).toThrow('Duplicated group(s): predefinedGroup')
})

it('throws an error with consecutive newlines objects', () => {
expect(() => {
validateGroupsConfiguration(
[
'a',
{ newlinesBetween: 'always' },
{ newlinesBetween: 'always' },
'b',
],
['a', 'b'],
[],
)
validateGroupsConfiguration({
options: {
groups: [
'a',
{ newlinesBetween: 'always' },
{ newlinesBetween: 'always' },
'b',
],
},
allowedPredefinedGroups: ['a', 'b'],
allowedCustomGroups: [],
})
}).toThrow("Consecutive 'newlinesBetween' objects are not allowed")
})
})
13 changes: 13 additions & 0 deletions test/utils/validate-newlines-between-inside-groups.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { describe, expect, it } from 'vitest'

import { validateNewlinesBetweenInsideGroups } from '../../utils/validate-newlines-between-inside-groups'

describe('validate-newlines-between-inside-groups', () => {
it('throws an error with consecutive newlines objects', () => {
expect(() => {
validateNewlinesBetweenInsideGroups({
groups: [{ newlinesBetween: 'always' }, { newlinesBetween: 'always' }],
})
}).toThrow("Consecutive 'newlinesBetween' objects are not allowed")
})
})
6 changes: 4 additions & 2 deletions utils/validate-generated-groups-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type {
GroupsOptions,
} from '../types/common-options'

import { validateNoDuplicatedGroups } from './validate-groups-configuration'
import { validateNewlinesBetweenInsideGroups } from './validate-newlines-between-inside-groups'
import { validateNoDuplicatedGroups } from './validate-no-duplicated-groups'

interface ValidateGenerateGroupsConfigurationParameters {
options: {
Expand Down Expand Up @@ -36,7 +37,8 @@ export let validateGeneratedGroupsConfiguration = ({
if (invalidGroups.length > 0) {
throw new Error(`Invalid group(s): ${invalidGroups.join(', ')}`)
}
validateNoDuplicatedGroups(options.groups)
validateNoDuplicatedGroups(options)
validateNewlinesBetweenInsideGroups(options)
}

let isPredefinedGroup = (
Expand Down
87 changes: 33 additions & 54 deletions utils/validate-groups-configuration.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,58 @@
import type { NewlinesBetweenOption } from '../types/common-options'
import type { GroupsOptions } from '../types/common-options'

import { validateNewlinesBetweenInsideGroups } from './validate-newlines-between-inside-groups'
import { validateNoDuplicatedGroups } from './validate-no-duplicated-groups'
import { isNewlinesBetweenOption } from './is-newlines-between-option'

type Group = { newlinesBetween: NewlinesBetweenOption } | string[] | string
interface ValidateGroupsConfigurationParameters {
options: {
groups: GroupsOptions<string>
}
allowedPredefinedGroups: string[]
allowedCustomGroups: 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 {Group[]} groups - The groups to validate.
* @param {string[]} allowedPredefinedGroups - An array of predefined group
* @param {object} parameters - Parameters object.
* @param {object} parameters.options - Options containing the groups to validate.
* @param {string[]} parameters.allowedPredefinedGroups - An array of predefined
* group names that are considered valid.
* @param {string[]} parameters.allowedCustomGroups - An array of custom group
* names that are considered valid.
* @param {string[]} allowedCustomGroups - An array of custom group names that
* are considered valid.
* @throws Will throw an error if invalid or duplicated groups are found.
* @throws Error Will throw an error if invalid or duplicated groups are found.
*/
export let validateGroupsConfiguration = (
groups: Group[],
allowedPredefinedGroups: string[],
allowedCustomGroups: string[],
): void => {
export let validateGroupsConfiguration = ({
allowedPredefinedGroups,
allowedCustomGroups,
options,
}: ValidateGroupsConfigurationParameters): void => {
let allowedGroupsSet = new Set([
...allowedPredefinedGroups,
...allowedCustomGroups,
])
let invalidGroups: string[] = []
let isPreviousElementNewlinesBetween = false
for (let groupElement of groups) {

for (let groupElement of options.groups) {
if (isNewlinesBetweenOption(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)
}
continue
}
let groupElements = Array.isArray(groupElement)
? groupElement
: [groupElement]
for (let group of groupElements) {
if (!allowedGroupsSet.has(group)) {
invalidGroups.push(group)
}
}
}
if (invalidGroups.length > 0) {
throw new Error(`Invalid group(s): ${invalidGroups.join(', ')}`)
}
validateNoDuplicatedGroups(groups)
}

/**
* Throws an error if a group is specified more than once
* @param {Group[]} groups - The groups to check for duplicates.
* @throws Will throw an error if duplicated groups are found.
*/
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 (isNewlinesBetweenOption(group)) {
continue
}
if (seenGroups.has(group)) {
duplicatedGroups.add(group)
} else {
seenGroups.add(group)
}
}

if (duplicatedGroups.size > 0) {
throw new Error(`Duplicated group(s): ${[...duplicatedGroups].join(', ')}`)
}
validateNoDuplicatedGroups(options)
validateNewlinesBetweenInsideGroups(options)
}
22 changes: 22 additions & 0 deletions utils/validate-newlines-between-inside-groups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { GroupsOptions } from '../types/common-options'

import { isNewlinesBetweenOption } from './is-newlines-between-option'

export let validateNewlinesBetweenInsideGroups = ({
groups,
}: {
groups: GroupsOptions<string>
}): void => {
let isPreviousElementNewlinesBetween = false
for (let groupElement of groups) {
if (!isNewlinesBetweenOption(groupElement)) {
isPreviousElementNewlinesBetween = false
continue
}
// There should not be two consecutive `newlinesBetween` objects
if (isPreviousElementNewlinesBetween) {
throw new Error("Consecutive 'newlinesBetween' objects are not allowed")
}
isPreviousElementNewlinesBetween = true
}
}
34 changes: 34 additions & 0 deletions utils/validate-no-duplicated-groups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { GroupsOptions } from '../types/common-options'

import { isNewlinesBetweenOption } from './is-newlines-between-option'

/**
* Throws an error if a group is specified more than once
* @param {object} parameters - Parameters object.
* @param {GroupsOptions} parameters.groups - The groups to check for duplicates.
* @throws Error Will throw an error if duplicated groups are found.
*/
export let validateNoDuplicatedGroups = ({
groups,
}: {
groups: GroupsOptions<string>
}): void => {
let flattenGroups = groups.flat()
let seenGroups = new Set<string>()
let duplicatedGroups = new Set<string>()

for (let group of flattenGroups) {
if (isNewlinesBetweenOption(group)) {
continue
}
if (seenGroups.has(group)) {
duplicatedGroups.add(group)
} else {
seenGroups.add(group)
}
}

if (duplicatedGroups.size > 0) {
throw new Error(`Duplicated group(s): ${[...duplicatedGroups].join(', ')}`)
}
}

0 comments on commit e6e0588

Please sign in to comment.