Skip to content

Commit afdda90

Browse files
authored
feat(sort-objects): add array-based custom groups option
1 parent 4def6db commit afdda90

14 files changed

+1202
-113
lines changed

docs/content/rules/sort-array-includes.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ Predefined groups are characterized by a selector.
308308
</sub>
309309
<sub>default: `{}`</sub>
310310

311-
You can define your own groups and use regexp pattern to match specific object type members.
311+
You can define your own groups and use regexp patterns to match specific object type members.
312312

313313
A custom group definition may follow one of the two following interfaces:
314314

docs/content/rules/sort-imports.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ This feature is only applicable when `partitionByNewLine` is false.
369369
</sub>
370370
<sub>default: `{ value: {}, type: {} }`</sub>
371371

372-
You can define your own groups and use regexp pattern to match specific imports.
372+
You can define your own groups and use regexp patterns to match specific imports.
373373

374374
Each key of the `value` or `type` fields represents a group name which you can then use in the `groups` option. The value for each key can either be of type:
375375
- `string` — An import matching the value will be marked as part of the group referenced by the key.

docs/content/rules/sort-interfaces.mdx

+2
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ interface CustomGroupDefinition {
477477
groupName: string
478478
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
479479
order?: 'asc' | 'desc'
480+
newlinesInside?: 'always' | 'never'
480481
selector?: string
481482
modifiers?: string[]
482483
elementNamePattern?: string
@@ -492,6 +493,7 @@ interface CustomGroupAnyOfDefinition {
492493
groupName: string
493494
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
494495
order?: 'asc' | 'desc'
496+
newlinesInside?: 'always' | 'never'
495497
anyOf: Array<{
496498
selector?: string
497499
modifiers?: string[]

docs/content/rules/sort-jsx-props.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ All members of the groups in the array will be sorted together as if they were p
232232
</sub>
233233
<sub>default: `{}`</sub>
234234

235-
You can define your own groups and use regexp pattern to match specific JSX attributes.
235+
You can define your own groups and use regexp patterns to match specific JSX attributes.
236236

237237
Each key of `customGroups` represents a group name which you can then use in the `groups` option. The value for each key can either be of type:
238238
- `string` — A JSX prop's name matching the value will be marked as part of the group referenced by the key.

docs/content/rules/sort-modules.mdx

+2
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ interface CustomGroupDefinition {
401401
groupName: string
402402
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
403403
order?: 'asc' | 'desc'
404+
newlinesInside?: 'always' | 'never'
404405
selector?: string
405406
modifiers?: string[]
406407
elementNamePattern?: string
@@ -416,6 +417,7 @@ interface CustomGroupAnyOfDefinition {
416417
groupName: string
417418
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
418419
order?: 'asc' | 'desc'
420+
newlinesInside?: 'always' | 'never'
419421
anyOf: Array<{
420422
selector?: string
421423
modifiers?: string[]

docs/content/rules/sort-object-types.mdx

+3-1
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ Current API:
433433
</sub>
434434
<sub>default: `[]`</sub>
435435
436-
You can define your own groups and use regexp pattern to match specific object type members.
436+
You can define your own groups and use regexp patterns to match specific object type members.
437437
438438
A custom group definition may follow one of the two following interfaces:
439439
@@ -442,6 +442,7 @@ interface CustomGroupDefinition {
442442
groupName: string
443443
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
444444
order?: 'asc' | 'desc'
445+
newlinesInside?: 'always' | 'never'
445446
selector?: string
446447
modifiers?: string[]
447448
elementNamePattern?: string
@@ -457,6 +458,7 @@ interface CustomGroupAnyOfDefinition {
457458
groupName: string
458459
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
459460
order?: 'asc' | 'desc'
461+
newlinesInside?: 'always' | 'never'
460462
anyOf: Array<{
461463
selector?: string
462464
modifiers?: string[]

docs/content/rules/sort-objects.mdx

+183-37
Original file line numberDiff line numberDiff line change
@@ -365,55 +365,194 @@ Example configuration:
365365

366366
Allows you to specify a list of object keys groups for sorting. Groups help organize object keys into categories, making your objects more readable and maintainable.
367367

368-
Predefined groups:
369-
370-
- `'multiline'` — Properties with multiline definitions, such as methods or complex type declarations.
371-
- `'method'` - Members that are methods.
372-
- `'unknown'` — Properties that don’t fit into any group specified in the `groups` option.
373-
374-
If the `unknown` group is not specified in the `groups` option, it will automatically be added to the end of the list.
375-
376-
Each object member will be assigned a single group specified in the `groups` option (or the `unknown` group if no match is found).
368+
Each property will be assigned a single group specified in the `groups` option (or the `unknown` group if no match is found).
377369
The order of items in the `groups` option determines how groups are ordered.
378370

379371
Within a given group, members will be sorted according to the `type`, `order`, `ignoreCase`, etc. options.
380372

381373
Individual groups can be combined together by placing them in an array. The order of groups in that array does not matter.
382374
All members of the groups in the array will be sorted together as if they were part of a single group.
383375

376+
Predefined groups are characterized by a single selector and potentially multiple modifiers. You may enter modifiers in any order, but the selector must always come at the end.
377+
378+
#### Example
379+
380+
```ts
381+
let user = {
382+
firstName: "John", // unknown
383+
lastName: "Doe", // unknown
384+
username: "john_doe", // unknown
385+
job: { // multiline-member
386+
// Stuff about job
387+
},
388+
localization: { // multiline-member
389+
// Stuff about localization
390+
}
391+
}
392+
```
393+
394+
`groups` option configuration:
395+
396+
```js
397+
{
398+
groups: [
399+
'unknown',
400+
'method',
401+
'multiline-member',
402+
]
403+
}
404+
405+
```
406+
407+
#### Methods
408+
409+
- Selectors: `method`, `member`.
410+
- Modifiers: `multiline`.
411+
- Example: `multiline-method`, `method`, `member`.
412+
413+
#### Properties
414+
415+
- Selectors: `property`, `member`.
416+
- Modifiers: `multiline`.
417+
- Example: `multiline-property`, `property`, `member`.
418+
419+
##### The `unknown` group
420+
421+
Members that don’t fit into any group specified in the `groups` option will be placed in the `unknown` group. If the `unknown` group is not specified in the `groups` option,
422+
it will automatically be added to the end of the list.
423+
424+
##### Behavior when multiple groups match an element
425+
426+
The lists of modifiers above are sorted by importance, from most to least important.
427+
In case of multiple groups matching an element, the following rules will be applied:
428+
429+
1. The group with the most modifiers matching will be selected.
430+
2. If modifiers quantity is the same, order will be chosen based on modifier importance as listed above.
431+
432+
Example :
433+
434+
```ts
435+
interface Test {
436+
multilineMethod: () => {
437+
property: string;
438+
}
439+
}
440+
```
441+
442+
`multilineMethod` can be matched by the following groups, from most to least important:
443+
- `multiline-method`.
444+
- `method`.
445+
- `multiline-member`.
446+
- `member`.
447+
- `unknown`.
448+
384449
### customGroups
385450

451+
<Important title="Migrating from the old API">
452+
Support for the object-based `customGroups` option is deprecated.
453+
454+
Migrating from the old to the current API is easy:
455+
456+
Old API:
457+
```ts
458+
{
459+
"key1": "value1",
460+
"key2": "value2"
461+
}
462+
```
463+
464+
Current API:
465+
```ts
466+
[
467+
{
468+
"groupName": "key1",
469+
"elementNamePattern": "value1"
470+
},
471+
{
472+
"groupName": "key2",
473+
"elementNamePattern": "value2"
474+
}
475+
]
476+
```
477+
</Important>
478+
386479
<sub>
387480
type: `{ [groupName: string]: string | string[] }`
388481
</sub>
389-
<sub>default: `{}`</sub>
482+
<sub>default: `[]`</sub>
390483

391-
You can define your own groups and use regexp pattern to match specific object keys.
484+
You can define your own groups and use regexp patterns to match specific object keys.
392485

393-
Each key of `customGroups` represents a group name which you can then use in the `groups` option. The value for each key can either be of type:
394-
- `string` — An object attribute's name matching the value will be marked as part of the group referenced by the key.
395-
- `string[]` — An object attribute's name matching any of the values of the array will be marked as part of the group referenced by the key.
396-
The order of values in the array does not matter.
486+
A custom group definition may follow one of the two following interfaces:
397487

398-
Custom group matching takes precedence over predefined group matching.
488+
```ts
489+
interface CustomGroupDefinition {
490+
groupName: string
491+
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
492+
order?: 'asc' | 'desc'
493+
newlinesInside?: 'always' | 'never'
494+
selector?: string
495+
modifiers?: string[]
496+
elementNamePattern?: string
497+
elementValuePattern?: string
498+
}
499+
500+
```
501+
An object will match a `CustomGroupDefinition` group if it matches all the filters of the custom group's definition.
502+
503+
or:
504+
505+
```ts
506+
interface CustomGroupAnyOfDefinition {
507+
groupName: string
508+
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
509+
order?: 'asc' | 'desc'
510+
newlinesInside?: 'always' | 'never'
511+
anyOf: Array<{
512+
selector?: string
513+
modifiers?: string[]
514+
elementNamePattern?: string
515+
elementValuePattern?: string
516+
}>
517+
}
518+
```
519+
520+
An object will match a `CustomGroupAnyOfDefinition` group if it matches all the filters of at least one of the `anyOf` items.
521+
522+
#### Attributes
523+
524+
- `groupName`: The group's name, which needs to be put in the `groups` option.
525+
- `selector`: Filter on the `selector` of the element.
526+
- `modifiers`: Filter on the `modifiers` of the element. (All the modifiers of the element must be present in that list)
527+
- `elementNamePattern`: If entered, will check that the name of the element matches the pattern entered.
528+
- `elementValuePattern`: Only for non-function properties. If entered, will check that the value of the property matches the pattern entered.
529+
- `type`: Overrides the sort type for that custom group. `unsorted` will not sort the group.
530+
- `order`: Overrides the sort order for that custom group
531+
- `newlinesInside`: Enforces a specific newline behavior between elements of the group.
532+
533+
#### Match importance
534+
535+
The `customGroups` list is ordered:
536+
The first custom group definition that matches an element will be used.
537+
538+
Custom groups have a higher priority than any predefined group.
399539

400540
#### Example
401541

402-
Put all properties starting with `id` and `name` at the top, put metadata at the bottom.
403-
Regroup multiline and in the middle, above unknown-matched properties.
542+
Put all properties starting with `id` and `name` at the top, combine and sort metadata and multiline properties at the bottom.
543+
Anything else is put in the middle.
404544

405545
```ts
406-
const user = {
407-
id: 'id', // top
408-
name: 'John', // top
409-
getEmail: () => null, // method
410-
localization: { // multiline
546+
let user = {
547+
id: "id", // top
548+
name: "John", // top
549+
age: 42, // unknown
550+
isAdmin: true, // unknown
551+
lastUpdated_metadata: null, // bottom
552+
localization: { // multiline-member
411553
// Stuff about localization
412554
},
413-
age: 40, // unknown
414-
isAdmin: false, // unknown
415-
lastUpdated_metadata: null, // bottom
416-
version_metadata: '1' // bottom
555+
version_metadata: "1" // bottom
417556
}
418557
```
419558

@@ -422,15 +561,22 @@ const user = {
422561
```js
423562
{
424563
groups: [
425-
+ 'top', // [!code ++]
426-
['multiline', 'method'], // [!code ++]
427-
['unknown'], // [!code ++]
428-
'bottom' // [!code ++]
564+
+ 'top', // [!code ++]
565+
'unknown',
566+
+ ['multiline-member', 'bottom'] // [!code ++]
429567
],
430-
+ customGroups: { // [!code ++]
431-
+ top: ['^id$', '^name$'] // [!code ++]
432-
+ bottom: '.+_metadata$' // [!code ++]
433-
+ } // [!code ++]
568+
+ customGroups: [ // [!code ++]
569+
+ { // [!code ++]
570+
+ groupName: 'top', // [!code ++]
571+
+ selector: 'property', // [!code ++]
572+
+ elementNamePattern: '^(?:id|name)$', // [!code ++]
573+
+ }, // [!code ++]
574+
+ { // [!code ++]
575+
+ groupName: 'bottom', // [!code ++]
576+
+ selector: 'property', // [!code ++]
577+
+ elementNamePattern: '.+_metadata$', // [!code ++]
578+
+ } // [!code ++]
579+
+ ] // [!code ++]
434580
}
435581
```
436582

@@ -465,7 +611,7 @@ const user = {
465611
ignorePattern: [],
466612
useConfigurationIf: {},
467613
groups: [],
468-
customGroups: {},
614+
customGroups: [],
469615
},
470616
],
471617
},
@@ -499,7 +645,7 @@ const user = {
499645
ignorePattern: [],
500646
useConfigurationIf: {},
501647
groups: [],
502-
customGroups: {},
648+
customGroups: [],
503649
},
504650
],
505651
},

docs/content/rules/sort-sets.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ Predefined groups are characterized by a selector.
266266
</sub>
267267
<sub>default: `{}`</sub>
268268

269-
You can define your own groups and use regexp pattern to match specific object type members.
269+
You can define your own groups and use regexp patterns to match specific object type members.
270270

271271
A custom group definition may follow one of the two following interfaces:
272272

rules/sort-classes/types.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { JoinWithDash } from '../../types/join-with-dash'
55
import {
66
buildCustomGroupModifiersJsonSchema,
77
buildCustomGroupSelectorJsonSchema,
8+
elementValuePatternJsonSchema,
89
elementNamePatternJsonSchema,
910
} from '../../utils/common-json-schemas'
1011

@@ -319,15 +320,12 @@ export let allModifiers: Modifier[] = [
319320
* that users do not enter invalid modifiers for a given selector
320321
*/
321322
export let singleCustomGroupJsonSchema: Record<string, JSONSchema4> = {
322-
elementValuePattern: {
323-
description: 'Element value pattern filter for properties.',
324-
type: 'string',
325-
},
326323
decoratorNamePattern: {
327324
description: 'Decorator name pattern filter.',
328325
type: 'string',
329326
},
330327
modifiers: buildCustomGroupModifiersJsonSchema(allModifiers),
331328
selector: buildCustomGroupSelectorJsonSchema(allSelectors),
329+
elementValuePattern: elementValuePatternJsonSchema,
332330
elementNamePattern: elementNamePatternJsonSchema,
333331
}

0 commit comments

Comments
 (0)