eslint-plugin-nextfriday 1.18.0 → 1.20.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 +16 -0
- package/README.md +23 -16
- package/docs/rules/ENFORCE_CONSTANT_CASE.md +10 -3
- package/docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md +24 -2
- package/docs/rules/JSX_NO_TERNARY_NULL.md +42 -0
- package/docs/rules/NO_LAZY_IDENTIFIERS.md +3 -1
- package/docs/rules/NO_MISLEADING_CONSTANT_CASE.md +60 -0
- package/docs/rules/PREFER_INLINE_TYPE_EXPORT.md +64 -0
- package/lib/index.cjs +581 -343
- 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 +581 -343
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# eslint-plugin-nextfriday
|
|
2
2
|
|
|
3
|
+
## 1.20.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#85](https://github.com/next-friday/eslint-plugin-nextfriday/pull/85) [`280a864`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/280a864f31d32433856d6914f742861d3bb43ec9) Thanks [@joetakara](https://github.com/joetakara)! - feat(rules): add no-misleading-constant-case rule and improve enforce-constant-case
|
|
8
|
+
- Add `no-misleading-constant-case` rule that disallows SCREAMING_SNAKE_CASE for mutable bindings (let/var) and non-static values (function calls, objects, arrays, dynamic templates, computed expressions)
|
|
9
|
+
- Add `prefer-inline-type-export` rule that requires type/interface declarations to be exported inline
|
|
10
|
+
- Update `enforce-constant-case` to exempt booleans with standard prefixes (is, has, should, etc.) to resolve conflict with `boolean-naming-prefix`
|
|
11
|
+
- Update existing rules: enforce-constant-case, jsx-newline-between-elements, no-lazy-identifiers
|
|
12
|
+
|
|
13
|
+
## 1.19.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- [#83](https://github.com/next-friday/eslint-plugin-nextfriday/pull/83) [`b7143d2`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/b7143d2f779ca1ca34f6562d09c1a6168b74c338) Thanks [@joetakara](https://github.com/joetakara)! - Add jsx-no-ternary-null rule to enforce logical AND over ternary with null/undefined in JSX
|
|
18
|
+
|
|
3
19
|
## 1.18.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -117,6 +117,7 @@ export default [
|
|
|
117
117
|
"nextfriday/no-nested-interface-declaration": "error",
|
|
118
118
|
"nextfriday/prefer-named-param-types": "error",
|
|
119
119
|
"nextfriday/prefer-inline-literal-union": "error",
|
|
120
|
+
"nextfriday/prefer-inline-type-export": "error",
|
|
120
121
|
"nextfriday/prefer-interface-over-inline-types": "error",
|
|
121
122
|
"nextfriday/sort-type-alphabetically": "error",
|
|
122
123
|
"nextfriday/sort-type-required-first": "error",
|
|
@@ -126,6 +127,7 @@ export default [
|
|
|
126
127
|
"nextfriday/jsx-no-inline-object-prop": "error",
|
|
127
128
|
"nextfriday/jsx-no-newline-single-line-elements": "error",
|
|
128
129
|
"nextfriday/jsx-no-non-component-function": "error",
|
|
130
|
+
"nextfriday/jsx-no-ternary-null": "error",
|
|
129
131
|
"nextfriday/jsx-no-variable-in-callback": "error",
|
|
130
132
|
"nextfriday/jsx-require-suspense": "error",
|
|
131
133
|
"nextfriday/jsx-simple-props": "error",
|
|
@@ -148,12 +150,13 @@ export default [
|
|
|
148
150
|
|
|
149
151
|
### Variable Naming Rules
|
|
150
152
|
|
|
151
|
-
| Rule
|
|
152
|
-
|
|
|
153
|
-
| [no-single-char-variables](docs/rules/NO_SINGLE_CHAR_VARIABLES.md)
|
|
154
|
-
| [no-lazy-identifiers](docs/rules/NO_LAZY_IDENTIFIERS.md)
|
|
155
|
-
| [boolean-naming-prefix](docs/rules/BOOLEAN_NAMING_PREFIX.md)
|
|
156
|
-
| [enforce-constant-case](docs/rules/ENFORCE_CONSTANT_CASE.md)
|
|
153
|
+
| Rule | Description | Fixable |
|
|
154
|
+
| ------------------------------------------------------------------------ | --------------------------------------------------------------------- | ------- |
|
|
155
|
+
| [no-single-char-variables](docs/rules/NO_SINGLE_CHAR_VARIABLES.md) | Disallow single character variable names (e.g., `d`, `u`, `l`) | ❌ |
|
|
156
|
+
| [no-lazy-identifiers](docs/rules/NO_LAZY_IDENTIFIERS.md) | Disallow lazy identifiers like `xxx`, `asdf`, `qwerty` | ❌ |
|
|
157
|
+
| [boolean-naming-prefix](docs/rules/BOOLEAN_NAMING_PREFIX.md) | Enforce boolean variables to have prefix (is, has, should, can, etc.) | ❌ |
|
|
158
|
+
| [enforce-constant-case](docs/rules/ENFORCE_CONSTANT_CASE.md) | Enforce SCREAMING_SNAKE_CASE for static constant primitive values | ❌ |
|
|
159
|
+
| [no-misleading-constant-case](docs/rules/NO_MISLEADING_CONSTANT_CASE.md) | Disallow SCREAMING_SNAKE_CASE for non-constant or non-static values | ❌ |
|
|
157
160
|
|
|
158
161
|
### File Naming Rules
|
|
159
162
|
|
|
@@ -205,6 +208,7 @@ export default [
|
|
|
205
208
|
| [no-nested-interface-declaration](docs/rules/NO_NESTED_INTERFACE_DECLARATION.md) | Disallow inline object types in interface/type properties | ❌ |
|
|
206
209
|
| [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
|
|
207
210
|
| [prefer-inline-literal-union](docs/rules/PREFER_INLINE_LITERAL_UNION.md) | Enforce inlining literal union types for better IDE hover info | ✅ |
|
|
211
|
+
| [prefer-inline-type-export](docs/rules/PREFER_INLINE_TYPE_EXPORT.md) | Require type/interface exports inline at the declaration | ✅ |
|
|
208
212
|
| [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
|
|
209
213
|
| [sort-type-alphabetically](docs/rules/SORT_TYPE_ALPHABETICALLY.md) | Enforce A-Z sorting of properties within type groups | ✅ |
|
|
210
214
|
| [sort-type-required-first](docs/rules/SORT_TYPE_REQUIRED_FIRST.md) | Enforce required properties before optional in types/interfaces | ✅ |
|
|
@@ -213,10 +217,11 @@ export default [
|
|
|
213
217
|
|
|
214
218
|
| Rule | Description | Fixable |
|
|
215
219
|
| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------- |
|
|
216
|
-
| [jsx-newline-between-elements](docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md) | Require empty lines between sibling multi-line JSX
|
|
220
|
+
| [jsx-newline-between-elements](docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md) | Require empty lines between sibling multi-line JSX children | ✅ |
|
|
217
221
|
| [jsx-no-inline-object-prop](docs/rules/JSX_NO_INLINE_OBJECT_PROP.md) | Disallow inline object literals in JSX props | ❌ |
|
|
218
222
|
| [jsx-no-newline-single-line-elements](docs/rules/JSX_NO_NEWLINE_SINGLE_LINE_ELEMENTS.md) | Disallow empty lines between single-line sibling JSX elements | ✅ |
|
|
219
223
|
| [jsx-no-non-component-function](docs/rules/JSX_NO_NON_COMPONENT_FUNCTION.md) | Disallow non-component functions at top level in .tsx/.jsx files | ❌ |
|
|
224
|
+
| [jsx-no-ternary-null](docs/rules/JSX_NO_TERNARY_NULL.md) | Enforce logical AND over ternary with null/undefined in JSX | ✅ |
|
|
220
225
|
| [jsx-no-variable-in-callback](docs/rules/JSX_NO_VARIABLE_IN_CALLBACK.md) | Disallow variable declarations inside callback functions in JSX | ❌ |
|
|
221
226
|
| [jsx-require-suspense](docs/rules/JSX_REQUIRE_SUSPENSE.md) | Require lazy-loaded components to be wrapped in Suspense | ❌ |
|
|
222
227
|
| [jsx-simple-props](docs/rules/JSX_SIMPLE_PROPS.md) | Enforce simple prop values (strings, variables, callbacks, ReactNode) | ❌ |
|
|
@@ -238,14 +243,14 @@ export default [
|
|
|
238
243
|
|
|
239
244
|
| Preset | Severity | Base Rules | JSX Rules | Next.js Rules | Total Rules |
|
|
240
245
|
| -------------------- | -------- | ---------- | --------- | ------------- | ----------- |
|
|
241
|
-
| `base` | warn |
|
|
242
|
-
| `base/recommended` | error |
|
|
243
|
-
| `react` | warn |
|
|
244
|
-
| `react/recommended` | error |
|
|
245
|
-
| `nextjs` | warn |
|
|
246
|
-
| `nextjs/recommended` | error |
|
|
246
|
+
| `base` | warn | 37 | 0 | 0 | 37 |
|
|
247
|
+
| `base/recommended` | error | 37 | 0 | 0 | 37 |
|
|
248
|
+
| `react` | warn | 37 | 15 | 0 | 52 |
|
|
249
|
+
| `react/recommended` | error | 37 | 15 | 0 | 52 |
|
|
250
|
+
| `nextjs` | warn | 37 | 15 | 1 | 53 |
|
|
251
|
+
| `nextjs/recommended` | error | 37 | 15 | 1 | 53 |
|
|
247
252
|
|
|
248
|
-
### Base Configuration Rules (
|
|
253
|
+
### Base Configuration Rules (37 rules)
|
|
249
254
|
|
|
250
255
|
Included in `base`, `base/recommended`, and all other presets:
|
|
251
256
|
|
|
@@ -278,6 +283,7 @@ Included in `base`, `base/recommended`, and all other presets:
|
|
|
278
283
|
- `nextfriday/prefer-guard-clause`
|
|
279
284
|
- `nextfriday/prefer-import-type`
|
|
280
285
|
- `nextfriday/prefer-inline-literal-union`
|
|
286
|
+
- `nextfriday/prefer-inline-type-export`
|
|
281
287
|
- `nextfriday/prefer-named-param-types`
|
|
282
288
|
- `nextfriday/prefer-react-import-types`
|
|
283
289
|
- `nextfriday/require-explicit-return-type`
|
|
@@ -286,7 +292,7 @@ Included in `base`, `base/recommended`, and all other presets:
|
|
|
286
292
|
- `nextfriday/sort-type-alphabetically`
|
|
287
293
|
- `nextfriday/sort-type-required-first`
|
|
288
294
|
|
|
289
|
-
### JSX Rules (
|
|
295
|
+
### JSX Rules (15 rules)
|
|
290
296
|
|
|
291
297
|
Additionally included in `react`, `react/recommended`, `nextjs`, `nextjs/recommended`:
|
|
292
298
|
|
|
@@ -296,6 +302,7 @@ Additionally included in `react`, `react/recommended`, `nextjs`, `nextjs/recomme
|
|
|
296
302
|
- `nextfriday/jsx-no-inline-object-prop`
|
|
297
303
|
- `nextfriday/jsx-no-newline-single-line-elements`
|
|
298
304
|
- `nextfriday/jsx-no-non-component-function`
|
|
305
|
+
- `nextfriday/jsx-no-ternary-null`
|
|
299
306
|
- `nextfriday/jsx-no-variable-in-callback`
|
|
300
307
|
- `nextfriday/jsx-pascal-case`
|
|
301
308
|
- `nextfriday/jsx-require-suspense`
|
|
@@ -329,7 +336,7 @@ Additionally included in `nextjs`, `nextjs/recommended` only:
|
|
|
329
336
|
|
|
330
337
|
## Agent Skill
|
|
331
338
|
|
|
332
|
-
This plugin ships with an [Agent Skill](https://github.com/anthropics/skills) that teaches AI coding assistants (Claude Code, Cursor, etc.) all
|
|
339
|
+
This plugin ships with an [Agent Skill](https://github.com/anthropics/skills) that teaches AI coding assistants (Claude Code, Cursor, etc.) all 53 rules so they generate compliant code from the start.
|
|
333
340
|
|
|
334
341
|
```bash
|
|
335
342
|
npx skills add next-friday/eslint-plugin-nextfriday --skill eslint-plugin-nextfriday
|
|
@@ -4,7 +4,7 @@ Enforce SCREAMING_SNAKE_CASE for constant primitive values.
|
|
|
4
4
|
|
|
5
5
|
## Rule Details
|
|
6
6
|
|
|
7
|
-
This rule ensures that `const` declarations with primitive values (strings, numbers, booleans, template literals) use SCREAMING_SNAKE_CASE naming convention. Objects, arrays, and functions are not checked. Only `const` declarations are checked; `let` and `var` are ignored.
|
|
7
|
+
This rule ensures that `const` declarations with static primitive values (strings, numbers, booleans, static template literals) use SCREAMING_SNAKE_CASE naming convention. Template literals with expressions (e.g., `` `${variable}` ``) are considered dynamic and are not checked. Objects, arrays, and functions are not checked. Only `const` declarations are checked; `let` and `var` are ignored.
|
|
8
8
|
|
|
9
9
|
## Examples
|
|
10
10
|
|
|
@@ -13,7 +13,6 @@ This rule ensures that `const` declarations with primitive values (strings, numb
|
|
|
13
13
|
```ts
|
|
14
14
|
const defaultCover = "/images/default.jpg";
|
|
15
15
|
const pageLimit = 10;
|
|
16
|
-
const isEnabled = true;
|
|
17
16
|
const apiBaseUrl = "https://api.example.com";
|
|
18
17
|
const template = `hello world`;
|
|
19
18
|
```
|
|
@@ -23,10 +22,18 @@ const template = `hello world`;
|
|
|
23
22
|
```ts
|
|
24
23
|
const DEFAULT_COVER = "/images/default.jpg";
|
|
25
24
|
const PAGE_LIMIT = 10;
|
|
26
|
-
const IS_ENABLED = true;
|
|
27
25
|
const API_BASE_URL = "https://api.example.com";
|
|
28
26
|
const TEMPLATE = `hello world`;
|
|
29
27
|
|
|
28
|
+
// Booleans with standard prefixes (is, has, should, can, etc.) are exempt
|
|
29
|
+
const isEnabled = true;
|
|
30
|
+
const hasAccess = false;
|
|
31
|
+
const shouldRender = true;
|
|
32
|
+
|
|
33
|
+
// Template literals with expressions are dynamic, camelCase is fine
|
|
34
|
+
const pendingHref = `/branch/${branch.branchNumber}`;
|
|
35
|
+
const greeting = `Hello, ${user.name}!`;
|
|
36
|
+
|
|
30
37
|
// Objects, arrays, and functions can use camelCase
|
|
31
38
|
const config = { key: "value" };
|
|
32
39
|
const items = [1, 2, 3];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# jsx-newline-between-elements
|
|
2
2
|
|
|
3
|
-
Require empty lines between sibling JSX elements when at least one spans multiple lines.
|
|
3
|
+
Require empty lines between sibling JSX elements and expression containers when at least one spans multiple lines.
|
|
4
4
|
|
|
5
5
|
## Rule Details
|
|
6
6
|
|
|
7
|
-
This rule enforces empty lines between sibling JSX elements when either
|
|
7
|
+
This rule enforces empty lines between sibling JSX elements, fragments, and expression containers (e.g., `{condition && (...)}`) when either sibling spans multiple lines. This improves visual separation and readability of complex component structures. Single-line siblings do not require empty lines between them.
|
|
8
8
|
|
|
9
9
|
## Examples
|
|
10
10
|
|
|
@@ -70,6 +70,28 @@ function UserProfile() {
|
|
|
70
70
|
}
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
Expression containers also need empty lines:
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
function StudentInfo({ studentId, name }) {
|
|
77
|
+
return (
|
|
78
|
+
<div>
|
|
79
|
+
{studentId && (
|
|
80
|
+
<div className="flex items-center gap-x-1">
|
|
81
|
+
<Text size="lg">{studentId}</Text>
|
|
82
|
+
</div>
|
|
83
|
+
)}
|
|
84
|
+
|
|
85
|
+
{name && (
|
|
86
|
+
<div className="flex items-center gap-x-1">
|
|
87
|
+
<Text size="lg">{name}</Text>
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
73
95
|
Single-line elements do not require empty lines:
|
|
74
96
|
|
|
75
97
|
```jsx
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# jsx-no-ternary-null
|
|
2
|
+
|
|
3
|
+
Enforce logical AND over ternary with null/undefined in JSX expressions.
|
|
4
|
+
|
|
5
|
+
> This rule is auto-fixable using `--fix`.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
This rule flags ternary expressions inside JSX where one branch is `null` or `undefined`. These patterns are better expressed using the logical AND (`&&`) operator, which is more concise and idiomatic in React.
|
|
10
|
+
|
|
11
|
+
### Why?
|
|
12
|
+
|
|
13
|
+
- **Readability**: `{condition && <Component />}` is cleaner than `{condition ? <Component /> : null}`
|
|
14
|
+
- **Consistency**: Encourages a single pattern for conditional rendering
|
|
15
|
+
- **Conciseness**: Removes unnecessary null/undefined branches
|
|
16
|
+
|
|
17
|
+
## Examples
|
|
18
|
+
|
|
19
|
+
### Incorrect
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
<div>{condition ? <span>Hello</span> : null}</div>
|
|
23
|
+
<div>{condition ? <Component /> : undefined}</div>
|
|
24
|
+
<div>{condition ? null : <span>Fallback</span>}</div>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Correct
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<div>{condition && <span>Hello</span>}</div>
|
|
31
|
+
<div>{condition && <Component />}</div>
|
|
32
|
+
<div>{!condition && <span>Fallback</span>}</div>
|
|
33
|
+
<div>{condition ? <A /> : <B />}</div>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## When Not To Use It
|
|
37
|
+
|
|
38
|
+
If your team prefers explicit ternary expressions for conditional rendering, even when one branch is null or undefined.
|
|
39
|
+
|
|
40
|
+
## Related Rules
|
|
41
|
+
|
|
42
|
+
- [no-nested-ternary](JSX_NO_TERNARY_NULL.md)
|
|
@@ -60,10 +60,12 @@ The rule detects two types of lazy patterns:
|
|
|
60
60
|
|
|
61
61
|
### Repeated Characters (3+)
|
|
62
62
|
|
|
63
|
-
Variables with 3 or more consecutive identical characters:
|
|
63
|
+
Variables with 3 or more consecutive identical characters (case-sensitive):
|
|
64
64
|
|
|
65
65
|
- `xxx`, `aaa`, `zzz`, `qqqq`, `aaaa`
|
|
66
66
|
|
|
67
|
+
Compound names where repeated characters span word boundaries are not flagged (e.g., `ProfileProgressSkeleton` is allowed because `ss` and `S` are different cases).
|
|
68
|
+
|
|
67
69
|
### Keyboard Sequences (4+)
|
|
68
70
|
|
|
69
71
|
Variables containing 4 or more consecutive keyboard row characters:
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# no-misleading-constant-case
|
|
2
|
+
|
|
3
|
+
Disallow SCREAMING_SNAKE_CASE for non-constant or non-static values.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
SCREAMING_SNAKE_CASE conventionally signals a compile-time constant with a static, immutable value. Using it for mutable bindings (`let`/`var`) or dynamic values (function calls, objects, arrays, computed expressions) is misleading because the name implies immutability that the value does not have.
|
|
8
|
+
|
|
9
|
+
### Why?
|
|
10
|
+
|
|
11
|
+
When reading `const API_URL = getUrl()`, the SCREAMING_SNAKE_CASE name suggests a hardcoded value, but it is actually computed at runtime. This mismatch makes code harder to reason about. Reserving SCREAMING_SNAKE_CASE for true static primitives keeps the convention meaningful.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Incorrect
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// Mutable bindings should not use SCREAMING_SNAKE_CASE
|
|
19
|
+
let API_URL = "https://api.example.com";
|
|
20
|
+
var MAX_COUNT = 10;
|
|
21
|
+
|
|
22
|
+
// Dynamic or computed values should use camelCase
|
|
23
|
+
const API_URL = getUrl();
|
|
24
|
+
const USER_ID = await fetchId();
|
|
25
|
+
const PATHNAME = `/news/${slug}`;
|
|
26
|
+
const CONFIG = { key: "value" };
|
|
27
|
+
const ITEMS = [1, 2, 3];
|
|
28
|
+
const RESULT = a + b;
|
|
29
|
+
const ACTIVE_USERS = users.filter((u) => u.active);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Correct
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
// Static primitive constants use SCREAMING_SNAKE_CASE
|
|
36
|
+
const API_URL = "https://api.example.com";
|
|
37
|
+
const MAX_COUNT = 10;
|
|
38
|
+
const IS_PRODUCTION = true;
|
|
39
|
+
const TEMPLATE = `hello world`;
|
|
40
|
+
|
|
41
|
+
// Dynamic or computed values use camelCase
|
|
42
|
+
const apiUrl = getUrl();
|
|
43
|
+
const userId = await fetchId();
|
|
44
|
+
const pathname = `/news/${slug}`;
|
|
45
|
+
const config = { key: "value" };
|
|
46
|
+
const items = [1, 2, 3];
|
|
47
|
+
const result = a + b;
|
|
48
|
+
|
|
49
|
+
// Mutable bindings use camelCase
|
|
50
|
+
let count = 10;
|
|
51
|
+
var name = "foo";
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## When Not To Use It
|
|
55
|
+
|
|
56
|
+
If your project does not follow the convention that SCREAMING_SNAKE_CASE is reserved for static primitive constants.
|
|
57
|
+
|
|
58
|
+
## Related Rules
|
|
59
|
+
|
|
60
|
+
- [enforce-constant-case](ENFORCE_CONSTANT_CASE.md) - The complementary rule that enforces SCREAMING_SNAKE_CASE for static primitive constants
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# prefer-inline-type-export
|
|
2
|
+
|
|
3
|
+
Require type and interface declarations to be exported inline rather than via a separate export statement.
|
|
4
|
+
|
|
5
|
+
> This rule is auto-fixable using `--fix`.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
This rule enforces that `interface` and `type` declarations are exported directly at the declaration site using the `export` keyword, rather than being exported separately via `export type { ... }` or `export { ... }` at the bottom of the file.
|
|
10
|
+
|
|
11
|
+
### Why?
|
|
12
|
+
|
|
13
|
+
Inline exports make it immediately clear at the declaration site that a type is part of the module's public API. Separate export statements create a disconnect between the declaration and its visibility, making it harder to understand the module's surface area at a glance.
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### Incorrect
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
interface ButtonProps {
|
|
21
|
+
label: string;
|
|
22
|
+
disabled: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type Theme = "light" | "dark";
|
|
26
|
+
|
|
27
|
+
export type { ButtonProps, Theme };
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
interface Config {
|
|
32
|
+
port: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { Config };
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Correct
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
export interface ButtonProps {
|
|
42
|
+
label: string;
|
|
43
|
+
disabled: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type Theme = "light" | "dark";
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
export interface Config {
|
|
51
|
+
port: number;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Exceptions
|
|
56
|
+
|
|
57
|
+
This rule only applies to `interface` and `type` declarations defined in the same file. It does not flag:
|
|
58
|
+
|
|
59
|
+
- Re-exports from other modules (`export type { Foo } from './types'`)
|
|
60
|
+
- Separate exports of non-type declarations (variables, functions, classes)
|
|
61
|
+
|
|
62
|
+
## When Not To Use It
|
|
63
|
+
|
|
64
|
+
If your project prefers grouping all exports at the bottom of the file for consistency.
|