Skip to content

Commit f818b4f

Browse files
authored
feat(sort-imports) add support for new groups and custom groups api
1 parent f790779 commit f818b4f

9 files changed

Lines changed: 1262 additions & 307 deletions

docs/content/rules/sort-imports.mdx

Lines changed: 163 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -288,36 +288,13 @@ Specifies the directory of the root `tsconfig.json` file (ex: `.`). This is use
288288
'internal',
289289
['parent-type', 'sibling-type', 'index-type'],
290290
['parent', 'sibling', 'index'],
291-
'object',
292291
'unknown',
293292
]
294293
```
295294
</sub>
296295

297296
Specifies a list of import groups for sorting. Groups help organize imports into meaningful categories, making your code more readable and maintainable.
298297

299-
Predefined groups:
300-
301-
- `'builtin'` — Node.js Built-in Modules.
302-
- `'external'` — External modules installed in the project.
303-
- `'internal'` — Your internal modules.
304-
- `'parent'` — Modules from the parent directory.
305-
- `'sibling'` — Modules from the same directory.
306-
- `'side-effect'` — Side effect imports.
307-
- `'side-effect-style'` — Side effect style imports.
308-
- `'index'` — Main file from the current directory.
309-
- `'object'` — TypeScript object imports.
310-
- `'style'` — Styles.
311-
- `'external-type'` — TypeScript type imports from external modules.
312-
- `'builtin-type'` — TypeScript type imports from built-in modules.
313-
- `'internal-type'` — TypeScript type imports from your internal modules.
314-
- `'parent-type'` — TypeScript type imports from the parent directory.
315-
- `'sibling-type'` — TypeScript type imports from the same directory.
316-
- `'index-type'` — TypeScript type imports from the main directory file.
317-
- `'unknown'` — Imports that don’t fit into any group specified in the `groups` option.
318-
319-
If the `unknown` group is not specified in the `groups` option, it will automatically be added to the end of the list.
320-
321298
Each import will be assigned a single group specified in the `groups` option (or the `unknown` group if no match is found).
322299
The order of items in the `groups` option determines how groups are ordered.
323300

@@ -326,7 +303,54 @@ Within a given group, members will be sorted according to the `type`, `order`, `
326303
Individual groups can be combined together by placing them in an array. The order of groups in that array does not matter.
327304
All members of the groups in the array will be sorted together as if they were part of a single group.
328305

329-
#### Example
306+
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.
307+
308+
#### Selectors
309+
310+
The list of selectors is sorted from most to least important:
311+
312+
- `'type'` — TypeScript type imports.
313+
- `'side-effect-style'` — Side effect style imports.
314+
- `'side-effect'` — Side effect imports.
315+
- `'style'` — Styles.
316+
- `'index'` — Main file from the current directory.
317+
- `'sibling'` — Modules from the same directory.
318+
- `'parent'` — Modules from the parent directory.
319+
- `'internal'` — Your internal modules.
320+
- `'builtin'` — Node.js Built-in Modules.
321+
- `'external'` — External modules installed in the project.
322+
323+
#### Modifiers
324+
325+
- `'type'` — Typescript time imports.
326+
327+
#### Important notes
328+
329+
##### The `unknown` group
330+
331+
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,
332+
the members will remain in their original order.
333+
334+
##### Behavior when multiple groups match an element
335+
336+
The lists of selectors and modifiers above are both sorted by importance, from most to least important.
337+
In case of multiple groups matching an element, the following rules will be applied:
338+
339+
1. Selector priority: `type`, `index`, ... will take precedence over `external` groups for example.
340+
2. If the selector is the same, the group with the most modifiers matching will be selected.
341+
342+
Example 1:
343+
344+
```ts
345+
import type { FC } from 'react'
346+
```
347+
348+
`react` can be matched by the following groups, from most to least important:
349+
- `type` (`type` selector).
350+
- `type-external` (`type` modifier).
351+
- `external`.
352+
353+
Example 2 (The most important group is written in the comments):
330354

331355
```ts
332356
// 'builtin' - Node.js Built-in Modules
@@ -345,21 +369,19 @@ import './set-production-env.js'
345369
import './styles.scss'
346370
// 'index' - Main file from the current directory
347371
import main from '.'
348-
// 'object' - TypeScript object-imports
349-
import log = console.log
350372
// 'style' - Styles
351373
import styles from './index.module.css'
352-
// 'external-type' - TypeScript type imports
374+
// 'type-external' - TypeScript type imports
353375
import type { FC } from 'react'
354-
// 'builtin-type' - TypeScript type imports from Built-in Modules
376+
// 'type-builtin' - TypeScript type imports from Built-in Modules
355377
import type { Server } from 'http'
356-
// 'internal-type' - TypeScript type imports from your internal modules
378+
// 'type-internal' - TypeScript type imports from your internal modules
357379
import type { User } from '~/users'
358-
// 'parent-type' - TypeScript type imports from parent directory
380+
// 'type-parent' - TypeScript type imports from parent directory
359381
import type { InputProps } from '../Input'
360-
// 'sibling-type' - TypeScript type imports from the same directory
382+
// 'type-sibling' - TypeScript type imports from the same directory
361383
import type { Details } from './data'
362-
// 'index-type' - TypeScript type imports from main directory file
384+
// 'type-index' - TypeScript type imports from main directory file
363385
import type { BaseOptions } from './index.d.ts'
364386
```
365387

@@ -384,25 +406,110 @@ This feature is only applicable when [`partitionByNewLine`](#partitionbynewline)
384406

385407
### customGroups
386408

387-
<sub>
388-
type:
389-
```
409+
<Important title="Migrating from the old API">
410+
Support for the object-based `customGroups` option is deprecated.
411+
412+
Here is how to migrate from the old to the current API:
413+
414+
Old API:
415+
```ts
416+
{
417+
value: {
418+
"keyForValue1": "value1",
419+
"keyForValue2": "value2"
420+
},
421+
type: {
422+
"keyForType1": "value1",
423+
"keyForType2": "value2"
424+
}
425+
}
426+
```
427+
428+
Current API:
429+
```ts
430+
[
390431
{
391-
value: { [groupName: string]: string | string[] }
392-
type: { [groupName: string]: string | string[] }
432+
"selector": "type",
433+
"groupName": "keyForType1",
434+
"elementNamePattern": "value1"
435+
},
436+
{
437+
"selector": "type",
438+
"groupName": "keyForType2",
439+
"elementNamePattern": "value2"
440+
},
441+
{
442+
"groupName": "keyForValue1",
443+
"elementNamePattern": "value1"
444+
},
445+
{
446+
"groupName": "keyForValue2",
447+
"elementNamePattern": "value2"
393448
}
394-
```
449+
]
450+
```
451+
</Important>
452+
453+
<sub>
454+
type: `Array<CustomGroupDefinition | CustomGroupAnyOfDefinition>`
395455
</sub>
396-
<sub>default: `{ value: {}, type: {} }`</sub>
456+
<sub>default: `[]`</sub>
457+
458+
You can define your own groups and use regex for matching very specific imports.
459+
460+
A custom group definition may follow one of the two following interfaces:
461+
462+
```ts
463+
interface CustomGroupDefinition {
464+
groupName: string
465+
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
466+
order?: 'asc' | 'desc'
467+
fallbackSort?: { type: string; order?: 'asc' | 'desc' }
468+
newlinesInside?: 'always' | 'never'
469+
selector?: string
470+
modifiers?: string[]
471+
elementNamePattern?: string | string[] | { pattern: string; flags?: string } | { pattern: string; flags?: string }[]
472+
}
473+
```
474+
An import will match a `CustomGroupDefinition` group if it matches all the filters of the custom group's definition.
475+
476+
or:
477+
478+
```ts
479+
interface CustomGroupAnyOfDefinition {
480+
groupName: string
481+
type?: 'alphabetical' | 'natural' | 'line-length' | 'unsorted'
482+
order?: 'asc' | 'desc'
483+
fallbackSort?: { type: string; order?: 'asc' | 'desc' }
484+
newlinesInside?: 'always' | 'never'
485+
anyOf: Array<{
486+
selector?: string
487+
modifiers?: string[]
488+
elementNamePattern?: string | string[] | { pattern: string; flags?: string } | { pattern: string; flags?: string }[]
489+
}>
490+
}
491+
```
492+
493+
An import will match a `CustomGroupAnyOfDefinition` group if it matches all the filters of at least one of the `anyOf` items.
494+
495+
#### Attributes
496+
497+
- `groupName` — The group's name, which needs to be put in the [`groups`](#groups) option.
498+
- `selector` — Filter on the `selector` of the element.
499+
- `modifiers` — Filter on the `modifiers` of the element. (All the modifiers of the element must be present in that list)
500+
- `elementNamePattern` — If entered, will check that the name of the element matches the pattern entered.
501+
- `type` — Overrides the [`type`](#type) option for that custom group. `unsorted` will not sort the group.
502+
- `order` — Overrides the [`order`](#order) option for that custom group.
503+
- `fallbackSort` — Overrides the [`fallbackSort`](#fallbacksort) option for that custom group.
504+
- `newlinesInside` — Enforces a specific newline behavior between elements of the group.
397505

398-
Defines custom groups to match specific imports.
506+
#### Match importance
399507

400-
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:
401-
- `string` — An import matching the value will be marked as part of the group referenced by the key.
402-
- `string[]` — An import matching any of the values of the array will be marked as part of the group referenced by the key.
403-
The order of values in the array does not matter.
508+
The `customGroups` list is ordered:
509+
The first custom group definition that matches an element will be used.
404510

405-
Custom group matching takes precedence over predefined group matching.
511+
Custom groups have a higher priority than any predefined group. If you want a predefined group to take precedence over a custom group,
512+
you must write a custom group definition that does the same as what the predefined group does (using `selector` and `modifiers` filters), and put it first in the list.
406513

407514
#### Example
408515

@@ -416,18 +523,18 @@ Custom group matching takes precedence over predefined group matching.
416523
'internal',
417524
['parent-type', 'sibling-type', 'index-type'],
418525
['parent', 'sibling', 'index'],
419-
'object',
420526
'unknown',
421527
],
422-
+ customGroups: { // [!code ++]
423-
+ value: { // [!code ++]
424-
+ react: ['^react$', '^react-.+'], // [!code ++]
425-
+ lodash: 'lodash', // [!code ++]
528+
+ customGroups: [ // [!code ++]
529+
+ { // [!code ++]
530+
+ groupName: 'react', // [!code ++]
531+
+ elementNamePattern: ['^react$', '^react-.+'], // [!code ++]
426532
+ }, // [!code ++]
427-
+ type: { // [!code ++]
428-
+ react: ['^react$', '^react-.+'], // [!code ++]
429-
+ } // [!code ++]
430-
+ }, // [!code ++]
533+
+ { // [!code ++]
534+
+ groupName: 'lodash', // [!code ++]
535+
+ elementNamePattern: 'lodash', // [!code ++]
536+
+ } // [!code ++]
537+
+ ], // [!code ++]
431538
}
432539
```
433540

@@ -472,10 +579,9 @@ Specifies which environment’s built-in modules should be recognized. If you ar
472579
'internal',
473580
['parent-type', 'sibling-type', 'index-type'],
474581
['parent', 'sibling', 'index'],
475-
'object',
476582
'unknown',
477583
],
478-
customGroups: { type: {}, value: {} },
584+
customGroups: [],
479585
environment: 'node',
480586
},
481587
],
@@ -514,10 +620,9 @@ Specifies which environment’s built-in modules should be recognized. If you ar
514620
'internal',
515621
['parent-type', 'sibling-type', 'index-type'],
516622
['parent', 'sibling', 'index'],
517-
'object',
518623
'unknown',
519624
],
520-
customGroups: { type: {}, value: {} },
625+
customGroups: [],
521626
environment: 'node',
522627
},
523628
],

0 commit comments

Comments
 (0)