eslint-plugin-nextfriday 1.19.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 +10 -0
- package/README.md +19 -15
- package/docs/rules/ENFORCE_CONSTANT_CASE.md +10 -3
- package/docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md +24 -2
- 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 +391 -219
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +28 -0
- package/lib/index.d.ts +28 -0
- package/lib/index.js +391 -219
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
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
|
+
|
|
3
13
|
## 1.19.0
|
|
4
14
|
|
|
5
15
|
### 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",
|
|
@@ -149,12 +150,13 @@ export default [
|
|
|
149
150
|
|
|
150
151
|
### Variable Naming Rules
|
|
151
152
|
|
|
152
|
-
| Rule
|
|
153
|
-
|
|
|
154
|
-
| [no-single-char-variables](docs/rules/NO_SINGLE_CHAR_VARIABLES.md)
|
|
155
|
-
| [no-lazy-identifiers](docs/rules/NO_LAZY_IDENTIFIERS.md)
|
|
156
|
-
| [boolean-naming-prefix](docs/rules/BOOLEAN_NAMING_PREFIX.md)
|
|
157
|
-
| [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 | ❌ |
|
|
158
160
|
|
|
159
161
|
### File Naming Rules
|
|
160
162
|
|
|
@@ -206,6 +208,7 @@ export default [
|
|
|
206
208
|
| [no-nested-interface-declaration](docs/rules/NO_NESTED_INTERFACE_DECLARATION.md) | Disallow inline object types in interface/type properties | ❌ |
|
|
207
209
|
| [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
|
|
208
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 | ✅ |
|
|
209
212
|
| [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
|
|
210
213
|
| [sort-type-alphabetically](docs/rules/SORT_TYPE_ALPHABETICALLY.md) | Enforce A-Z sorting of properties within type groups | ✅ |
|
|
211
214
|
| [sort-type-required-first](docs/rules/SORT_TYPE_REQUIRED_FIRST.md) | Enforce required properties before optional in types/interfaces | ✅ |
|
|
@@ -214,7 +217,7 @@ export default [
|
|
|
214
217
|
|
|
215
218
|
| Rule | Description | Fixable |
|
|
216
219
|
| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------- |
|
|
217
|
-
| [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 | ✅ |
|
|
218
221
|
| [jsx-no-inline-object-prop](docs/rules/JSX_NO_INLINE_OBJECT_PROP.md) | Disallow inline object literals in JSX props | ❌ |
|
|
219
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 | ✅ |
|
|
220
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 | ❌ |
|
|
@@ -240,14 +243,14 @@ export default [
|
|
|
240
243
|
|
|
241
244
|
| Preset | Severity | Base Rules | JSX Rules | Next.js Rules | Total Rules |
|
|
242
245
|
| -------------------- | -------- | ---------- | --------- | ------------- | ----------- |
|
|
243
|
-
| `base` | warn |
|
|
244
|
-
| `base/recommended` | error |
|
|
245
|
-
| `react` | warn |
|
|
246
|
-
| `react/recommended` | error |
|
|
247
|
-
| `nextjs` | warn |
|
|
248
|
-
| `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 |
|
|
249
252
|
|
|
250
|
-
### Base Configuration Rules (
|
|
253
|
+
### Base Configuration Rules (37 rules)
|
|
251
254
|
|
|
252
255
|
Included in `base`, `base/recommended`, and all other presets:
|
|
253
256
|
|
|
@@ -280,6 +283,7 @@ Included in `base`, `base/recommended`, and all other presets:
|
|
|
280
283
|
- `nextfriday/prefer-guard-clause`
|
|
281
284
|
- `nextfriday/prefer-import-type`
|
|
282
285
|
- `nextfriday/prefer-inline-literal-union`
|
|
286
|
+
- `nextfriday/prefer-inline-type-export`
|
|
283
287
|
- `nextfriday/prefer-named-param-types`
|
|
284
288
|
- `nextfriday/prefer-react-import-types`
|
|
285
289
|
- `nextfriday/require-explicit-return-type`
|
|
@@ -332,7 +336,7 @@ Additionally included in `nextjs`, `nextjs/recommended` only:
|
|
|
332
336
|
|
|
333
337
|
## Agent Skill
|
|
334
338
|
|
|
335
|
-
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.
|
|
336
340
|
|
|
337
341
|
```bash
|
|
338
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
|
|
@@ -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.
|