eslint-plugin-nextfriday 1.14.0 → 1.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # eslint-plugin-nextfriday
2
2
 
3
+ ## 1.15.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#71](https://github.com/next-friday/eslint-plugin-nextfriday/pull/71) [`4831ea6`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/4831ea697e9dfe38361b3a3577b67692ea1cd862) Thanks [@joetakara](https://github.com/joetakara)! - Update docs: add fixable info to sorting rules, add bundled plugin configs section to README.
8
+
9
+ ## 1.15.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#68](https://github.com/next-friday/eslint-plugin-nextfriday/pull/68) [`857906e`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/857906e5264ef87a988ba5429019c004360fa2a1) Thanks [@nextfridaydeveloper](https://github.com/nextfridaydeveloper)! - Add sort-imports, sort-exports, sort-type-alphabetically, jsx-sort-props, jsx-no-newline-single-line-elements rules. Add auto-fix to sorting rules. Bundle eslint-plugin-unicorn and eslint-plugin-sonarjs configs.
14
+
15
+ ### Patch Changes
16
+
17
+ - [#69](https://github.com/next-friday/eslint-plugin-nextfriday/pull/69) [`2475fc5`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/2475fc5e7d80c2b158cddbed961dbb7e4e348188) Thanks [@joetakara](https://github.com/joetakara)! - Fix CJS compatibility for bundled eslint-plugin-sonarjs and eslint-plugin-unicorn configs.
18
+
3
19
  ## 1.14.0
4
20
 
5
21
  ### Minor Changes
package/README.md CHANGED
@@ -46,6 +46,21 @@ export default [nextfriday.configs.nextjs];
46
46
  export default [nextfriday.configs["nextjs/recommended"]];
47
47
  ```
48
48
 
49
+ #### Bundled Plugin Configs
50
+
51
+ Pre-configured configs for popular plugins. No extra install needed — they ship as dependencies.
52
+
53
+ ```js
54
+ import nextfriday from "eslint-plugin-nextfriday";
55
+
56
+ export default [nextfriday.configs["react/recommended"], ...nextfriday.configs.sonarjs, ...nextfriday.configs.unicorn];
57
+ ```
58
+
59
+ | Config | Plugin | Description |
60
+ | --------- | --------------------- | ---------------------------------------------------------------------------------------------------------- |
61
+ | `sonarjs` | eslint-plugin-sonarjs | SonarJS recommended rules for bug detection and code quality |
62
+ | `unicorn` | eslint-plugin-unicorn | Unicorn recommended rules (with `filename-case` and `prevent-abbreviations` off, `no-null` off in JSX/TSX) |
63
+
49
64
  ### Manual Configuration
50
65
 
51
66
  If you prefer to configure rules manually:
@@ -94,19 +109,24 @@ export default [
94
109
  "nextfriday/no-relative-imports": "error",
95
110
  "nextfriday/prefer-import-type": "error",
96
111
  "nextfriday/prefer-react-import-types": "error",
112
+ "nextfriday/sort-exports": "error",
113
+ "nextfriday/sort-imports": "error",
97
114
 
98
115
  // Type Patterns
99
116
  "nextfriday/prefer-named-param-types": "error",
100
117
  "nextfriday/prefer-interface-over-inline-types": "error",
118
+ "nextfriday/sort-type-alphabetically": "error",
101
119
  "nextfriday/sort-type-required-first": "error",
102
120
 
103
121
  // React/JSX
104
122
  "nextfriday/jsx-newline-between-elements": "error",
105
123
  "nextfriday/jsx-no-inline-object-prop": "error",
124
+ "nextfriday/jsx-no-newline-single-line-elements": "error",
106
125
  "nextfriday/jsx-no-non-component-function": "error",
107
126
  "nextfriday/jsx-no-variable-in-callback": "error",
108
127
  "nextfriday/jsx-require-suspense": "error",
109
128
  "nextfriday/jsx-simple-props": "error",
129
+ "nextfriday/jsx-sort-props": "error",
110
130
  "nextfriday/prefer-jsx-template-literals": "error",
111
131
  "nextfriday/react-props-destructure": "error",
112
132
  "nextfriday/enforce-props-suffix": "error",
@@ -179,7 +199,7 @@ module.exports = {
179
199
  | [no-logic-in-params](docs/rules/NO_LOGIC_IN_PARAMS.md) | Disallow logic/conditions in function parameters - extract to const | ❌ |
180
200
  | [enforce-hook-naming](docs/rules/ENFORCE_HOOK_NAMING.md) | Enforce 'use' prefix for functions in \*.hook.ts files | ❌ |
181
201
  | [enforce-service-naming](docs/rules/ENFORCE_SERVICE_NAMING.md) | Enforce 'fetch' prefix for async functions in \*.service.ts files | ❌ |
182
- | [enforce-sorted-destructuring](docs/rules/ENFORCE_SORTED_DESTRUCTURING.md) | Enforce alphabetical sorting of destructured properties | |
202
+ | [enforce-sorted-destructuring](docs/rules/ENFORCE_SORTED_DESTRUCTURING.md) | Enforce alphabetical sorting of destructured properties | |
183
203
  | [no-env-fallback](docs/rules/NO_ENV_FALLBACK.md) | Disallow fallback values for environment variables | ❌ |
184
204
  | [no-inline-default-export](docs/rules/NO_INLINE_DEFAULT_EXPORT.md) | Disallow inline default exports - declare first, then export | ❌ |
185
205
  | [no-direct-date](docs/rules/NO_DIRECT_DATE.md) | Disallow direct usage of Date constructor and methods | ❌ |
@@ -198,6 +218,8 @@ module.exports = {
198
218
  | [no-relative-imports](docs/rules/NO_RELATIVE_IMPORTS.md) | Disallow relative imports with ../ - use absolute imports | ❌ |
199
219
  | [prefer-import-type](docs/rules/PREFER_IMPORT_TYPE.md) | Enforce using 'import type' for type-only imports | ✅ |
200
220
  | [prefer-react-import-types](docs/rules/PREFER_REACT_IMPORT_TYPES.md) | Enforce direct imports from 'react' instead of React.X | ✅ |
221
+ | [sort-exports](docs/rules/SORT_EXPORTS.md) | Enforce a consistent ordering of export groups | ✅ |
222
+ | [sort-imports](docs/rules/SORT_IMPORTS.md) | Enforce a consistent ordering of import groups | ✅ |
201
223
 
202
224
  ### Type Pattern Rules
203
225
 
@@ -205,22 +227,25 @@ module.exports = {
205
227
  | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- |
206
228
  | [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
207
229
  | [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
208
- | [sort-type-required-first](docs/rules/SORT_TYPE_REQUIRED_FIRST.md) | Enforce required properties before optional in types/interfaces | |
230
+ | [sort-type-alphabetically](docs/rules/SORT_TYPE_ALPHABETICALLY.md) | Enforce A-Z sorting of properties within type groups | |
231
+ | [sort-type-required-first](docs/rules/SORT_TYPE_REQUIRED_FIRST.md) | Enforce required properties before optional in types/interfaces | ✅ |
209
232
 
210
233
  ### React/JSX Rules
211
234
 
212
- | Rule | Description | Fixable |
213
- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------- |
214
- | [jsx-newline-between-elements](docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md) | Require empty lines between sibling multi-line JSX elements | ✅ |
215
- | [jsx-no-inline-object-prop](docs/rules/JSX_NO_INLINE_OBJECT_PROP.md) | Disallow inline object literals in JSX props | ❌ |
216
- | [jsx-no-non-component-function](docs/rules/JSX_NO_NON_COMPONENT_FUNCTION.md) | Disallow non-component functions at top level in .tsx/.jsx files | |
217
- | [jsx-no-variable-in-callback](docs/rules/JSX_NO_VARIABLE_IN_CALLBACK.md) | Disallow variable declarations inside callback functions in JSX | ❌ |
218
- | [jsx-require-suspense](docs/rules/JSX_REQUIRE_SUSPENSE.md) | Require lazy-loaded components to be wrapped in Suspense | ❌ |
219
- | [jsx-simple-props](docs/rules/JSX_SIMPLE_PROPS.md) | Enforce simple prop values (strings, variables, callbacks, ReactNode) | ❌ |
220
- | [prefer-jsx-template-literals](docs/rules/PREFER_JSX_TEMPLATE_LITERALS.md) | Enforce template literals instead of mixing text and JSX expressions | |
221
- | [react-props-destructure](docs/rules/REACT_PROPS_DESTRUCTURE.md) | Enforce destructuring props inside React component body | ❌ |
222
- | [enforce-props-suffix](docs/rules/ENFORCE_PROPS_SUFFIX.md) | Enforce 'Props' suffix for interfaces and types in \*.tsx files | |
223
- | [enforce-readonly-component-props](docs/rules/ENFORCE_READONLY_COMPONENT_PROPS.md) | Enforce Readonly wrapper for React component props | |
235
+ | Rule | Description | Fixable |
236
+ | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------- |
237
+ | [jsx-newline-between-elements](docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md) | Require empty lines between sibling multi-line JSX elements | ✅ |
238
+ | [jsx-no-inline-object-prop](docs/rules/JSX_NO_INLINE_OBJECT_PROP.md) | Disallow inline object literals in JSX props | ❌ |
239
+ | [jsx-no-newline-single-line-elements](docs/rules/JSX_NO_NEWLINE_SINGLE_LINE_ELEMENTS.md) | Disallow empty lines between single-line sibling JSX elements | |
240
+ | [jsx-no-non-component-function](docs/rules/JSX_NO_NON_COMPONENT_FUNCTION.md) | Disallow non-component functions at top level in .tsx/.jsx files | ❌ |
241
+ | [jsx-no-variable-in-callback](docs/rules/JSX_NO_VARIABLE_IN_CALLBACK.md) | Disallow variable declarations inside callback functions in JSX | ❌ |
242
+ | [jsx-require-suspense](docs/rules/JSX_REQUIRE_SUSPENSE.md) | Require lazy-loaded components to be wrapped in Suspense | ❌ |
243
+ | [jsx-simple-props](docs/rules/JSX_SIMPLE_PROPS.md) | Enforce simple prop values (strings, variables, callbacks, ReactNode) | |
244
+ | [jsx-sort-props](docs/rules/JSX_SORT_PROPS.md) | Enforce JSX props are sorted by value type | ❌ |
245
+ | [prefer-jsx-template-literals](docs/rules/PREFER_JSX_TEMPLATE_LITERALS.md) | Enforce template literals instead of mixing text and JSX expressions | |
246
+ | [react-props-destructure](docs/rules/REACT_PROPS_DESTRUCTURE.md) | Enforce destructuring props inside React component body | |
247
+ | [enforce-props-suffix](docs/rules/ENFORCE_PROPS_SUFFIX.md) | Enforce 'Props' suffix for interfaces and types in \*.tsx files | ❌ |
248
+ | [enforce-readonly-component-props](docs/rules/ENFORCE_READONLY_COMPONENT_PROPS.md) | Enforce Readonly wrapper for React component props | ✅ |
224
249
 
225
250
  ### Next.js Rules
226
251
 
@@ -234,14 +259,14 @@ module.exports = {
234
259
 
235
260
  | Preset | Severity | Base Rules | JSX Rules | Next.js Rules | Total Rules |
236
261
  | -------------------- | -------- | ---------- | --------- | ------------- | ----------- |
237
- | `base` | warn | 30 | 0 | 0 | 30 |
238
- | `base/recommended` | error | 30 | 0 | 0 | 30 |
239
- | `react` | warn | 30 | 12 | 0 | 42 |
240
- | `react/recommended` | error | 30 | 12 | 0 | 42 |
241
- | `nextjs` | warn | 30 | 12 | 1 | 43 |
242
- | `nextjs/recommended` | error | 30 | 12 | 1 | 43 |
262
+ | `base` | warn | 33 | 0 | 0 | 33 |
263
+ | `base/recommended` | error | 33 | 0 | 0 | 33 |
264
+ | `react` | warn | 33 | 14 | 0 | 47 |
265
+ | `react/recommended` | error | 33 | 14 | 0 | 47 |
266
+ | `nextjs` | warn | 33 | 14 | 1 | 48 |
267
+ | `nextjs/recommended` | error | 33 | 14 | 1 | 48 |
243
268
 
244
- ### Base Configuration Rules (30 rules)
269
+ ### Base Configuration Rules (33 rules)
245
270
 
246
271
  Included in `base`, `base/recommended`, and all other presets:
247
272
 
@@ -274,9 +299,12 @@ Included in `base`, `base/recommended`, and all other presets:
274
299
  - `nextfriday/prefer-named-param-types`
275
300
  - `nextfriday/prefer-react-import-types`
276
301
  - `nextfriday/require-explicit-return-type`
302
+ - `nextfriday/sort-exports`
303
+ - `nextfriday/sort-imports`
304
+ - `nextfriday/sort-type-alphabetically`
277
305
  - `nextfriday/sort-type-required-first`
278
306
 
279
- ### JSX Rules (12 rules)
307
+ ### JSX Rules (14 rules)
280
308
 
281
309
  Additionally included in `react`, `react/recommended`, `nextjs`, `nextjs/recommended`:
282
310
 
@@ -284,11 +312,13 @@ Additionally included in `react`, `react/recommended`, `nextjs`, `nextjs/recomme
284
312
  - `nextfriday/enforce-readonly-component-props`
285
313
  - `nextfriday/jsx-newline-between-elements`
286
314
  - `nextfriday/jsx-no-inline-object-prop`
315
+ - `nextfriday/jsx-no-newline-single-line-elements`
287
316
  - `nextfriday/jsx-no-non-component-function`
288
317
  - `nextfriday/jsx-no-variable-in-callback`
289
318
  - `nextfriday/jsx-pascal-case`
290
319
  - `nextfriday/jsx-require-suspense`
291
320
  - `nextfriday/jsx-simple-props`
321
+ - `nextfriday/jsx-sort-props`
292
322
  - `nextfriday/prefer-interface-over-inline-types`
293
323
  - `nextfriday/prefer-jsx-template-literals`
294
324
  - `nextfriday/react-props-destructure`
@@ -2,6 +2,8 @@
2
2
 
3
3
  Enforce alphabetical sorting of destructured properties with defaults first.
4
4
 
5
+ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
+
5
7
  ## Rule Details
6
8
 
7
9
  This rule enforces that object destructuring properties are sorted alphabetically, with properties that have default values coming first. Both groups (defaults and non-defaults) are sorted alphabetically (A-Z).
@@ -0,0 +1,76 @@
1
+ # jsx-no-newline-single-line-elements
2
+
3
+ Disallow empty lines between single-line sibling JSX elements.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces that sibling JSX elements which are both single-line should not have empty lines between them. Single-line elements should be compact and grouped together.
8
+
9
+ Use with `jsx-newline-between-elements` which requires empty lines between multi-line siblings.
10
+
11
+ ### Why?
12
+
13
+ 1. **Readability**: Single-line elements that are visually similar should be grouped together without gaps
14
+ 2. **Consistency**: Prevents inconsistent spacing between elements of the same visual weight
15
+ 3. **Complementary**: Works alongside `jsx-newline-between-elements` to create clear visual separation only where it matters
16
+
17
+ ## Examples
18
+
19
+ ### ❌ Incorrect
20
+
21
+ ```tsx
22
+ // Bad: Unnecessary empty line between single-line siblings
23
+ <div>
24
+ <Panel id="courses">Courses</Panel>
25
+
26
+ <Panel id="news">News</Panel>
27
+ </div>
28
+ ```
29
+
30
+ ```tsx
31
+ // Bad: Empty lines between single-line list items
32
+ <ul>
33
+ <li>Item 1</li>
34
+
35
+ <li>Item 2</li>
36
+
37
+ <li>Item 3</li>
38
+ </ul>
39
+ ```
40
+
41
+ ### ✅ Correct
42
+
43
+ ```tsx
44
+ // Good: Single-line siblings are compact
45
+ <div>
46
+ <Panel id="courses">Courses</Panel>
47
+ <Panel id="news">News</Panel>
48
+ </div>
49
+ ```
50
+
51
+ ```tsx
52
+ // Good: Multi-line sibling has empty line (handled by jsx-newline-between-elements)
53
+ <div>
54
+ <Panel id="overview">
55
+ <div className="grid gap-8">
56
+ <div>Content</div>
57
+ </div>
58
+ </Panel>
59
+
60
+ <Panel id="courses">Courses</Panel>
61
+ <Panel id="news">News</Panel>
62
+ </div>
63
+ ```
64
+
65
+ ```tsx
66
+ // Good: Self-closing components without empty lines
67
+ <div>
68
+ <Header />
69
+ <Main />
70
+ <Footer />
71
+ </div>
72
+ ```
73
+
74
+ ## When Not To Use It
75
+
76
+ If you prefer empty lines between all sibling JSX elements regardless of their line count, you can disable this rule.
@@ -0,0 +1,58 @@
1
+ # jsx-sort-props
2
+
3
+ Enforce JSX props are sorted by value type.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces a consistent ordering of JSX props based on the type of their value. Props must appear in the following order:
8
+
9
+ 1. **String** - String literals and template literals
10
+ 2. **Number/Boolean/Null** - Numeric literals, boolean literals, null, and undefined
11
+ 3. **Object/Array** - Inline objects and arrays
12
+ 4. **Function** - Arrow functions and function expressions
13
+ 5. **JSX Element** - JSX elements and fragments
14
+ 6. **Shorthand boolean** - Props with no value (e.g., `disabled`)
15
+
16
+ Props with values that cannot be statically determined (variables, member expressions, call expressions, etc.) are skipped and do not affect the ordering check. Spread attributes (`{...props}`) reset the ordering context.
17
+
18
+ ### Why?
19
+
20
+ - **Readability**: Grouping props by type makes components easier to scan
21
+ - **Consistency**: Enforces a uniform prop ordering convention across the codebase
22
+ - **Predictability**: Developers know where to find specific prop types at a glance
23
+
24
+ ## Examples
25
+
26
+ ### ❌ Incorrect
27
+
28
+ ```tsx
29
+ <Component disabled title="hello" />
30
+ <Component onClick={() => {}} count={42} />
31
+ <Component icon={<Icon />} style={{ color: "red" }} />
32
+ ```
33
+
34
+ ### ✅ Correct
35
+
36
+ ```tsx
37
+ <Component
38
+ title="hello"
39
+ count={100}
40
+ style={{ color: "red" }}
41
+ onClick={() => handleClick()}
42
+ icon={<HomeIcon />}
43
+ disabled
44
+ />
45
+
46
+ <Component title="hello" count={42} disabled />
47
+
48
+ <Component value={someVar} disabled />
49
+ ```
50
+
51
+ ## When Not To Use It
52
+
53
+ - If your team prefers alphabetical or custom prop ordering
54
+ - If you use a different prop sorting convention
55
+
56
+ ## Related Rules
57
+
58
+ - [jsx-simple-props](./JSX_SIMPLE_PROPS.md) - Enforce simple prop values
@@ -0,0 +1,70 @@
1
+ # sort-exports
2
+
3
+ Enforce a consistent ordering of export groups.
4
+
5
+ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
+
7
+ ## Rule Details
8
+
9
+ This rule enforces that named export statements (without declarations) are grouped and ordered by their source type. It does not enforce alphabetical sorting within groups.
10
+
11
+ ### Why?
12
+
13
+ 1. **Readability**: Grouping exports by source type makes barrel files and re-export modules easier to scan
14
+ 2. **Consistency**: A predictable export order reduces merge conflicts and code review friction
15
+ 3. **Separation of concerns**: Re-exports from external/internal sources vs local exports serve different purposes
16
+
17
+ ### Export Group Order
18
+
19
+ 1. **External/alias re-exports** — source matches a package name or alias (`@/`, `~/`, `#`) (e.g., `export { foo } from "react"`)
20
+ 2. **Relative re-exports** — source starts with `.` (e.g., `export { bar } from "../bar"`)
21
+ 3. **Local exports** — no source (e.g., `export { baz }`)
22
+
23
+ Skipped (breaks contiguity): `export default`, `export *`, `export const/function/class` (declarations).
24
+
25
+ Non-contiguous exports (separated by other statements) are checked independently.
26
+
27
+ ## Examples
28
+
29
+ ### ❌ Incorrect
30
+
31
+ ```ts
32
+ // Bad: Local before re-export
33
+ export { bar };
34
+ export { foo } from "react";
35
+ ```
36
+
37
+ ```ts
38
+ // Bad: Relative before external
39
+ export { bar } from "../bar";
40
+ export { foo } from "react";
41
+ ```
42
+
43
+ ### ✅ Correct
44
+
45
+ ```ts
46
+ // Good: All 3 groups in correct order
47
+ export { foo } from "@/lib/foo";
48
+ export { bar } from "../bar";
49
+ export { baz };
50
+ ```
51
+
52
+ ```ts
53
+ // Good: Non-contiguous exports are independent
54
+ export { foo } from "react";
55
+
56
+ const x = 1;
57
+
58
+ export { bar };
59
+ ```
60
+
61
+ ```ts
62
+ // Good: Export declarations break contiguity
63
+ export const x = 1;
64
+ export { foo } from "./foo";
65
+ export { bar };
66
+ ```
67
+
68
+ ## When Not To Use It
69
+
70
+ If you prefer a different export ordering convention or don't want to enforce any particular order for exports, you can disable this rule.
@@ -0,0 +1,80 @@
1
+ # sort-imports
2
+
3
+ Enforce a consistent ordering of import groups.
4
+
5
+ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
+
7
+ ## Rule Details
8
+
9
+ This rule enforces that import statements are grouped and ordered by their source type. It does not enforce alphabetical sorting within groups.
10
+
11
+ ### Why?
12
+
13
+ 1. **Readability**: Grouping imports by source type makes it easy to scan dependencies at a glance
14
+ 2. **Consistency**: A predictable import order reduces merge conflicts and code review friction
15
+ 3. **Separation of concerns**: Side effects, platform modules, third-party packages, internal aliases, and relative imports serve different purposes
16
+
17
+ ### Import Group Order
18
+
19
+ 1. **Side-effect imports** — no specifiers (e.g., `import "./setup"`)
20
+ 2. **Node.js builtins** — `node:` prefix or known builtin names (e.g., `import fs from "node:fs"`)
21
+ 3. **External packages** — scoped or plain package names (e.g., `import React from "react"`)
22
+ 4. **Internal aliases** — paths starting with `@/`, `~/`, or `#` (e.g., `import { utils } from "@/lib/utils"`)
23
+ 5. **Relative imports** — paths starting with `.` (e.g., `import { foo } from "../foo"`)
24
+
25
+ Type-only imports (`import type`) are skipped and do not affect ordering.
26
+
27
+ Non-contiguous imports (separated by other statements) are checked independently.
28
+
29
+ ## Examples
30
+
31
+ ### ❌ Incorrect
32
+
33
+ ```ts
34
+ // Bad: Relative before external
35
+ import { foo } from "../foo";
36
+ import React from "react";
37
+ ```
38
+
39
+ ```ts
40
+ // Bad: External before builtin
41
+ import React from "react";
42
+ import fs from "node:fs";
43
+ ```
44
+
45
+ ```ts
46
+ // Bad: Side-effect after external
47
+ import React from "react";
48
+ import "./setup";
49
+ ```
50
+
51
+ ### ✅ Correct
52
+
53
+ ```ts
54
+ // Good: All 5 groups in correct order
55
+ import "./setup";
56
+ import fs from "node:fs";
57
+ import React from "react";
58
+ import { utils } from "@/lib/utils";
59
+ import { foo } from "../foo";
60
+ ```
61
+
62
+ ```ts
63
+ // Good: Type imports can appear anywhere
64
+ import type { FC } from "react";
65
+ import { foo } from "../foo";
66
+ import React from "react";
67
+ ```
68
+
69
+ ```ts
70
+ // Good: Non-contiguous imports are independent
71
+ import React from "react";
72
+
73
+ const x = 1;
74
+
75
+ import { foo } from "../foo";
76
+ ```
77
+
78
+ ## When Not To Use It
79
+
80
+ If you use a different import sorting tool (e.g., `eslint-plugin-simple-import-sort`) or prefer a different group ordering, you can disable this rule.
@@ -0,0 +1,106 @@
1
+ # sort-type-alphabetically
2
+
3
+ Enforce alphabetical sorting of properties within required and optional groups in TypeScript interfaces and type aliases.
4
+
5
+ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6
+
7
+ ## Rule Details
8
+
9
+ This rule enforces that TypeScript interface and type alias properties are sorted alphabetically (A-Z) within their respective groups (required and optional). It checks each group independently.
10
+
11
+ ### Why?
12
+
13
+ 1. **Readability**: Alphabetical ordering makes properties easier to find
14
+ 2. **Consistency**: A predictable ordering reduces cognitive load during code review
15
+ 3. **Maintainability**: Clear structure makes it easier to add or remove properties
16
+
17
+ ### Sorting Order
18
+
19
+ Properties within each group are sorted alphabetically A-Z:
20
+
21
+ 1. **Required properties** sorted A-Z among themselves
22
+ 2. **Optional properties** sorted A-Z among themselves
23
+
24
+ Use with `sort-type-required-first` to also enforce required properties come before optional.
25
+
26
+ ## Examples
27
+
28
+ ### ❌ Incorrect
29
+
30
+ ```ts
31
+ // Bad: Required not sorted A-Z
32
+ interface Props {
33
+ src: string;
34
+ alt: string;
35
+ }
36
+ ```
37
+
38
+ ```ts
39
+ // Bad: Optional not sorted A-Z
40
+ interface Props {
41
+ b?: number;
42
+ a?: string;
43
+ }
44
+ ```
45
+
46
+ ```ts
47
+ // Bad: Required group not sorted A-Z
48
+ interface HeroBannerRootProps {
49
+ size: "detail" | "highlight" | "main";
50
+ alt: string;
51
+ src: string;
52
+ className?: string;
53
+ label?: string;
54
+ }
55
+ ```
56
+
57
+ ### ✅ Correct
58
+
59
+ ```ts
60
+ // Good: Required A-Z, optional A-Z
61
+ interface HeroBannerRootProps {
62
+ alt: string;
63
+ size: "detail" | "highlight" | "main";
64
+ src: string;
65
+ className?: string;
66
+ label?: string;
67
+ onClick?: () => void;
68
+ }
69
+ ```
70
+
71
+ ```ts
72
+ // Good: All required, sorted A-Z
73
+ interface Props {
74
+ a: string;
75
+ b: number;
76
+ c: boolean;
77
+ }
78
+ ```
79
+
80
+ ```ts
81
+ // Good: All optional, sorted A-Z
82
+ interface Props {
83
+ a?: string;
84
+ b?: number;
85
+ c?: boolean;
86
+ }
87
+ ```
88
+
89
+ ```ts
90
+ // Good: Type alias with A-Z within groups
91
+ type Props = {
92
+ alt: string;
93
+ size: string;
94
+ src: string;
95
+ label?: string;
96
+ };
97
+ ```
98
+
99
+ ## When Not To Use It
100
+
101
+ If you prefer a different sorting strategy for type properties or don't want to enforce alphabetical ordering, you can disable this rule.
102
+
103
+ ## Further Reading
104
+
105
+ - [TypeScript Interfaces](https://www.typescriptlang.org/docs/handbook/2/objects.html)
106
+ - [TypeScript Type Aliases](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-aliases)