eslint-plugin-nextfriday 1.14.0 → 1.15.0
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 +10 -0
- package/README.md +35 -20
- package/docs/rules/JSX_NO_NEWLINE_SINGLE_LINE_ELEMENTS.md +76 -0
- package/docs/rules/JSX_SORT_PROPS.md +58 -0
- package/docs/rules/SORT_EXPORTS.md +68 -0
- package/docs/rules/SORT_IMPORTS.md +78 -0
- package/docs/rules/SORT_TYPE_ALPHABETICALLY.md +104 -0
- package/docs/rules/SORT_TYPE_REQUIRED_FIRST.md +18 -46
- package/lib/index.cjs +880 -327
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +152 -26
- package/lib/index.d.ts +152 -26
- package/lib/index.js +882 -327
- package/lib/index.js.map +1 -1
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# eslint-plugin-nextfriday
|
|
2
2
|
|
|
3
|
+
## 1.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#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.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [#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.
|
|
12
|
+
|
|
3
13
|
## 1.14.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -94,19 +94,24 @@ export default [
|
|
|
94
94
|
"nextfriday/no-relative-imports": "error",
|
|
95
95
|
"nextfriday/prefer-import-type": "error",
|
|
96
96
|
"nextfriday/prefer-react-import-types": "error",
|
|
97
|
+
"nextfriday/sort-exports": "error",
|
|
98
|
+
"nextfriday/sort-imports": "error",
|
|
97
99
|
|
|
98
100
|
// Type Patterns
|
|
99
101
|
"nextfriday/prefer-named-param-types": "error",
|
|
100
102
|
"nextfriday/prefer-interface-over-inline-types": "error",
|
|
103
|
+
"nextfriday/sort-type-alphabetically": "error",
|
|
101
104
|
"nextfriday/sort-type-required-first": "error",
|
|
102
105
|
|
|
103
106
|
// React/JSX
|
|
104
107
|
"nextfriday/jsx-newline-between-elements": "error",
|
|
105
108
|
"nextfriday/jsx-no-inline-object-prop": "error",
|
|
109
|
+
"nextfriday/jsx-no-newline-single-line-elements": "error",
|
|
106
110
|
"nextfriday/jsx-no-non-component-function": "error",
|
|
107
111
|
"nextfriday/jsx-no-variable-in-callback": "error",
|
|
108
112
|
"nextfriday/jsx-require-suspense": "error",
|
|
109
113
|
"nextfriday/jsx-simple-props": "error",
|
|
114
|
+
"nextfriday/jsx-sort-props": "error",
|
|
110
115
|
"nextfriday/prefer-jsx-template-literals": "error",
|
|
111
116
|
"nextfriday/react-props-destructure": "error",
|
|
112
117
|
"nextfriday/enforce-props-suffix": "error",
|
|
@@ -198,6 +203,8 @@ module.exports = {
|
|
|
198
203
|
| [no-relative-imports](docs/rules/NO_RELATIVE_IMPORTS.md) | Disallow relative imports with ../ - use absolute imports | ❌ |
|
|
199
204
|
| [prefer-import-type](docs/rules/PREFER_IMPORT_TYPE.md) | Enforce using 'import type' for type-only imports | ✅ |
|
|
200
205
|
| [prefer-react-import-types](docs/rules/PREFER_REACT_IMPORT_TYPES.md) | Enforce direct imports from 'react' instead of React.X | ✅ |
|
|
206
|
+
| [sort-exports](docs/rules/SORT_EXPORTS.md) | Enforce a consistent ordering of export groups | ❌ |
|
|
207
|
+
| [sort-imports](docs/rules/SORT_IMPORTS.md) | Enforce a consistent ordering of import groups | ❌ |
|
|
201
208
|
|
|
202
209
|
### Type Pattern Rules
|
|
203
210
|
|
|
@@ -205,22 +212,25 @@ module.exports = {
|
|
|
205
212
|
| -------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- |
|
|
206
213
|
| [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
|
|
207
214
|
| [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
|
|
215
|
+
| [sort-type-alphabetically](docs/rules/SORT_TYPE_ALPHABETICALLY.md) | Enforce A-Z sorting of properties within type groups | ❌ |
|
|
208
216
|
| [sort-type-required-first](docs/rules/SORT_TYPE_REQUIRED_FIRST.md) | Enforce required properties before optional in types/interfaces | ❌ |
|
|
209
217
|
|
|
210
218
|
### React/JSX Rules
|
|
211
219
|
|
|
212
|
-
| Rule
|
|
213
|
-
|
|
|
214
|
-
| [jsx-newline-between-elements](docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md)
|
|
215
|
-
| [jsx-no-inline-object-prop](docs/rules/JSX_NO_INLINE_OBJECT_PROP.md)
|
|
216
|
-
| [jsx-no-
|
|
217
|
-
| [jsx-no-
|
|
218
|
-
| [jsx-
|
|
219
|
-
| [jsx-
|
|
220
|
-
| [
|
|
221
|
-
| [
|
|
222
|
-
| [
|
|
223
|
-
| [
|
|
220
|
+
| Rule | Description | Fixable |
|
|
221
|
+
| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------- |
|
|
222
|
+
| [jsx-newline-between-elements](docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md) | Require empty lines between sibling multi-line JSX elements | ✅ |
|
|
223
|
+
| [jsx-no-inline-object-prop](docs/rules/JSX_NO_INLINE_OBJECT_PROP.md) | Disallow inline object literals in JSX props | ❌ |
|
|
224
|
+
| [jsx-no-newline-single-line-elements](docs/rules/JSX_NO_NEWLINE_SINGLE_LINE_ELEMENTS.md) | Disallow empty lines between single-line sibling JSX elements | ✅ |
|
|
225
|
+
| [jsx-no-non-component-function](docs/rules/JSX_NO_NON_COMPONENT_FUNCTION.md) | Disallow non-component functions at top level in .tsx/.jsx files | ❌ |
|
|
226
|
+
| [jsx-no-variable-in-callback](docs/rules/JSX_NO_VARIABLE_IN_CALLBACK.md) | Disallow variable declarations inside callback functions in JSX | ❌ |
|
|
227
|
+
| [jsx-require-suspense](docs/rules/JSX_REQUIRE_SUSPENSE.md) | Require lazy-loaded components to be wrapped in Suspense | ❌ |
|
|
228
|
+
| [jsx-simple-props](docs/rules/JSX_SIMPLE_PROPS.md) | Enforce simple prop values (strings, variables, callbacks, ReactNode) | ❌ |
|
|
229
|
+
| [jsx-sort-props](docs/rules/JSX_SORT_PROPS.md) | Enforce JSX props are sorted by value type | ❌ |
|
|
230
|
+
| [prefer-jsx-template-literals](docs/rules/PREFER_JSX_TEMPLATE_LITERALS.md) | Enforce template literals instead of mixing text and JSX expressions | ✅ |
|
|
231
|
+
| [react-props-destructure](docs/rules/REACT_PROPS_DESTRUCTURE.md) | Enforce destructuring props inside React component body | ❌ |
|
|
232
|
+
| [enforce-props-suffix](docs/rules/ENFORCE_PROPS_SUFFIX.md) | Enforce 'Props' suffix for interfaces and types in \*.tsx files | ❌ |
|
|
233
|
+
| [enforce-readonly-component-props](docs/rules/ENFORCE_READONLY_COMPONENT_PROPS.md) | Enforce Readonly wrapper for React component props | ✅ |
|
|
224
234
|
|
|
225
235
|
### Next.js Rules
|
|
226
236
|
|
|
@@ -234,14 +244,14 @@ module.exports = {
|
|
|
234
244
|
|
|
235
245
|
| Preset | Severity | Base Rules | JSX Rules | Next.js Rules | Total Rules |
|
|
236
246
|
| -------------------- | -------- | ---------- | --------- | ------------- | ----------- |
|
|
237
|
-
| `base` | warn |
|
|
238
|
-
| `base/recommended` | error |
|
|
239
|
-
| `react` | warn |
|
|
240
|
-
| `react/recommended` | error |
|
|
241
|
-
| `nextjs` | warn |
|
|
242
|
-
| `nextjs/recommended` | error |
|
|
247
|
+
| `base` | warn | 33 | 0 | 0 | 33 |
|
|
248
|
+
| `base/recommended` | error | 33 | 0 | 0 | 33 |
|
|
249
|
+
| `react` | warn | 33 | 14 | 0 | 47 |
|
|
250
|
+
| `react/recommended` | error | 33 | 14 | 0 | 47 |
|
|
251
|
+
| `nextjs` | warn | 33 | 14 | 1 | 48 |
|
|
252
|
+
| `nextjs/recommended` | error | 33 | 14 | 1 | 48 |
|
|
243
253
|
|
|
244
|
-
### Base Configuration Rules (
|
|
254
|
+
### Base Configuration Rules (33 rules)
|
|
245
255
|
|
|
246
256
|
Included in `base`, `base/recommended`, and all other presets:
|
|
247
257
|
|
|
@@ -274,9 +284,12 @@ Included in `base`, `base/recommended`, and all other presets:
|
|
|
274
284
|
- `nextfriday/prefer-named-param-types`
|
|
275
285
|
- `nextfriday/prefer-react-import-types`
|
|
276
286
|
- `nextfriday/require-explicit-return-type`
|
|
287
|
+
- `nextfriday/sort-exports`
|
|
288
|
+
- `nextfriday/sort-imports`
|
|
289
|
+
- `nextfriday/sort-type-alphabetically`
|
|
277
290
|
- `nextfriday/sort-type-required-first`
|
|
278
291
|
|
|
279
|
-
### JSX Rules (
|
|
292
|
+
### JSX Rules (14 rules)
|
|
280
293
|
|
|
281
294
|
Additionally included in `react`, `react/recommended`, `nextjs`, `nextjs/recommended`:
|
|
282
295
|
|
|
@@ -284,11 +297,13 @@ Additionally included in `react`, `react/recommended`, `nextjs`, `nextjs/recomme
|
|
|
284
297
|
- `nextfriday/enforce-readonly-component-props`
|
|
285
298
|
- `nextfriday/jsx-newline-between-elements`
|
|
286
299
|
- `nextfriday/jsx-no-inline-object-prop`
|
|
300
|
+
- `nextfriday/jsx-no-newline-single-line-elements`
|
|
287
301
|
- `nextfriday/jsx-no-non-component-function`
|
|
288
302
|
- `nextfriday/jsx-no-variable-in-callback`
|
|
289
303
|
- `nextfriday/jsx-pascal-case`
|
|
290
304
|
- `nextfriday/jsx-require-suspense`
|
|
291
305
|
- `nextfriday/jsx-simple-props`
|
|
306
|
+
- `nextfriday/jsx-sort-props`
|
|
292
307
|
- `nextfriday/prefer-interface-over-inline-types`
|
|
293
308
|
- `nextfriday/prefer-jsx-template-literals`
|
|
294
309
|
- `nextfriday/react-props-destructure`
|
|
@@ -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,68 @@
|
|
|
1
|
+
# sort-exports
|
|
2
|
+
|
|
3
|
+
Enforce a consistent ordering of export groups.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
9
|
+
### Why?
|
|
10
|
+
|
|
11
|
+
1. **Readability**: Grouping exports by source type makes barrel files and re-export modules easier to scan
|
|
12
|
+
2. **Consistency**: A predictable export order reduces merge conflicts and code review friction
|
|
13
|
+
3. **Separation of concerns**: Re-exports from external/internal sources vs local exports serve different purposes
|
|
14
|
+
|
|
15
|
+
### Export Group Order
|
|
16
|
+
|
|
17
|
+
1. **External/alias re-exports** — source matches a package name or alias (`@/`, `~/`, `#`) (e.g., `export { foo } from "react"`)
|
|
18
|
+
2. **Relative re-exports** — source starts with `.` (e.g., `export { bar } from "../bar"`)
|
|
19
|
+
3. **Local exports** — no source (e.g., `export { baz }`)
|
|
20
|
+
|
|
21
|
+
Skipped (breaks contiguity): `export default`, `export *`, `export const/function/class` (declarations).
|
|
22
|
+
|
|
23
|
+
Non-contiguous exports (separated by other statements) are checked independently.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### ❌ Incorrect
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// Bad: Local before re-export
|
|
31
|
+
export { bar };
|
|
32
|
+
export { foo } from "react";
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// Bad: Relative before external
|
|
37
|
+
export { bar } from "../bar";
|
|
38
|
+
export { foo } from "react";
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### ✅ Correct
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// Good: All 3 groups in correct order
|
|
45
|
+
export { foo } from "@/lib/foo";
|
|
46
|
+
export { bar } from "../bar";
|
|
47
|
+
export { baz };
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// Good: Non-contiguous exports are independent
|
|
52
|
+
export { foo } from "react";
|
|
53
|
+
|
|
54
|
+
const x = 1;
|
|
55
|
+
|
|
56
|
+
export { bar };
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
// Good: Export declarations break contiguity
|
|
61
|
+
export const x = 1;
|
|
62
|
+
export { foo } from "./foo";
|
|
63
|
+
export { bar };
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## When Not To Use It
|
|
67
|
+
|
|
68
|
+
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,78 @@
|
|
|
1
|
+
# sort-imports
|
|
2
|
+
|
|
3
|
+
Enforce a consistent ordering of import groups.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule enforces that import statements are grouped and ordered by their source type. It does not enforce alphabetical sorting within groups.
|
|
8
|
+
|
|
9
|
+
### Why?
|
|
10
|
+
|
|
11
|
+
1. **Readability**: Grouping imports by source type makes it easy to scan dependencies at a glance
|
|
12
|
+
2. **Consistency**: A predictable import order reduces merge conflicts and code review friction
|
|
13
|
+
3. **Separation of concerns**: Side effects, platform modules, third-party packages, internal aliases, and relative imports serve different purposes
|
|
14
|
+
|
|
15
|
+
### Import Group Order
|
|
16
|
+
|
|
17
|
+
1. **Side-effect imports** — no specifiers (e.g., `import "./setup"`)
|
|
18
|
+
2. **Node.js builtins** — `node:` prefix or known builtin names (e.g., `import fs from "node:fs"`)
|
|
19
|
+
3. **External packages** — scoped or plain package names (e.g., `import React from "react"`)
|
|
20
|
+
4. **Internal aliases** — paths starting with `@/`, `~/`, or `#` (e.g., `import { utils } from "@/lib/utils"`)
|
|
21
|
+
5. **Relative imports** — paths starting with `.` (e.g., `import { foo } from "../foo"`)
|
|
22
|
+
|
|
23
|
+
Type-only imports (`import type`) are skipped and do not affect ordering.
|
|
24
|
+
|
|
25
|
+
Non-contiguous imports (separated by other statements) are checked independently.
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
### ❌ Incorrect
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// Bad: Relative before external
|
|
33
|
+
import { foo } from "../foo";
|
|
34
|
+
import React from "react";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
// Bad: External before builtin
|
|
39
|
+
import React from "react";
|
|
40
|
+
import fs from "node:fs";
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// Bad: Side-effect after external
|
|
45
|
+
import React from "react";
|
|
46
|
+
import "./setup";
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### ✅ Correct
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// Good: All 5 groups in correct order
|
|
53
|
+
import "./setup";
|
|
54
|
+
import fs from "node:fs";
|
|
55
|
+
import React from "react";
|
|
56
|
+
import { utils } from "@/lib/utils";
|
|
57
|
+
import { foo } from "../foo";
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// Good: Type imports can appear anywhere
|
|
62
|
+
import type { FC } from "react";
|
|
63
|
+
import { foo } from "../foo";
|
|
64
|
+
import React from "react";
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// Good: Non-contiguous imports are independent
|
|
69
|
+
import React from "react";
|
|
70
|
+
|
|
71
|
+
const x = 1;
|
|
72
|
+
|
|
73
|
+
import { foo } from "../foo";
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## When Not To Use It
|
|
77
|
+
|
|
78
|
+
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,104 @@
|
|
|
1
|
+
# sort-type-alphabetically
|
|
2
|
+
|
|
3
|
+
Enforce alphabetical sorting of properties within required and optional groups in TypeScript interfaces and type aliases.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
9
|
+
### Why?
|
|
10
|
+
|
|
11
|
+
1. **Readability**: Alphabetical ordering makes properties easier to find
|
|
12
|
+
2. **Consistency**: A predictable ordering reduces cognitive load during code review
|
|
13
|
+
3. **Maintainability**: Clear structure makes it easier to add or remove properties
|
|
14
|
+
|
|
15
|
+
### Sorting Order
|
|
16
|
+
|
|
17
|
+
Properties within each group are sorted alphabetically A-Z:
|
|
18
|
+
|
|
19
|
+
1. **Required properties** sorted A-Z among themselves
|
|
20
|
+
2. **Optional properties** sorted A-Z among themselves
|
|
21
|
+
|
|
22
|
+
Use with `sort-type-required-first` to also enforce required properties come before optional.
|
|
23
|
+
|
|
24
|
+
## Examples
|
|
25
|
+
|
|
26
|
+
### ❌ Incorrect
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// Bad: Required not sorted A-Z
|
|
30
|
+
interface Props {
|
|
31
|
+
src: string;
|
|
32
|
+
alt: string;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// Bad: Optional not sorted A-Z
|
|
38
|
+
interface Props {
|
|
39
|
+
b?: number;
|
|
40
|
+
a?: string;
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// Bad: Required group not sorted A-Z
|
|
46
|
+
interface HeroBannerRootProps {
|
|
47
|
+
size: "detail" | "highlight" | "main";
|
|
48
|
+
alt: string;
|
|
49
|
+
src: string;
|
|
50
|
+
className?: string;
|
|
51
|
+
label?: string;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### ✅ Correct
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
// Good: Required A-Z, optional A-Z
|
|
59
|
+
interface HeroBannerRootProps {
|
|
60
|
+
alt: string;
|
|
61
|
+
size: "detail" | "highlight" | "main";
|
|
62
|
+
src: string;
|
|
63
|
+
className?: string;
|
|
64
|
+
label?: string;
|
|
65
|
+
onClick?: () => void;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// Good: All required, sorted A-Z
|
|
71
|
+
interface Props {
|
|
72
|
+
a: string;
|
|
73
|
+
b: number;
|
|
74
|
+
c: boolean;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
// Good: All optional, sorted A-Z
|
|
80
|
+
interface Props {
|
|
81
|
+
a?: string;
|
|
82
|
+
b?: number;
|
|
83
|
+
c?: boolean;
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
// Good: Type alias with A-Z within groups
|
|
89
|
+
type Props = {
|
|
90
|
+
alt: string;
|
|
91
|
+
size: string;
|
|
92
|
+
src: string;
|
|
93
|
+
label?: string;
|
|
94
|
+
};
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## When Not To Use It
|
|
98
|
+
|
|
99
|
+
If you prefer a different sorting strategy for type properties or don't want to enforce alphabetical ordering, you can disable this rule.
|
|
100
|
+
|
|
101
|
+
## Further Reading
|
|
102
|
+
|
|
103
|
+
- [TypeScript Interfaces](https://www.typescriptlang.org/docs/handbook/2/objects.html)
|
|
104
|
+
- [TypeScript Type Aliases](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-aliases)
|
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
# sort-type-required-first
|
|
2
2
|
|
|
3
|
-
Enforce required properties come before optional properties in TypeScript interfaces and type aliases
|
|
3
|
+
Enforce required properties come before optional properties in TypeScript interfaces and type aliases.
|
|
4
4
|
|
|
5
5
|
## Rule Details
|
|
6
6
|
|
|
7
|
-
This rule enforces that TypeScript interface and type alias
|
|
7
|
+
This rule enforces that TypeScript interface and type alias required (non-optional) properties come before optional properties.
|
|
8
8
|
|
|
9
9
|
### Why?
|
|
10
10
|
|
|
11
|
-
1. **
|
|
12
|
-
2. **
|
|
13
|
-
3. **
|
|
14
|
-
4. **Maintainability**: Clear structure makes it easier to add or remove properties
|
|
11
|
+
1. **Readability**: Required properties are the most important contract of a type - they should be visible first
|
|
12
|
+
2. **Organization**: Grouping by optionality clearly communicates which properties are mandatory
|
|
13
|
+
3. **Consistency**: A predictable ordering makes code easier to scan and review
|
|
15
14
|
|
|
16
15
|
### Sorting Order
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
1. **Required properties** first
|
|
18
|
+
2. **Optional properties** after
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
2. **Optional properties** (sorted alphabetically A-Z)
|
|
20
|
+
Use with `sort-type-alphabetically` to also enforce A-Z ordering within each group.
|
|
22
21
|
|
|
23
22
|
## Examples
|
|
24
23
|
|
|
@@ -44,35 +43,19 @@ interface Props {
|
|
|
44
43
|
```
|
|
45
44
|
|
|
46
45
|
```ts
|
|
47
|
-
// Bad: Required
|
|
46
|
+
// Bad: Required after optional
|
|
48
47
|
interface Props {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```ts
|
|
55
|
-
// Bad: Optional not sorted alphabetically
|
|
56
|
-
interface Props {
|
|
57
|
-
b?: number;
|
|
58
|
-
a?: string;
|
|
48
|
+
a: string;
|
|
49
|
+
b: string;
|
|
50
|
+
c?: string;
|
|
51
|
+
d: string;
|
|
59
52
|
}
|
|
60
53
|
```
|
|
61
54
|
|
|
62
|
-
```ts
|
|
63
|
-
// Bad: Type alias with optional before required
|
|
64
|
-
type Props = {
|
|
65
|
-
label?: string;
|
|
66
|
-
alt: string;
|
|
67
|
-
size: string;
|
|
68
|
-
src: string;
|
|
69
|
-
};
|
|
70
|
-
```
|
|
71
|
-
|
|
72
55
|
### ✅ Correct
|
|
73
56
|
|
|
74
57
|
```ts
|
|
75
|
-
// Good: Required first
|
|
58
|
+
// Good: Required first, then optional
|
|
76
59
|
interface HeroBannerRootProps {
|
|
77
60
|
alt: string;
|
|
78
61
|
size: "detail" | "highlight" | "main";
|
|
@@ -82,7 +65,7 @@ interface HeroBannerRootProps {
|
|
|
82
65
|
```
|
|
83
66
|
|
|
84
67
|
```ts
|
|
85
|
-
// Good: All required
|
|
68
|
+
// Good: All required
|
|
86
69
|
interface Props {
|
|
87
70
|
a: string;
|
|
88
71
|
b: number;
|
|
@@ -91,7 +74,7 @@ interface Props {
|
|
|
91
74
|
```
|
|
92
75
|
|
|
93
76
|
```ts
|
|
94
|
-
// Good: All optional
|
|
77
|
+
// Good: All optional
|
|
95
78
|
interface Props {
|
|
96
79
|
a?: string;
|
|
97
80
|
b?: number;
|
|
@@ -100,7 +83,7 @@ interface Props {
|
|
|
100
83
|
```
|
|
101
84
|
|
|
102
85
|
```ts
|
|
103
|
-
// Good: Type alias with required first
|
|
86
|
+
// Good: Type alias with required first
|
|
104
87
|
type Props = {
|
|
105
88
|
alt: string;
|
|
106
89
|
size: string;
|
|
@@ -109,20 +92,9 @@ type Props = {
|
|
|
109
92
|
};
|
|
110
93
|
```
|
|
111
94
|
|
|
112
|
-
```ts
|
|
113
|
-
// Good: Multiple optional at end, sorted alphabetically
|
|
114
|
-
interface Props {
|
|
115
|
-
alt: string;
|
|
116
|
-
size: "detail" | "highlight" | "main";
|
|
117
|
-
src: string;
|
|
118
|
-
label?: string;
|
|
119
|
-
visible?: boolean;
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
95
|
## When Not To Use It
|
|
124
96
|
|
|
125
|
-
If you prefer a different
|
|
97
|
+
If you prefer a different grouping strategy for type properties or don't want to enforce any particular order, you can disable this rule.
|
|
126
98
|
|
|
127
99
|
## Further Reading
|
|
128
100
|
|