eslint-plugin-nextfriday 1.20.0 → 1.22.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 +19 -0
- package/README.md +26 -17
- package/docs/rules/ENFORCE_CAMEL_CASE.md +68 -0
- package/docs/rules/ENFORCE_CONSTANT_CASE.md +27 -12
- package/docs/rules/ENFORCE_CURLY_NEWLINE.md +4 -10
- package/docs/rules/ENFORCE_PROPERTY_CASE.md +63 -0
- package/docs/rules/ENFORCE_SERVICE_NAMING.md +33 -21
- package/docs/rules/JSX_NO_TERNARY_NULL.md +1 -1
- package/docs/rules/NO_INLINE_NESTED_OBJECT.md +10 -4
- package/docs/rules/NO_INLINE_RETURN_PROPERTIES.md +83 -0
- package/docs/rules/NO_MISLEADING_CONSTANT_CASE.md +33 -17
- package/docs/rules/PREFER_INLINE_LITERAL_UNION.md +6 -6
- package/lib/index.cjs +841 -546
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +2352 -756
- package/lib/index.d.ts +2352 -756
- package/lib/index.js +841 -546
- package/lib/index.js.map +1 -1
- package/package.json +26 -26
- package/docs/rules/MD_FILENAME_CASE_RESTRICTION.md +0 -36
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# eslint-plugin-nextfriday
|
|
2
2
|
|
|
3
|
+
## 1.22.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#92](https://github.com/next-friday/eslint-plugin-nextfriday/pull/92) [`432b4b4`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/432b4b49cabc0d6ea9289441b13e7442d328614f) Thanks [@joetakara](https://github.com/joetakara)! - Rework enforce-service-naming rule to ban misleading prefixes (set, delete, do, handle) instead of forcing fetch prefix. Allow single-property inline nested objects in no-inline-nested-object rule. Fix documentation inconsistencies across README, rule docs, and configuration presets. Update dependencies to resolve security vulnerabilities.
|
|
8
|
+
|
|
9
|
+
## 1.21.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#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
|
|
14
|
+
|
|
15
|
+
- [#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
|
|
16
|
+
- Add `enforce-camel-case` rule: ban snake_case variables/functions, restrict PascalCase to React components
|
|
17
|
+
- Add `enforce-property-case` rule: enforce camelCase for unquoted object property keys
|
|
18
|
+
- Refactor `enforce-constant-case` to only check global scope, support RegExp/objects/arrays/as const
|
|
19
|
+
- Refactor `no-misleading-constant-case` to flag SCREAMING_SNAKE_CASE in local scope
|
|
20
|
+
- Fix `prefer-import-type` incorrectly converting imports used as JSX prop values to type imports
|
|
21
|
+
|
|
3
22
|
## 1.20.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -78,12 +78,14 @@ export default [
|
|
|
78
78
|
"nextfriday/no-single-char-variables": "error",
|
|
79
79
|
"nextfriday/no-lazy-identifiers": "error",
|
|
80
80
|
"nextfriday/boolean-naming-prefix": "error",
|
|
81
|
+
"nextfriday/enforce-camel-case": "error",
|
|
81
82
|
"nextfriday/enforce-constant-case": "error",
|
|
83
|
+
"nextfriday/enforce-property-case": "error",
|
|
84
|
+
"nextfriday/no-misleading-constant-case": "error",
|
|
82
85
|
|
|
83
86
|
// File Naming
|
|
84
87
|
"nextfriday/file-kebab-case": "error",
|
|
85
88
|
"nextfriday/jsx-pascal-case": "error",
|
|
86
|
-
"nextfriday/md-filename-case-restriction": "error",
|
|
87
89
|
|
|
88
90
|
// Code Style
|
|
89
91
|
"nextfriday/no-emoji": "error",
|
|
@@ -97,9 +99,11 @@ export default [
|
|
|
97
99
|
"nextfriday/enforce-sorted-destructuring": "error",
|
|
98
100
|
"nextfriday/no-env-fallback": "error",
|
|
99
101
|
"nextfriday/no-inline-default-export": "error",
|
|
102
|
+
"nextfriday/no-direct-date": "error",
|
|
100
103
|
"nextfriday/newline-after-multiline-block": "error",
|
|
101
104
|
"nextfriday/newline-before-return": "error",
|
|
102
105
|
"nextfriday/no-inline-nested-object": "error",
|
|
106
|
+
"nextfriday/no-inline-return-properties": "error",
|
|
103
107
|
"nextfriday/prefer-async-await": "error",
|
|
104
108
|
"nextfriday/enforce-curly-newline": "error",
|
|
105
109
|
"nextfriday/no-nested-ternary": "error",
|
|
@@ -155,16 +159,17 @@ export default [
|
|
|
155
159
|
| [no-single-char-variables](docs/rules/NO_SINGLE_CHAR_VARIABLES.md) | Disallow single character variable names (e.g., `d`, `u`, `l`) | ❌ |
|
|
156
160
|
| [no-lazy-identifiers](docs/rules/NO_LAZY_IDENTIFIERS.md) | Disallow lazy identifiers like `xxx`, `asdf`, `qwerty` | ❌ |
|
|
157
161
|
| [boolean-naming-prefix](docs/rules/BOOLEAN_NAMING_PREFIX.md) | Enforce boolean variables to have prefix (is, has, should, can, etc.) | ❌ |
|
|
158
|
-
| [enforce-
|
|
159
|
-
| [
|
|
162
|
+
| [enforce-camel-case](docs/rules/ENFORCE_CAMEL_CASE.md) | Ban snake_case and restrict PascalCase to React components | ❌ |
|
|
163
|
+
| [enforce-constant-case](docs/rules/ENFORCE_CONSTANT_CASE.md) | Enforce SCREAMING_SNAKE_CASE for global static constant values | ❌ |
|
|
164
|
+
| [enforce-property-case](docs/rules/ENFORCE_PROPERTY_CASE.md) | Enforce camelCase for unquoted object property keys | ❌ |
|
|
165
|
+
| [no-misleading-constant-case](docs/rules/NO_MISLEADING_CONSTANT_CASE.md) | Disallow SCREAMING_SNAKE_CASE in local scope and for dynamic values | ❌ |
|
|
160
166
|
|
|
161
167
|
### File Naming Rules
|
|
162
168
|
|
|
163
|
-
| Rule
|
|
164
|
-
|
|
|
165
|
-
| [file-kebab-case](docs/rules/FILE_KEBAB_CASE.md)
|
|
166
|
-
| [jsx-pascal-case](docs/rules/JSX_PASCAL_CASE.md)
|
|
167
|
-
| [md-filename-case-restriction](docs/rules/MD_FILENAME_CASE_RESTRICTION.md) | Enforce SNAKE_CASE filenames for .md files | ❌ |
|
|
169
|
+
| Rule | Description | Fixable |
|
|
170
|
+
| ------------------------------------------------ | ---------------------------------------------------- | ------- |
|
|
171
|
+
| [file-kebab-case](docs/rules/FILE_KEBAB_CASE.md) | Enforce kebab-case filenames for .ts and .js files | ❌ |
|
|
172
|
+
| [jsx-pascal-case](docs/rules/JSX_PASCAL_CASE.md) | Enforce PascalCase filenames for .jsx and .tsx files | ❌ |
|
|
168
173
|
|
|
169
174
|
### Code Style Rules
|
|
170
175
|
|
|
@@ -185,6 +190,7 @@ export default [
|
|
|
185
190
|
| [newline-after-multiline-block](docs/rules/NEWLINE_AFTER_MULTILINE_BLOCK.md) | Require a blank line after multi-line statements | ✅ |
|
|
186
191
|
| [newline-before-return](docs/rules/NEWLINE_BEFORE_RETURN.md) | Require a blank line before return statements | ✅ |
|
|
187
192
|
| [no-inline-nested-object](docs/rules/NO_INLINE_NESTED_OBJECT.md) | Require nested objects and arrays to span multiple lines | ✅ |
|
|
193
|
+
| [no-inline-return-properties](docs/rules/NO_INLINE_RETURN_PROPERTIES.md) | Require return object properties to use shorthand notation | ❌ |
|
|
188
194
|
| [prefer-async-await](docs/rules/PREFER_ASYNC_AWAIT.md) | Enforce async/await over .then() promise chains | ❌ |
|
|
189
195
|
| [enforce-curly-newline](docs/rules/ENFORCE_CURLY_NEWLINE.md) | Enforce curly braces for multi-line if, forbid for single-line | ✅ |
|
|
190
196
|
| [no-nested-ternary](docs/rules/NO_NESTED_TERNARY.md) | Disallow nested ternary expressions | ❌ |
|
|
@@ -243,26 +249,27 @@ export default [
|
|
|
243
249
|
|
|
244
250
|
| Preset | Severity | Base Rules | JSX Rules | Next.js Rules | Total Rules |
|
|
245
251
|
| -------------------- | -------- | ---------- | --------- | ------------- | ----------- |
|
|
246
|
-
| `base` | warn |
|
|
247
|
-
| `base/recommended` | error |
|
|
248
|
-
| `react` | warn |
|
|
249
|
-
| `react/recommended` | error |
|
|
250
|
-
| `nextjs` | warn |
|
|
251
|
-
| `nextjs/recommended` | error |
|
|
252
|
+
| `base` | warn | 40 | 0 | 0 | 40 |
|
|
253
|
+
| `base/recommended` | error | 40 | 0 | 0 | 40 |
|
|
254
|
+
| `react` | warn | 40 | 15 | 0 | 55 |
|
|
255
|
+
| `react/recommended` | error | 40 | 15 | 0 | 55 |
|
|
256
|
+
| `nextjs` | warn | 40 | 15 | 1 | 56 |
|
|
257
|
+
| `nextjs/recommended` | error | 40 | 15 | 1 | 56 |
|
|
252
258
|
|
|
253
|
-
### Base Configuration Rules (
|
|
259
|
+
### Base Configuration Rules (40 rules)
|
|
254
260
|
|
|
255
261
|
Included in `base`, `base/recommended`, and all other presets:
|
|
256
262
|
|
|
257
263
|
- `nextfriday/boolean-naming-prefix`
|
|
264
|
+
- `nextfriday/enforce-camel-case`
|
|
258
265
|
- `nextfriday/enforce-constant-case`
|
|
259
266
|
- `nextfriday/enforce-curly-newline`
|
|
260
267
|
- `nextfriday/enforce-hook-naming`
|
|
268
|
+
- `nextfriday/enforce-property-case`
|
|
261
269
|
- `nextfriday/enforce-service-naming`
|
|
262
270
|
- `nextfriday/enforce-sorted-destructuring`
|
|
263
271
|
- `nextfriday/enforce-type-declaration-order`
|
|
264
272
|
- `nextfriday/file-kebab-case`
|
|
265
|
-
- `nextfriday/md-filename-case-restriction`
|
|
266
273
|
- `nextfriday/newline-after-multiline-block`
|
|
267
274
|
- `nextfriday/newline-before-return`
|
|
268
275
|
- `nextfriday/no-complex-inline-return`
|
|
@@ -271,8 +278,10 @@ Included in `base`, `base/recommended`, and all other presets:
|
|
|
271
278
|
- `nextfriday/no-env-fallback`
|
|
272
279
|
- `nextfriday/no-inline-default-export`
|
|
273
280
|
- `nextfriday/no-inline-nested-object`
|
|
281
|
+
- `nextfriday/no-inline-return-properties`
|
|
274
282
|
- `nextfriday/no-lazy-identifiers`
|
|
275
283
|
- `nextfriday/no-logic-in-params`
|
|
284
|
+
- `nextfriday/no-misleading-constant-case`
|
|
276
285
|
- `nextfriday/no-nested-interface-declaration`
|
|
277
286
|
- `nextfriday/no-nested-ternary`
|
|
278
287
|
- `nextfriday/no-relative-imports`
|
|
@@ -336,7 +345,7 @@ Additionally included in `nextjs`, `nextjs/recommended` only:
|
|
|
336
345
|
|
|
337
346
|
## Agent Skill
|
|
338
347
|
|
|
339
|
-
This plugin ships with an [Agent Skill](https://github.com/anthropics/skills) that teaches AI coding assistants (Claude Code, Cursor, etc.) all
|
|
348
|
+
This plugin ships with an [Agent Skill](https://github.com/anthropics/skills) that teaches AI coding assistants (Claude Code, Cursor, etc.) all 56 rules so they generate compliant code from the start.
|
|
340
349
|
|
|
341
350
|
```bash
|
|
342
351
|
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 static
|
|
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
|
|
|
@@ -15,6 +17,9 @@ const defaultCover = "/images/default.jpg";
|
|
|
15
17
|
const pageLimit = 10;
|
|
16
18
|
const apiBaseUrl = "https://api.example.com";
|
|
17
19
|
const template = `hello world`;
|
|
20
|
+
const phoneRegex = /^[0-9]{10}$/;
|
|
21
|
+
const default_theme = "dark";
|
|
22
|
+
export const categories = [{ id: "1" }] as const;
|
|
18
23
|
```
|
|
19
24
|
|
|
20
25
|
### Correct
|
|
@@ -24,27 +29,37 @@ const DEFAULT_COVER = "/images/default.jpg";
|
|
|
24
29
|
const PAGE_LIMIT = 10;
|
|
25
30
|
const API_BASE_URL = "https://api.example.com";
|
|
26
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;
|
|
27
39
|
|
|
28
|
-
// Booleans with standard prefixes (is, has, should,
|
|
29
|
-
const
|
|
40
|
+
// Booleans with standard prefixes (is, has, should, etc.) are exempt
|
|
41
|
+
const isProduction = true;
|
|
30
42
|
const hasAccess = false;
|
|
31
|
-
const shouldRender = true;
|
|
32
43
|
|
|
33
44
|
// Template literals with expressions are dynamic, camelCase is fine
|
|
34
45
|
const pendingHref = `/branch/${branch.branchNumber}`;
|
|
35
|
-
const greeting = `Hello, ${user.name}!`;
|
|
36
46
|
|
|
37
|
-
//
|
|
38
|
-
const config = { key: "value" };
|
|
39
|
-
const items = [1, 2, 3];
|
|
47
|
+
// Functions and components are not checked
|
|
40
48
|
const handleClick = () => {};
|
|
49
|
+
const MyComponent = () => {};
|
|
41
50
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
// Local scope is not checked
|
|
52
|
+
function foo() {
|
|
53
|
+
const maxRetry = 3;
|
|
54
|
+
}
|
|
45
55
|
```
|
|
46
56
|
|
|
47
57
|
## When Not To Use It
|
|
48
58
|
|
|
49
59
|
- If your project uses different naming conventions for constants
|
|
50
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
|
|
@@ -16,35 +16,29 @@ This rule manages curly braces for `IfStatement` based on visual layout (line br
|
|
|
16
16
|
### Incorrect
|
|
17
17
|
|
|
18
18
|
```ts
|
|
19
|
-
// Single-line with braces (BAD)
|
|
20
19
|
if (!data) {
|
|
21
20
|
return [];
|
|
22
21
|
}
|
|
23
22
|
if (x > 0) {
|
|
24
23
|
doSomething();
|
|
25
24
|
}
|
|
25
|
+
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
```ts
|
|
28
28
|
if (veryLongCondition && anotherCondition) return [];
|
|
29
|
-
|
|
30
|
-
if (condition) doSomething();
|
|
31
29
|
```
|
|
32
30
|
|
|
33
31
|
### Correct
|
|
34
32
|
|
|
35
33
|
```ts
|
|
36
|
-
// Single-line without braces (GOOD)
|
|
37
34
|
if (!data) return [];
|
|
38
35
|
if (x > 0) doSomething();
|
|
36
|
+
```
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
```ts
|
|
41
39
|
if (veryLongCondition && anotherCondition) {
|
|
42
40
|
return [];
|
|
43
41
|
}
|
|
44
|
-
|
|
45
|
-
if (condition) {
|
|
46
|
-
doSomething();
|
|
47
|
-
}
|
|
48
42
|
```
|
|
49
43
|
|
|
50
44
|
## Auto-Fix
|
|
@@ -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,48 +1,60 @@
|
|
|
1
1
|
# enforce-service-naming
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Ban misleading function name prefixes in `*.service.ts` files.
|
|
4
4
|
|
|
5
5
|
## Rule Details
|
|
6
6
|
|
|
7
|
-
This rule
|
|
7
|
+
This rule flags misleading prefixes on async exported functions in `*.service.ts` files. It does not force a specific prefix — developers choose based on intent.
|
|
8
8
|
|
|
9
9
|
### Why?
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
11
|
+
Service functions represent API/network calls. Certain prefixes are misleading in this context:
|
|
12
|
+
|
|
13
|
+
- `set` implies a local setter, not an API call
|
|
14
|
+
- `delete` is a JS reserved word that may conflict
|
|
15
|
+
- `do` is vague and conveys no intent
|
|
16
|
+
- `handle` is typically for UI event handlers, not service operations
|
|
17
|
+
|
|
18
|
+
### Banned Prefixes
|
|
19
|
+
|
|
20
|
+
| Prefix | Why banned | Suggested alternatives |
|
|
21
|
+
| -------- | ----------------------------------------- | ------------------------- |
|
|
22
|
+
| `set` | Implies local setter, not API call | `update`, `save`, `patch` |
|
|
23
|
+
| `delete` | JS reserved word, may conflict | `remove`, `archive` |
|
|
24
|
+
| `do` | Vague, no intent | `submit`, `process` |
|
|
25
|
+
| `handle` | Vague, typically for event handlers in UI | `create`, `verify` |
|
|
14
26
|
|
|
15
27
|
## Examples
|
|
16
28
|
|
|
17
29
|
### Incorrect
|
|
18
30
|
|
|
19
31
|
```ts
|
|
20
|
-
//
|
|
21
|
-
export async function
|
|
22
|
-
export async function
|
|
23
|
-
export async function
|
|
24
|
-
export
|
|
32
|
+
// profile.service.ts
|
|
33
|
+
export async function setProfile(data: ProfileRequest) {}
|
|
34
|
+
export async function deleteComment(id: string) {}
|
|
35
|
+
export async function doLogin(credentials: LoginRequest) {}
|
|
36
|
+
export async function handlePayment(data: PaymentRequest) {}
|
|
25
37
|
```
|
|
26
38
|
|
|
27
39
|
### Correct
|
|
28
40
|
|
|
29
41
|
```ts
|
|
30
|
-
//
|
|
42
|
+
// profile.service.ts
|
|
43
|
+
export async function getArticles() {}
|
|
31
44
|
export async function fetchArticles() {}
|
|
32
|
-
export async function
|
|
33
|
-
export async function
|
|
34
|
-
export
|
|
45
|
+
export async function searchArticles(query: string) {}
|
|
46
|
+
export async function createOrder(data: OrderRequest) {}
|
|
47
|
+
export async function updateProfile(id: string, data: ProfileRequest) {}
|
|
48
|
+
export async function removeComment(id: string) {}
|
|
49
|
+
export async function verifyEmail(token: string) {}
|
|
35
50
|
|
|
36
51
|
// Non-async functions can use any prefix
|
|
37
|
-
export function
|
|
52
|
+
export function setLocalState(value: string) {}
|
|
38
53
|
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
export async function updateArticle() {}
|
|
42
|
-
export async function deleteComment() {}
|
|
54
|
+
// Non-exported functions are not checked
|
|
55
|
+
async function handleInternal() {}
|
|
43
56
|
```
|
|
44
57
|
|
|
45
58
|
## When Not To Use It
|
|
46
59
|
|
|
47
|
-
|
|
48
|
-
- If you prefer `get`/`load` prefixes for data-fetching operations
|
|
60
|
+
If your project does not follow a service layer pattern or has different naming conventions for service functions.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# no-inline-nested-object
|
|
2
2
|
|
|
3
|
-
Require nested objects and arrays to span multiple lines.
|
|
3
|
+
Require nested objects and arrays with multiple properties to span multiple lines.
|
|
4
4
|
|
|
5
5
|
## Rule Details
|
|
6
6
|
|
|
7
|
-
This rule enforces that when an object property's value is another object or array, it should span multiple lines rather than being written inline. This improves readability and makes diffs cleaner when properties are added or removed.
|
|
7
|
+
This rule enforces that when an object property's value is another object or array with more than one element, it should span multiple lines rather than being written inline. Single-property nested objects are allowed inline. This improves readability and makes diffs cleaner when properties are added or removed.
|
|
8
8
|
|
|
9
9
|
## Examples
|
|
10
10
|
|
|
@@ -25,6 +25,12 @@ const routes = {
|
|
|
25
25
|
|
|
26
26
|
### Correct
|
|
27
27
|
|
|
28
|
+
```ts
|
|
29
|
+
const config = {
|
|
30
|
+
database: { host: "localhost" },
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
28
34
|
```ts
|
|
29
35
|
const config = {
|
|
30
36
|
database: {
|
|
@@ -65,8 +71,8 @@ const initialState = {
|
|
|
65
71
|
|
|
66
72
|
## When Not To Use It
|
|
67
73
|
|
|
68
|
-
If you prefer compact inline nested objects for
|
|
74
|
+
If you prefer compact inline nested objects for all cases, or if your team has different formatting preferences.
|
|
69
75
|
|
|
70
76
|
## Fixable
|
|
71
77
|
|
|
72
|
-
This rule is auto-fixable. Running ESLint with the `--fix` flag will automatically expand inline nested objects and arrays to multiple lines.
|
|
78
|
+
This rule is auto-fixable. Running ESLint with the `--fix` flag will automatically expand inline nested objects and arrays with multiple properties to multiple lines.
|
|
@@ -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.
|