eslint-plugin-nextfriday 1.15.2 → 1.16.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 +6 -0
- package/README.md +16 -7
- package/docs/rules/ENFORCE_TYPE_DECLARATION_ORDER.md +87 -0
- package/docs/rules/NO_NESTED_INTERFACE_DECLARATION.md +102 -0
- package/docs/rules/PREFER_INLINE_LITERAL_UNION.md +87 -0
- package/lib/index.cjs +551 -337
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +42 -0
- package/lib/index.d.ts +42 -0
- package/lib/index.js +551 -337
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# eslint-plugin-nextfriday
|
|
2
2
|
|
|
3
|
+
## 1.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#75](https://github.com/next-friday/eslint-plugin-nextfriday/pull/75) [`f506561`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/f506561c1587af4a129801dee87c7ed08154b090) Thanks [@joetakara](https://github.com/joetakara)! - feat(rules): add prefer-inline-literal-union, no-nested-interface-declaration, and enforce-type-declaration-order rules
|
|
8
|
+
|
|
3
9
|
## 1.15.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -113,7 +113,10 @@ export default [
|
|
|
113
113
|
"nextfriday/sort-imports": "error",
|
|
114
114
|
|
|
115
115
|
// Type Patterns
|
|
116
|
+
"nextfriday/enforce-type-declaration-order": "error",
|
|
117
|
+
"nextfriday/no-nested-interface-declaration": "error",
|
|
116
118
|
"nextfriday/prefer-named-param-types": "error",
|
|
119
|
+
"nextfriday/prefer-inline-literal-union": "error",
|
|
117
120
|
"nextfriday/prefer-interface-over-inline-types": "error",
|
|
118
121
|
"nextfriday/sort-type-alphabetically": "error",
|
|
119
122
|
"nextfriday/sort-type-required-first": "error",
|
|
@@ -225,7 +228,10 @@ module.exports = {
|
|
|
225
228
|
|
|
226
229
|
| Rule | Description | Fixable |
|
|
227
230
|
| -------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- |
|
|
231
|
+
| [enforce-type-declaration-order](docs/rules/ENFORCE_TYPE_DECLARATION_ORDER.md) | Enforce referenced types are declared after their consumer | ❌ |
|
|
232
|
+
| [no-nested-interface-declaration](docs/rules/NO_NESTED_INTERFACE_DECLARATION.md) | Disallow inline object types in interface/type properties | ❌ |
|
|
228
233
|
| [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
|
|
234
|
+
| [prefer-inline-literal-union](docs/rules/PREFER_INLINE_LITERAL_UNION.md) | Enforce inlining literal union types for better IDE hover info | ✅ |
|
|
229
235
|
| [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
|
|
230
236
|
| [sort-type-alphabetically](docs/rules/SORT_TYPE_ALPHABETICALLY.md) | Enforce A-Z sorting of properties within type groups | ✅ |
|
|
231
237
|
| [sort-type-required-first](docs/rules/SORT_TYPE_REQUIRED_FIRST.md) | Enforce required properties before optional in types/interfaces | ✅ |
|
|
@@ -259,14 +265,14 @@ module.exports = {
|
|
|
259
265
|
|
|
260
266
|
| Preset | Severity | Base Rules | JSX Rules | Next.js Rules | Total Rules |
|
|
261
267
|
| -------------------- | -------- | ---------- | --------- | ------------- | ----------- |
|
|
262
|
-
| `base` | warn |
|
|
263
|
-
| `base/recommended` | error |
|
|
264
|
-
| `react` | warn |
|
|
265
|
-
| `react/recommended` | error |
|
|
266
|
-
| `nextjs` | warn |
|
|
267
|
-
| `nextjs/recommended` | error |
|
|
268
|
+
| `base` | warn | 36 | 0 | 0 | 36 |
|
|
269
|
+
| `base/recommended` | error | 36 | 0 | 0 | 36 |
|
|
270
|
+
| `react` | warn | 36 | 14 | 0 | 50 |
|
|
271
|
+
| `react/recommended` | error | 36 | 14 | 0 | 50 |
|
|
272
|
+
| `nextjs` | warn | 36 | 14 | 1 | 51 |
|
|
273
|
+
| `nextjs/recommended` | error | 36 | 14 | 1 | 51 |
|
|
268
274
|
|
|
269
|
-
### Base Configuration Rules (
|
|
275
|
+
### Base Configuration Rules (36 rules)
|
|
270
276
|
|
|
271
277
|
Included in `base`, `base/recommended`, and all other presets:
|
|
272
278
|
|
|
@@ -276,6 +282,7 @@ Included in `base`, `base/recommended`, and all other presets:
|
|
|
276
282
|
- `nextfriday/enforce-hook-naming`
|
|
277
283
|
- `nextfriday/enforce-service-naming`
|
|
278
284
|
- `nextfriday/enforce-sorted-destructuring`
|
|
285
|
+
- `nextfriday/enforce-type-declaration-order`
|
|
279
286
|
- `nextfriday/file-kebab-case`
|
|
280
287
|
- `nextfriday/md-filename-case-restriction`
|
|
281
288
|
- `nextfriday/newline-after-multiline-block`
|
|
@@ -288,6 +295,7 @@ Included in `base`, `base/recommended`, and all other presets:
|
|
|
288
295
|
- `nextfriday/no-inline-nested-object`
|
|
289
296
|
- `nextfriday/no-lazy-identifiers`
|
|
290
297
|
- `nextfriday/no-logic-in-params`
|
|
298
|
+
- `nextfriday/no-nested-interface-declaration`
|
|
291
299
|
- `nextfriday/no-nested-ternary`
|
|
292
300
|
- `nextfriday/no-relative-imports`
|
|
293
301
|
- `nextfriday/no-single-char-variables`
|
|
@@ -296,6 +304,7 @@ Included in `base`, `base/recommended`, and all other presets:
|
|
|
296
304
|
- `nextfriday/prefer-function-declaration`
|
|
297
305
|
- `nextfriday/prefer-guard-clause`
|
|
298
306
|
- `nextfriday/prefer-import-type`
|
|
307
|
+
- `nextfriday/prefer-inline-literal-union`
|
|
299
308
|
- `nextfriday/prefer-named-param-types`
|
|
300
309
|
- `nextfriday/prefer-react-import-types`
|
|
301
310
|
- `nextfriday/require-explicit-return-type`
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# enforce-type-declaration-order
|
|
2
|
+
|
|
3
|
+
Enforce that referenced types and interfaces are declared after the type that uses them.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule enforces a top-down reading order for type declarations. When an interface or type references another locally-declared type, the referenced (dependency) type must appear _after_ the consumer. This ensures the "main" type is read first, with its supporting types following below.
|
|
8
|
+
|
|
9
|
+
### Why?
|
|
10
|
+
|
|
11
|
+
1. **Top-down readability**: The primary type appears first, making it easy to understand the high-level structure before drilling into details
|
|
12
|
+
2. **Consistency**: A uniform ordering convention eliminates debates about where to place types
|
|
13
|
+
3. **Natural flow**: Mirrors how you'd explain a data structure - start with the big picture, then define the parts
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### Incorrect
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// Dependency declared before consumer
|
|
21
|
+
interface Baz {
|
|
22
|
+
baz: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface Foo {
|
|
26
|
+
bar: Baz;
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
type Config = {
|
|
32
|
+
theme: string;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type Props = {
|
|
36
|
+
config: Config;
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Correct
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// Consumer first, dependency after
|
|
44
|
+
interface Foo {
|
|
45
|
+
bar: Baz;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface Baz {
|
|
49
|
+
baz: string;
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
type Props = {
|
|
55
|
+
config: Config;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type Config = {
|
|
59
|
+
theme: string;
|
|
60
|
+
};
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// Chain of dependencies in top-down order
|
|
65
|
+
interface Parent {
|
|
66
|
+
child: Child;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface Child {
|
|
70
|
+
grandchild: Grandchild;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface Grandchild {
|
|
74
|
+
value: string;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
// External/imported types are ignored (not locally declared)
|
|
80
|
+
interface Props {
|
|
81
|
+
items: ExternalType[];
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## When Not To Use It
|
|
86
|
+
|
|
87
|
+
If you prefer declaring dependency types before the types that reference them (bottom-up order), or if you don't want to enforce any particular declaration order, you can disable this rule.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# no-nested-interface-declaration
|
|
2
|
+
|
|
3
|
+
Disallow inline object type literals in interface or type properties.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule flags inline object type literals nested inside interface or type properties. Nested object types should be extracted into separate named interfaces or type declarations for clarity and reusability.
|
|
8
|
+
|
|
9
|
+
### Why?
|
|
10
|
+
|
|
11
|
+
1. **Readability**: Deeply nested inline types make interfaces harder to scan
|
|
12
|
+
2. **Reusability**: Extracted types can be imported and reused across files
|
|
13
|
+
3. **Maintainability**: Flat, named types are easier to modify and extend
|
|
14
|
+
4. **IDE experience**: Named types provide better hover information and navigation
|
|
15
|
+
|
|
16
|
+
## Examples
|
|
17
|
+
|
|
18
|
+
### Incorrect
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
interface Foo {
|
|
22
|
+
bar: {
|
|
23
|
+
baz: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
interface Props {
|
|
30
|
+
user: {
|
|
31
|
+
name: string;
|
|
32
|
+
age: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
interface Props {
|
|
39
|
+
items: {
|
|
40
|
+
id: number;
|
|
41
|
+
label: string;
|
|
42
|
+
}[];
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
interface Props {
|
|
48
|
+
data: Readonly<{
|
|
49
|
+
id: number;
|
|
50
|
+
name: string;
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Correct
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
interface Bar {
|
|
59
|
+
baz: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface Foo {
|
|
63
|
+
bar: Bar;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
interface User {
|
|
69
|
+
name: string;
|
|
70
|
+
age: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface Props {
|
|
74
|
+
user: User;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
interface Item {
|
|
80
|
+
id: number;
|
|
81
|
+
label: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface Props {
|
|
85
|
+
items: Item[];
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// Primitive and simple types are fine inline
|
|
91
|
+
interface Props {
|
|
92
|
+
name: string;
|
|
93
|
+
age: number;
|
|
94
|
+
isActive: boolean;
|
|
95
|
+
ids: string[];
|
|
96
|
+
callback: () => void;
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## When Not To Use It
|
|
101
|
+
|
|
102
|
+
If you prefer keeping small object types inline within interfaces for co-location, you can disable this rule.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# prefer-inline-literal-union
|
|
2
|
+
|
|
3
|
+
Enforce inlining literal union types in interface properties instead of using type aliases for better IDE hover information.
|
|
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 detects type aliases that are unions of only literal values (strings, numbers, booleans, null, undefined) and flags their usage in interface or type properties. The fix inlines the union directly into the property type annotation.
|
|
10
|
+
|
|
11
|
+
### Why?
|
|
12
|
+
|
|
13
|
+
When you hover over a prop in your IDE, a type alias shows the alias name (e.g., `ArticleFaqCategoryId`) instead of the actual values (`"articles" | "dharma" | "faq"`). Inlining literal unions gives immediate visibility into the allowed values without needing to jump to the type definition.
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### Incorrect
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
type ArticleFaqCategoryId = "articles" | "dharma" | "faq";
|
|
21
|
+
|
|
22
|
+
interface ArticleFaqCategoryFilterProps {
|
|
23
|
+
activeCategoryId?: ArticleFaqCategoryId;
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
type Status = "loading" | "success" | "error";
|
|
29
|
+
|
|
30
|
+
interface Props {
|
|
31
|
+
status: Status;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
type Size = 1 | 2 | 3 | 4;
|
|
37
|
+
|
|
38
|
+
interface Props {
|
|
39
|
+
size: Size;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Correct
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
interface ArticleFaqCategoryFilterProps {
|
|
47
|
+
activeCategoryId?: "articles" | "dharma" | "faq";
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
interface Props {
|
|
53
|
+
status: "loading" | "success" | "error";
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
interface Props {
|
|
59
|
+
size: 1 | 2 | 3 | 4;
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// Non-literal unions are allowed as type aliases
|
|
65
|
+
type User = { name: string; age: number };
|
|
66
|
+
|
|
67
|
+
interface Props {
|
|
68
|
+
user: User;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
// Using the alias outside of interface properties is fine
|
|
74
|
+
type Status = "loading" | "success" | "error";
|
|
75
|
+
function getStatus(s: Status): string {
|
|
76
|
+
return s;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## When Not To Use It
|
|
81
|
+
|
|
82
|
+
If you prefer using type aliases for literal unions (e.g., for reuse across multiple interfaces or for self-documenting code), you can disable this rule.
|
|
83
|
+
|
|
84
|
+
## Further Reading
|
|
85
|
+
|
|
86
|
+
- [TypeScript Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types)
|
|
87
|
+
- [TypeScript Literal Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types)
|