eslint-plugin-nextfriday 1.19.0 → 1.21.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 +23 -0
- package/README.md +22 -15
- package/docs/rules/ENFORCE_CAMEL_CASE.md +68 -0
- package/docs/rules/ENFORCE_CONSTANT_CASE.md +32 -10
- package/docs/rules/ENFORCE_PROPERTY_CASE.md +63 -0
- package/docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md +24 -2
- package/docs/rules/NO_INLINE_RETURN_PROPERTIES.md +83 -0
- package/docs/rules/NO_LAZY_IDENTIFIERS.md +3 -1
- package/docs/rules/NO_MISLEADING_CONSTANT_CASE.md +76 -0
- package/docs/rules/PREFER_INLINE_TYPE_EXPORT.md +64 -0
- package/lib/index.cjs +982 -466
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +2394 -728
- package/lib/index.d.ts +2394 -728
- package/lib/index.js +982 -466
- package/lib/index.js.map +1 -1
- package/package.json +26 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# eslint-plugin-nextfriday
|
|
2
2
|
|
|
3
|
+
## 1.21.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#87](https://github.com/next-friday/eslint-plugin-nextfriday/pull/87) [`ed401e3`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/ed401e39db04857995ddcc29d7444298181ee60b) Thanks [@joetakara](https://github.com/joetakara)! - Add `no-inline-return-properties` rule that enforces shorthand-only properties in return objects
|
|
8
|
+
|
|
9
|
+
- [#90](https://github.com/next-friday/eslint-plugin-nextfriday/pull/90) [`d5e9db5`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/d5e9db562cb9e38beadd59da39f8618b6f5825ed) Thanks [@joetakara](https://github.com/joetakara)! - Add comprehensive naming convention rules and fix prefer-import-type JSX prop bug
|
|
10
|
+
- Add `enforce-camel-case` rule: ban snake_case variables/functions, restrict PascalCase to React components
|
|
11
|
+
- Add `enforce-property-case` rule: enforce camelCase for unquoted object property keys
|
|
12
|
+
- Refactor `enforce-constant-case` to only check global scope, support RegExp/objects/arrays/as const
|
|
13
|
+
- Refactor `no-misleading-constant-case` to flag SCREAMING_SNAKE_CASE in local scope
|
|
14
|
+
- Fix `prefer-import-type` incorrectly converting imports used as JSX prop values to type imports
|
|
15
|
+
|
|
16
|
+
## 1.20.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- [#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
|
|
21
|
+
- 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)
|
|
22
|
+
- Add `prefer-inline-type-export` rule that requires type/interface declarations to be exported inline
|
|
23
|
+
- Update `enforce-constant-case` to exempt booleans with standard prefixes (is, has, should, etc.) to resolve conflict with `boolean-naming-prefix`
|
|
24
|
+
- Update existing rules: enforce-constant-case, jsx-newline-between-elements, no-lazy-identifiers
|
|
25
|
+
|
|
3
26
|
## 1.19.0
|
|
4
27
|
|
|
5
28
|
### 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,15 @@ 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-
|
|
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-camel-case](docs/rules/ENFORCE_CAMEL_CASE.md) | Ban snake_case and restrict PascalCase to React components | ❌ |
|
|
159
|
+
| [enforce-constant-case](docs/rules/ENFORCE_CONSTANT_CASE.md) | Enforce SCREAMING_SNAKE_CASE for global static constant values | ❌ |
|
|
160
|
+
| [enforce-property-case](docs/rules/ENFORCE_PROPERTY_CASE.md) | Enforce camelCase for unquoted object property keys | ❌ |
|
|
161
|
+
| [no-misleading-constant-case](docs/rules/NO_MISLEADING_CONSTANT_CASE.md) | Disallow SCREAMING_SNAKE_CASE in local scope and for dynamic values | ❌ |
|
|
158
162
|
|
|
159
163
|
### File Naming Rules
|
|
160
164
|
|
|
@@ -183,6 +187,7 @@ export default [
|
|
|
183
187
|
| [newline-after-multiline-block](docs/rules/NEWLINE_AFTER_MULTILINE_BLOCK.md) | Require a blank line after multi-line statements | ✅ |
|
|
184
188
|
| [newline-before-return](docs/rules/NEWLINE_BEFORE_RETURN.md) | Require a blank line before return statements | ✅ |
|
|
185
189
|
| [no-inline-nested-object](docs/rules/NO_INLINE_NESTED_OBJECT.md) | Require nested objects and arrays to span multiple lines | ✅ |
|
|
190
|
+
| [no-inline-return-properties](docs/rules/NO_INLINE_RETURN_PROPERTIES.md) | Require return object properties to use shorthand notation | ❌ |
|
|
186
191
|
| [prefer-async-await](docs/rules/PREFER_ASYNC_AWAIT.md) | Enforce async/await over .then() promise chains | ❌ |
|
|
187
192
|
| [enforce-curly-newline](docs/rules/ENFORCE_CURLY_NEWLINE.md) | Enforce curly braces for multi-line if, forbid for single-line | ✅ |
|
|
188
193
|
| [no-nested-ternary](docs/rules/NO_NESTED_TERNARY.md) | Disallow nested ternary expressions | ❌ |
|
|
@@ -206,6 +211,7 @@ export default [
|
|
|
206
211
|
| [no-nested-interface-declaration](docs/rules/NO_NESTED_INTERFACE_DECLARATION.md) | Disallow inline object types in interface/type properties | ❌ |
|
|
207
212
|
| [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
|
|
208
213
|
| [prefer-inline-literal-union](docs/rules/PREFER_INLINE_LITERAL_UNION.md) | Enforce inlining literal union types for better IDE hover info | ✅ |
|
|
214
|
+
| [prefer-inline-type-export](docs/rules/PREFER_INLINE_TYPE_EXPORT.md) | Require type/interface exports inline at the declaration | ✅ |
|
|
209
215
|
| [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
|
|
210
216
|
| [sort-type-alphabetically](docs/rules/SORT_TYPE_ALPHABETICALLY.md) | Enforce A-Z sorting of properties within type groups | ✅ |
|
|
211
217
|
| [sort-type-required-first](docs/rules/SORT_TYPE_REQUIRED_FIRST.md) | Enforce required properties before optional in types/interfaces | ✅ |
|
|
@@ -214,7 +220,7 @@ export default [
|
|
|
214
220
|
|
|
215
221
|
| Rule | Description | Fixable |
|
|
216
222
|
| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------- |
|
|
217
|
-
| [jsx-newline-between-elements](docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md) | Require empty lines between sibling multi-line JSX
|
|
223
|
+
| [jsx-newline-between-elements](docs/rules/JSX_NEWLINE_BETWEEN_ELEMENTS.md) | Require empty lines between sibling multi-line JSX children | ✅ |
|
|
218
224
|
| [jsx-no-inline-object-prop](docs/rules/JSX_NO_INLINE_OBJECT_PROP.md) | Disallow inline object literals in JSX props | ❌ |
|
|
219
225
|
| [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
226
|
| [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 +246,14 @@ export default [
|
|
|
240
246
|
|
|
241
247
|
| Preset | Severity | Base Rules | JSX Rules | Next.js Rules | Total Rules |
|
|
242
248
|
| -------------------- | -------- | ---------- | --------- | ------------- | ----------- |
|
|
243
|
-
| `base` | warn |
|
|
244
|
-
| `base/recommended` | error |
|
|
245
|
-
| `react` | warn |
|
|
246
|
-
| `react/recommended` | error |
|
|
247
|
-
| `nextjs` | warn |
|
|
248
|
-
| `nextjs/recommended` | error |
|
|
249
|
+
| `base` | warn | 37 | 0 | 0 | 37 |
|
|
250
|
+
| `base/recommended` | error | 37 | 0 | 0 | 37 |
|
|
251
|
+
| `react` | warn | 37 | 15 | 0 | 52 |
|
|
252
|
+
| `react/recommended` | error | 37 | 15 | 0 | 52 |
|
|
253
|
+
| `nextjs` | warn | 37 | 15 | 1 | 53 |
|
|
254
|
+
| `nextjs/recommended` | error | 37 | 15 | 1 | 53 |
|
|
249
255
|
|
|
250
|
-
### Base Configuration Rules (
|
|
256
|
+
### Base Configuration Rules (37 rules)
|
|
251
257
|
|
|
252
258
|
Included in `base`, `base/recommended`, and all other presets:
|
|
253
259
|
|
|
@@ -280,6 +286,7 @@ Included in `base`, `base/recommended`, and all other presets:
|
|
|
280
286
|
- `nextfriday/prefer-guard-clause`
|
|
281
287
|
- `nextfriday/prefer-import-type`
|
|
282
288
|
- `nextfriday/prefer-inline-literal-union`
|
|
289
|
+
- `nextfriday/prefer-inline-type-export`
|
|
283
290
|
- `nextfriday/prefer-named-param-types`
|
|
284
291
|
- `nextfriday/prefer-react-import-types`
|
|
285
292
|
- `nextfriday/require-explicit-return-type`
|
|
@@ -332,7 +339,7 @@ Additionally included in `nextjs`, `nextjs/recommended` only:
|
|
|
332
339
|
|
|
333
340
|
## Agent Skill
|
|
334
341
|
|
|
335
|
-
This plugin ships with an [Agent Skill](https://github.com/anthropics/skills) that teaches AI coding assistants (Claude Code, Cursor, etc.) all
|
|
342
|
+
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
343
|
|
|
337
344
|
```bash
|
|
338
345
|
npx skills add next-friday/eslint-plugin-nextfriday --skill eslint-plugin-nextfriday
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# enforce-camel-case
|
|
2
|
+
|
|
3
|
+
Enforce camelCase for variables and functions, ban snake_case, and restrict PascalCase to React components.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule enforces consistent naming conventions across your codebase:
|
|
8
|
+
|
|
9
|
+
- Variables and functions must use camelCase
|
|
10
|
+
- snake_case is banned for all variable and function declarations
|
|
11
|
+
- PascalCase is reserved exclusively for React components (functions that return JSX)
|
|
12
|
+
|
|
13
|
+
Global static constants are not checked by this rule. Use `enforce-constant-case` for those.
|
|
14
|
+
|
|
15
|
+
### Why?
|
|
16
|
+
|
|
17
|
+
Consistent naming conventions reduce cognitive load. When PascalCase is reserved for components and camelCase is used for everything else, the name alone tells you what something is.
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
### Incorrect
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// snake_case variables
|
|
25
|
+
let current_index = 0;
|
|
26
|
+
const first_name = "John";
|
|
27
|
+
|
|
28
|
+
// snake_case functions
|
|
29
|
+
function calculate_total() {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// PascalCase for non-component functions
|
|
34
|
+
const CalculateTotal = () => 0;
|
|
35
|
+
const FormatDate = (date: string) => date;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Correct
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// camelCase variables
|
|
42
|
+
let currentIndex = 0;
|
|
43
|
+
const firstName = "John";
|
|
44
|
+
|
|
45
|
+
// camelCase functions
|
|
46
|
+
function calculateTotal() { return 0; }
|
|
47
|
+
const formatDate = (date: string) => date;
|
|
48
|
+
|
|
49
|
+
// PascalCase for React components
|
|
50
|
+
const ArticleCard = () => <div />;
|
|
51
|
+
const WrappedComponent = memo(() => <div />);
|
|
52
|
+
const LazyPage = lazy(() => import("./Page"));
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Exceptions
|
|
56
|
+
|
|
57
|
+
- Global static constants (handled by `enforce-constant-case`)
|
|
58
|
+
- SCREAMING_SNAKE_CASE variables (handled by `no-misleading-constant-case`)
|
|
59
|
+
- React components wrapped with `memo`, `forwardRef`, or `lazy`
|
|
60
|
+
|
|
61
|
+
## When Not To Use It
|
|
62
|
+
|
|
63
|
+
If your project does not follow the convention that PascalCase is reserved for React components.
|
|
64
|
+
|
|
65
|
+
## Related Rules
|
|
66
|
+
|
|
67
|
+
- [enforce-constant-case](ENFORCE_CONSTANT_CASE.md) - Enforces SCREAMING_SNAKE_CASE for global static constants
|
|
68
|
+
- [no-misleading-constant-case](NO_MISLEADING_CONSTANT_CASE.md) - Disallows SCREAMING_SNAKE_CASE in local scope
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# enforce-constant-case
|
|
2
2
|
|
|
3
|
-
Enforce SCREAMING_SNAKE_CASE for constant
|
|
3
|
+
Enforce SCREAMING_SNAKE_CASE for global constant static values.
|
|
4
4
|
|
|
5
5
|
## Rule Details
|
|
6
6
|
|
|
7
|
-
This rule ensures that `const` declarations with
|
|
7
|
+
This rule ensures that global-scope `const` declarations with static values use SCREAMING_SNAKE_CASE naming convention. Static values include: string/number/boolean literals, RegExp, static template literals, `as const` assertions, and objects/arrays containing only literal values.
|
|
8
|
+
|
|
9
|
+
Only global scope (top-level of a file) is checked. Local scope constants inside functions are not checked by this rule.
|
|
8
10
|
|
|
9
11
|
## Examples
|
|
10
12
|
|
|
@@ -13,9 +15,11 @@ This rule ensures that `const` declarations with primitive values (strings, numb
|
|
|
13
15
|
```ts
|
|
14
16
|
const defaultCover = "/images/default.jpg";
|
|
15
17
|
const pageLimit = 10;
|
|
16
|
-
const isEnabled = true;
|
|
17
18
|
const apiBaseUrl = "https://api.example.com";
|
|
18
19
|
const template = `hello world`;
|
|
20
|
+
const phoneRegex = /^[0-9]{10}$/;
|
|
21
|
+
const default_theme = "dark";
|
|
22
|
+
export const categories = [{ id: "1" }] as const;
|
|
19
23
|
```
|
|
20
24
|
|
|
21
25
|
### Correct
|
|
@@ -23,21 +27,39 @@ const template = `hello world`;
|
|
|
23
27
|
```ts
|
|
24
28
|
const DEFAULT_COVER = "/images/default.jpg";
|
|
25
29
|
const PAGE_LIMIT = 10;
|
|
26
|
-
const IS_ENABLED = true;
|
|
27
30
|
const API_BASE_URL = "https://api.example.com";
|
|
28
31
|
const TEMPLATE = `hello world`;
|
|
32
|
+
const PHONE_REGEX = /^[0-9]{10}$/;
|
|
33
|
+
const DEFAULT_THEME = "dark";
|
|
34
|
+
export const CATEGORIES = [{ id: "1" }] as const;
|
|
35
|
+
|
|
36
|
+
const SKELETON_ITEMS = [1, 2, 3, 4, 5];
|
|
37
|
+
const MAP_STYLE = { height: "320px", width: "100%" };
|
|
38
|
+
const STATUS_MAP = { ACTIVE: "active" } as const;
|
|
39
|
+
|
|
40
|
+
// Booleans with standard prefixes (is, has, should, etc.) are exempt
|
|
41
|
+
const isProduction = true;
|
|
42
|
+
const hasAccess = false;
|
|
29
43
|
|
|
30
|
-
//
|
|
31
|
-
const
|
|
32
|
-
|
|
44
|
+
// Template literals with expressions are dynamic, camelCase is fine
|
|
45
|
+
const pendingHref = `/branch/${branch.branchNumber}`;
|
|
46
|
+
|
|
47
|
+
// Functions and components are not checked
|
|
33
48
|
const handleClick = () => {};
|
|
49
|
+
const MyComponent = () => {};
|
|
34
50
|
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
51
|
+
// Local scope is not checked
|
|
52
|
+
function foo() {
|
|
53
|
+
const maxRetry = 3;
|
|
54
|
+
}
|
|
38
55
|
```
|
|
39
56
|
|
|
40
57
|
## When Not To Use It
|
|
41
58
|
|
|
42
59
|
- If your project uses different naming conventions for constants
|
|
43
60
|
- If you prefer camelCase for all variable declarations
|
|
61
|
+
|
|
62
|
+
## Related Rules
|
|
63
|
+
|
|
64
|
+
- [no-misleading-constant-case](NO_MISLEADING_CONSTANT_CASE.md) - Disallows SCREAMING_SNAKE_CASE in local scope and for dynamic values
|
|
65
|
+
- [enforce-camel-case](ENFORCE_CAMEL_CASE.md) - Enforces camelCase for variables and functions
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# enforce-property-case
|
|
2
|
+
|
|
3
|
+
Enforce camelCase for unquoted object property keys.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule bans snake_case and SCREAMING_SNAKE_CASE for unquoted object property keys. Quoted keys (string literals) are allowed for API boundaries where external systems require different conventions.
|
|
8
|
+
|
|
9
|
+
### Why?
|
|
10
|
+
|
|
11
|
+
Object properties should follow the same camelCase convention as variables. When an external API requires snake_case keys, wrapping them in quotes makes it explicit that the naming is intentional and driven by an external contract.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Incorrect
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const userPayload = {
|
|
19
|
+
first_name: "John",
|
|
20
|
+
last_name: "Doe",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const item = {
|
|
24
|
+
ITEM_ID: 1,
|
|
25
|
+
};
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Correct
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// camelCase properties
|
|
32
|
+
const userPayload = {
|
|
33
|
+
firstName: "John",
|
|
34
|
+
lastName: "Doe",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Quoted keys for API boundaries
|
|
38
|
+
const apiPayload = {
|
|
39
|
+
first_name: "John",
|
|
40
|
+
last_name: "Doe",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// as const objects are exempt (enum-like pattern)
|
|
44
|
+
const STATUS_MAP = {
|
|
45
|
+
ACTIVE: "active",
|
|
46
|
+
INACTIVE: "inactive",
|
|
47
|
+
} as const;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Exceptions
|
|
51
|
+
|
|
52
|
+
- Quoted property keys (`"first_name"`) are always allowed
|
|
53
|
+
- Computed property keys (`[key]`) are not checked
|
|
54
|
+
- Properties inside `as const` objects and arrays are exempt
|
|
55
|
+
|
|
56
|
+
## When Not To Use It
|
|
57
|
+
|
|
58
|
+
If your project frequently uses snake_case or SCREAMING_SNAKE_CASE for object properties without quoting.
|
|
59
|
+
|
|
60
|
+
## Related Rules
|
|
61
|
+
|
|
62
|
+
- [enforce-camel-case](ENFORCE_CAMEL_CASE.md) - Enforces camelCase for variables and functions
|
|
63
|
+
- [enforce-constant-case](ENFORCE_CONSTANT_CASE.md) - Enforces SCREAMING_SNAKE_CASE for global constants
|
|
@@ -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,83 @@
|
|
|
1
|
+
# no-inline-return-properties
|
|
2
|
+
|
|
3
|
+
Require return object properties to use shorthand notation by extracting non-shorthand values to const variables.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule enforces that all properties in a returned object literal use shorthand notation. When a return statement contains an object with renamed or computed properties, the values should be extracted into const variables before the return statement.
|
|
8
|
+
|
|
9
|
+
### Why?
|
|
10
|
+
|
|
11
|
+
Return objects with a mix of shorthand and non-shorthand properties are harder to scan. Extracting values into named constants before returning keeps the return statement clean and makes the data flow easier to follow.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Incorrect
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
function useBranch() {
|
|
19
|
+
return {
|
|
20
|
+
admins,
|
|
21
|
+
branch,
|
|
22
|
+
coursesCurrentPage: coursePage,
|
|
23
|
+
coursesTotalPages: Math.ceil(sortedLearning.length / COURSES_PER_PAGE) || 1,
|
|
24
|
+
members,
|
|
25
|
+
membersHref: `/branch/${branchNumber}/members`,
|
|
26
|
+
news,
|
|
27
|
+
newsCurrentPage: newsData?.currentPage ?? 1,
|
|
28
|
+
newsTotalPages: newsData?.pages ?? 1,
|
|
29
|
+
stats,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
function useJoin() {
|
|
36
|
+
return {
|
|
37
|
+
error,
|
|
38
|
+
isSubmitting,
|
|
39
|
+
onJoin: handleJoin,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Correct
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
function useBranch() {
|
|
48
|
+
const coursesCurrentPage = coursePage;
|
|
49
|
+
const coursesTotalPages = Math.ceil(sortedLearning.length / COURSES_PER_PAGE) || 1;
|
|
50
|
+
const membersHref = `/branch/${branchNumber}/members`;
|
|
51
|
+
const newsCurrentPage = newsData?.currentPage ?? 1;
|
|
52
|
+
const newsTotalPages = newsData?.pages ?? 1;
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
admins,
|
|
56
|
+
branch,
|
|
57
|
+
coursesCurrentPage,
|
|
58
|
+
coursesTotalPages,
|
|
59
|
+
members,
|
|
60
|
+
membersHref,
|
|
61
|
+
news,
|
|
62
|
+
newsCurrentPage,
|
|
63
|
+
newsTotalPages,
|
|
64
|
+
stats,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
function useJoin() {
|
|
71
|
+
const onJoin = handleJoin;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
error,
|
|
75
|
+
isSubmitting,
|
|
76
|
+
onJoin,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## When Not To Use It
|
|
82
|
+
|
|
83
|
+
If your project prefers inline property values in return statements for brevity.
|
|
@@ -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,76 @@
|
|
|
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 is reserved for global static constants. This rule flags it when used incorrectly:
|
|
8
|
+
|
|
9
|
+
- **Mutable bindings**: `let` or `var` with SCREAMING_SNAKE_CASE
|
|
10
|
+
- **Dynamic values**: `const` with function calls, await, dynamic templates, objects with dynamic values
|
|
11
|
+
- **Local scope**: SCREAMING_SNAKE_CASE inside functions, even for static values
|
|
12
|
+
|
|
13
|
+
### Why?
|
|
14
|
+
|
|
15
|
+
SCREAMING_SNAKE_CASE signals a compile-time constant at the module level. Using it for local variables or dynamic values is misleading. Local constants should use camelCase regardless of whether the value is static.
|
|
16
|
+
|
|
17
|
+
## Examples
|
|
18
|
+
|
|
19
|
+
### Incorrect
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// Mutable bindings
|
|
23
|
+
let API_URL = "https://api.example.com";
|
|
24
|
+
var MAX_COUNT = 10;
|
|
25
|
+
|
|
26
|
+
// Dynamic values at global scope
|
|
27
|
+
const API_URL = getUrl();
|
|
28
|
+
const USER_ID = await fetchId();
|
|
29
|
+
const PATHNAME = `/news/${slug}`;
|
|
30
|
+
const CONFIG = { key: getValue() };
|
|
31
|
+
|
|
32
|
+
// SCREAMING_SNAKE_CASE in local scope (even static values)
|
|
33
|
+
function foo() {
|
|
34
|
+
const MAX_RETRY = 3;
|
|
35
|
+
const TOTAL_COUNT = items.length;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const MyComponent = () => {
|
|
39
|
+
const ACTIVE_ITEMS = ITEMS.filter((i) => i.active);
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Correct
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
// Global static constants use SCREAMING_SNAKE_CASE
|
|
47
|
+
const API_URL = "https://api.example.com";
|
|
48
|
+
const MAX_COUNT = 10;
|
|
49
|
+
const ITEMS = [1, 2, 3];
|
|
50
|
+
const CONFIG = { key: "value" };
|
|
51
|
+
const VARIANTS = ["a", "b"] as const;
|
|
52
|
+
|
|
53
|
+
// Dynamic values use camelCase
|
|
54
|
+
const apiUrl = getUrl();
|
|
55
|
+
const userId = await fetchId();
|
|
56
|
+
const pathname = `/news/${slug}`;
|
|
57
|
+
|
|
58
|
+
// Local scope uses camelCase
|
|
59
|
+
function foo() {
|
|
60
|
+
const maxRetry = 3;
|
|
61
|
+
const totalCount = items.length;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Mutable bindings use camelCase
|
|
65
|
+
let count = 10;
|
|
66
|
+
var name = "foo";
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## When Not To Use It
|
|
70
|
+
|
|
71
|
+
If your project does not follow the convention that SCREAMING_SNAKE_CASE is reserved for global static constants.
|
|
72
|
+
|
|
73
|
+
## Related Rules
|
|
74
|
+
|
|
75
|
+
- [enforce-constant-case](ENFORCE_CONSTANT_CASE.md) - The complementary rule that enforces SCREAMING_SNAKE_CASE for global static constants
|
|
76
|
+
- [enforce-camel-case](ENFORCE_CAMEL_CASE.md) - Enforces camelCase for variables and functions
|
|
@@ -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.
|