eslint-plugin-code-style 1.7.4 β 1.8.1
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 +56 -0
- package/README.md +117 -38
- package/index.d.ts +2 -0
- package/index.js +786 -165
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.8.1] - 2026-02-03
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **`function-naming-convention`** - Add `handleXxx` β `xxxHandler` auto-fix (converts `handleClick` to `clickHandler` instead of `handleClickHandler`)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## [1.8.0] - 2026-02-03
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **New Rule: `no-hardcoded-strings`** - Enforce importing strings from constants/strings modules instead of hardcoding them inline. Promotes maintainability, consistency, and easier internationalization.
|
|
23
|
+
- Detects hardcoded strings in JSX text content, attributes, and component logic
|
|
24
|
+
- Configurable `ignoreAttributes`, `extraIgnoreAttributes`, `ignorePatterns` options
|
|
25
|
+
- Automatically ignores technical strings (CSS units, URLs, paths, identifiers, etc.)
|
|
26
|
+
- Valid import paths: `@/constants`, `@/strings`, `@/@constants`, `@/@strings`, `@/data/constants`, `@/data/strings`
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **`absolute-imports-only`** - Add `strings`, `@constants`, `@strings` to default allowed folders
|
|
31
|
+
- **`module-index-exports`** - Add `strings`, `@constants`, `@strings` to default module folders
|
|
32
|
+
|
|
33
|
+
### Stats
|
|
34
|
+
|
|
35
|
+
- Total Rules: 70 (was 69)
|
|
36
|
+
- Auto-fixable: 63 rules π§
|
|
37
|
+
- Report-only: 7 rules (was 6)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## [1.7.6] - 2026-02-02
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- **`ternary-condition-multiline`** - Now depends only on operand count, not line length:
|
|
46
|
+
- β€maxOperands (default: 3): Always collapse to single line regardless of line length
|
|
47
|
+
- \>maxOperands: Format multiline with each operand on its own line
|
|
48
|
+
- Removed `maxLineLength` option (no longer used)
|
|
49
|
+
- This aligns behavior with `multiline-if-conditions` rule
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## [1.7.5] - 2026-02-02
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- **`ternary-condition-multiline`** - For β€3 operands, always collapse to single line when `?` is on different line than condition end (enforces `condition ? value : value` format for simple ternaries)
|
|
58
|
+
- **`no-empty-lines-in-function-params`** - Add detection for empty lines in TSTypeLiteral (type annotation objects like `{ prop: Type }` in intersection types)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
10
62
|
## [1.7.4] - 2026-02-02
|
|
11
63
|
|
|
12
64
|
### Fixed
|
|
@@ -1117,6 +1169,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1117
1169
|
|
|
1118
1170
|
---
|
|
1119
1171
|
|
|
1172
|
+
[1.8.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.8.0...v1.8.1
|
|
1173
|
+
[1.8.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.7.6...v1.8.0
|
|
1174
|
+
[1.7.6]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.7.5...v1.7.6
|
|
1175
|
+
[1.7.5]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.7.4...v1.7.5
|
|
1120
1176
|
[1.7.4]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.7.3...v1.7.4
|
|
1121
1177
|
[1.7.3]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.7.2...v1.7.3
|
|
1122
1178
|
[1.7.2]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.7.1...v1.7.2
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
**A powerful ESLint plugin for enforcing consistent code formatting and style rules in React/JSX projects.**
|
|
21
21
|
|
|
22
|
-
*
|
|
22
|
+
*70 rules (63 auto-fixable) to keep your codebase clean and consistent*
|
|
23
23
|
|
|
24
24
|
</div>
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
## π― Why This Plugin?
|
|
29
29
|
|
|
30
|
-
This plugin provides **
|
|
30
|
+
This plugin provides **70 custom rules** (63 auto-fixable) for code formatting. Built for **ESLint v9 flat configs**.
|
|
31
31
|
|
|
32
32
|
> **Note:** ESLint [deprecated 79 formatting rules](https://eslint.org/blog/2023/10/deprecating-formatting-rules/) in v8.53.0. Our recommended configs use `@stylistic/eslint-plugin` as the replacement for these deprecated rules.
|
|
33
33
|
|
|
@@ -36,7 +36,7 @@ This plugin provides **69 custom rules** (63 auto-fixable) for code formatting.
|
|
|
36
36
|
- **Works alongside existing tools** β Complements ESLint's built-in rules and packages like eslint-plugin-react, eslint-plugin-import, etc
|
|
37
37
|
- **Self-sufficient rules** β Each rule handles complete formatting independently
|
|
38
38
|
- **Consistency at scale** β Reduces code-style differences between team members by enforcing uniform formatting across your projects
|
|
39
|
-
- **Highly automated** β 63 of
|
|
39
|
+
- **Highly automated** β 63 of 70 rules support auto-fix with `eslint --fix`
|
|
40
40
|
|
|
41
41
|
When combined with ESLint's native rules and other popular plugins, this package helps create a complete code style solution that keeps your codebase clean and consistent.
|
|
42
42
|
|
|
@@ -236,6 +236,7 @@ rules: {
|
|
|
236
236
|
"code-style/no-empty-lines-in-jsx": "error",
|
|
237
237
|
"code-style/no-empty-lines-in-objects": "error",
|
|
238
238
|
"code-style/no-empty-lines-in-switch-cases": "error",
|
|
239
|
+
"code-style/no-hardcoded-strings": "error",
|
|
239
240
|
"code-style/no-inline-type-definitions": "error",
|
|
240
241
|
"code-style/object-property-per-line": "error",
|
|
241
242
|
"code-style/object-property-value-brace": "error",
|
|
@@ -259,7 +260,7 @@ rules: {
|
|
|
259
260
|
|
|
260
261
|
## π Rules Categories
|
|
261
262
|
|
|
262
|
-
> **
|
|
263
|
+
> **70 rules total** β 63 with auto-fix π§, 7 report-only. See detailed examples in [Rules Reference](#-rules-reference) below.
|
|
263
264
|
>
|
|
264
265
|
> **Legend:** π§ Auto-fixable with `eslint --fix` β’ βοΈ Customizable options
|
|
265
266
|
|
|
@@ -295,11 +296,11 @@ rules: {
|
|
|
295
296
|
| `if-statement-format` | `{` on same line as `if`/`else if`, `else` on same line as `}`, proper spacing π§ |
|
|
296
297
|
| `multiline-if-conditions` | Conditions exceeding threshold get one operand per line with proper indentation (default: >3) π§ βοΈ |
|
|
297
298
|
| `no-empty-lines-in-switch-cases` | No empty line after `case X:` before code, no empty lines between cases π§ |
|
|
298
|
-
| `ternary-condition-multiline` |
|
|
299
|
+
| `ternary-condition-multiline` | β€maxOperands always single line; >maxOperands multiline (based on operand count, not line length) π§ βοΈ |
|
|
299
300
|
| **Function Rules** | |
|
|
300
301
|
| `function-call-spacing` | No space between function name and `(`: `fn()` not `fn ()` π§ |
|
|
301
302
|
| `function-declaration-style` | Auto-fix for `func-style`: converts function declarations to arrow expressions π§ |
|
|
302
|
-
| `function-naming-convention` | Functions use camelCase, start with verb
|
|
303
|
+
| `function-naming-convention` | Functions use camelCase, start with verb, end with Handler suffix; handleXxx β xxxHandler π§ |
|
|
303
304
|
| `function-object-destructure` | Non-component functions: use typed params (not destructured), destructure in body; report dot notation access π§ |
|
|
304
305
|
| `function-params-per-line` | When multiline, each param on own line with consistent indentation π§ |
|
|
305
306
|
| `no-empty-lines-in-function-params` | No empty lines between parameters or after `(`/before `)` π§ |
|
|
@@ -348,6 +349,8 @@ rules: {
|
|
|
348
349
|
| `typescript-definition-location` | Enforce TypeScript definitions (interfaces, types, enums) to be in designated folders βοΈ |
|
|
349
350
|
| **React Rules** | |
|
|
350
351
|
| `react-code-order` | Enforce consistent ordering in components and hooks: props destructure β refs β state β redux β router β context β custom hooks β derived β memo β callback β handlers β effects β return π§ |
|
|
352
|
+
| **String Rules** | |
|
|
353
|
+
| `no-hardcoded-strings` | Enforce importing strings from constants/strings modules instead of hardcoding them βοΈ |
|
|
351
354
|
| **Variable Rules** | |
|
|
352
355
|
| `variable-naming-convention` | camelCase for all variables and constants, PascalCase for components, `use` prefix for hooks π§ |
|
|
353
356
|
|
|
@@ -1211,24 +1214,24 @@ switch (status) {
|
|
|
1211
1214
|
|
|
1212
1215
|
### `ternary-condition-multiline`
|
|
1213
1216
|
|
|
1214
|
-
**What it does:**
|
|
1215
|
-
-
|
|
1216
|
-
-
|
|
1217
|
+
**What it does:** Formats ternary expressions based on condition operand count:
|
|
1218
|
+
- β€maxOperands (default: 3): Always collapse to single line regardless of line length
|
|
1219
|
+
- \>maxOperands: Expand to multiline with each operand on its own line
|
|
1217
1220
|
|
|
1218
|
-
**Why use it:**
|
|
1221
|
+
**Why use it:** Consistent formatting based on complexity, not line length. Simple conditions stay readable on one line; complex conditions get proper multiline formatting.
|
|
1219
1222
|
|
|
1220
1223
|
**Options:**
|
|
1221
1224
|
|
|
1222
1225
|
| Option | Type | Default | Description |
|
|
1223
1226
|
|--------|------|---------|-------------|
|
|
1224
|
-
| `maxOperands` | `integer` | `3` | Maximum operands to keep on single line |
|
|
1225
|
-
| `maxLineLength` | `integer` | `120` | Maximum line length for single-line ternaries |
|
|
1227
|
+
| `maxOperands` | `integer` | `3` | Maximum condition operands to keep ternary on single line |
|
|
1226
1228
|
|
|
1227
1229
|
```javascript
|
|
1228
|
-
// β
Good β
|
|
1230
|
+
// β
Good β β€3 operands always on single line
|
|
1229
1231
|
const x = a && b && c ? "yes" : "no";
|
|
1232
|
+
const url = lang === "ar" ? `${apiEndpoints.exam.status}/${jobId}?lang=ar` : `${apiEndpoints.exam.status}/${jobId}`;
|
|
1230
1233
|
|
|
1231
|
-
// β
Good β
|
|
1234
|
+
// β
Good β >3 operands formatted multiline
|
|
1232
1235
|
const style = variant === "ghost"
|
|
1233
1236
|
|| variant === "ghost-danger"
|
|
1234
1237
|
|| variant === "muted"
|
|
@@ -1236,7 +1239,12 @@ const style = variant === "ghost"
|
|
|
1236
1239
|
? "transparent"
|
|
1237
1240
|
: "solid";
|
|
1238
1241
|
|
|
1239
|
-
// β Bad β
|
|
1242
|
+
// β Bad β β€3 operands split across lines
|
|
1243
|
+
const x = a && b && c
|
|
1244
|
+
? "yes"
|
|
1245
|
+
: "no";
|
|
1246
|
+
|
|
1247
|
+
// β Bad β >3 operands crammed on one line
|
|
1240
1248
|
const style = variant === "ghost" || variant === "ghost-danger" || variant === "muted" || variant === "primary" ? "transparent" : "solid";
|
|
1241
1249
|
```
|
|
1242
1250
|
|
|
@@ -1311,33 +1319,37 @@ function isAuthenticated(): boolean {
|
|
|
1311
1319
|
|
|
1312
1320
|
**What it does:** Enforces naming conventions for functions:
|
|
1313
1321
|
- **camelCase** required
|
|
1314
|
-
- **Verb prefix**
|
|
1315
|
-
- **
|
|
1322
|
+
- **Verb prefix** required (get, set, fetch, is, has, can, should, click, submit, etc.)
|
|
1323
|
+
- **Handler suffix** required (all functions must end with `Handler`)
|
|
1324
|
+
- **Auto-fixes** `handleXxx` to `xxxHandler` (avoids redundant `handleClickHandler`)
|
|
1325
|
+
- **Auto-fixes** PascalCase to camelCase for verb-prefixed functions
|
|
1316
1326
|
|
|
1317
|
-
**Why use it:** Function names should describe actions. Verb prefixes make the purpose immediately clear.
|
|
1327
|
+
**Why use it:** Function names should describe actions. Verb prefixes make the purpose immediately clear, and consistent Handler suffix makes event handlers easy to identify.
|
|
1318
1328
|
|
|
1319
1329
|
```javascript
|
|
1320
|
-
// β
Good β
|
|
1321
|
-
function
|
|
1322
|
-
function
|
|
1323
|
-
function
|
|
1324
|
-
function
|
|
1325
|
-
function
|
|
1326
|
-
function
|
|
1327
|
-
function
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1330
|
+
// β
Good β verb prefix + Handler suffix
|
|
1331
|
+
function getUserDataHandler() {}
|
|
1332
|
+
function setUserNameHandler(name) {}
|
|
1333
|
+
function clickHandler() {}
|
|
1334
|
+
function submitHandler() {}
|
|
1335
|
+
function isValidEmailHandler(email) {}
|
|
1336
|
+
function hasPermissionHandler(user) {}
|
|
1337
|
+
function canAccessHandler(resource) {}
|
|
1338
|
+
const fetchUsersHandler = async () => {};
|
|
1339
|
+
|
|
1340
|
+
// β Bad (auto-fixed) β handleXxx β xxxHandler
|
|
1341
|
+
function handleClick() {} // β clickHandler
|
|
1342
|
+
function handleSubmit() {} // β submitHandler
|
|
1343
|
+
function handleChange() {} // β changeHandler
|
|
1331
1344
|
|
|
1332
|
-
// β Bad β
|
|
1333
|
-
function
|
|
1334
|
-
function
|
|
1335
|
-
function
|
|
1336
|
-
function valid(email) {}
|
|
1345
|
+
// β Bad (auto-fixed) β missing Handler suffix
|
|
1346
|
+
function getUserData() {} // β getUserDataHandler
|
|
1347
|
+
function setUserName() {} // β setUserNameHandler
|
|
1348
|
+
function fetchUsers() {} // β fetchUsersHandler
|
|
1337
1349
|
|
|
1338
|
-
// β Bad β
|
|
1339
|
-
function GetUserData() {}
|
|
1340
|
-
function
|
|
1350
|
+
// β Bad (auto-fixed) β PascalCase to camelCase
|
|
1351
|
+
function GetUserData() {} // β getUserDataHandler
|
|
1352
|
+
function FetchStatus() {} // β fetchStatusHandler
|
|
1341
1353
|
```
|
|
1342
1354
|
|
|
1343
1355
|
---
|
|
@@ -3273,6 +3285,73 @@ const YetAnotherBad = ({ title }) => {
|
|
|
3273
3285
|
|
|
3274
3286
|
<br />
|
|
3275
3287
|
|
|
3288
|
+
## π String Rules
|
|
3289
|
+
|
|
3290
|
+
### `no-hardcoded-strings`
|
|
3291
|
+
|
|
3292
|
+
**What it does:** Enforces that user-facing strings should be imported from constants/strings modules rather than hardcoded inline. This promotes maintainability, consistency, and enables easier internationalization.
|
|
3293
|
+
|
|
3294
|
+
**Why use it:** Hardcoded strings scattered throughout your codebase are hard to maintain, translate, and keep consistent. Centralizing strings in constants makes them easy to find, update, and potentially translate.
|
|
3295
|
+
|
|
3296
|
+
**Options:**
|
|
3297
|
+
|
|
3298
|
+
| Option | Type | Default | Description |
|
|
3299
|
+
|--------|------|---------|-------------|
|
|
3300
|
+
| `ignoreAttributes` | `string[]` | See below | JSX attributes to ignore (replaces defaults) |
|
|
3301
|
+
| `extraIgnoreAttributes` | `string[]` | `[]` | Additional JSX attributes to ignore (extends defaults) |
|
|
3302
|
+
| `ignorePatterns` | `string[]` | `[]` | Regex patterns for strings to ignore |
|
|
3303
|
+
|
|
3304
|
+
**Default ignored attributes:** `className`, `id`, `type`, `name`, `href`, `src`, `alt`, `role`, `style`, `key`, `data-*`, `aria-*`, and many more HTML/SVG attributes.
|
|
3305
|
+
|
|
3306
|
+
**Default ignored patterns:** Empty strings, single characters, CSS units (`px`, `em`, `%`), colors, URLs, paths, file extensions, MIME types, UUIDs, dates, camelCase/snake_case identifiers, HTTP methods, and other technical strings.
|
|
3307
|
+
|
|
3308
|
+
```javascript
|
|
3309
|
+
// β
Good β strings imported from constants
|
|
3310
|
+
import { BUTTON_LABEL, ERROR_MESSAGE, welcomeText } from "@/constants";
|
|
3311
|
+
import { FORM_LABELS } from "@/strings";
|
|
3312
|
+
|
|
3313
|
+
const Component = () => (
|
|
3314
|
+
<div>
|
|
3315
|
+
<button>{BUTTON_LABEL}</button>
|
|
3316
|
+
<span>{ERROR_MESSAGE}</span>
|
|
3317
|
+
<p>{welcomeText}</p>
|
|
3318
|
+
</div>
|
|
3319
|
+
);
|
|
3320
|
+
|
|
3321
|
+
const getMessage = () => ERROR_MESSAGE;
|
|
3322
|
+
|
|
3323
|
+
// β
Good β technical strings are allowed
|
|
3324
|
+
<input type="text" className="input-field" />
|
|
3325
|
+
<a href="/dashboard">Link</a>
|
|
3326
|
+
const url = `/api/users/${id}`;
|
|
3327
|
+
const size = "100px";
|
|
3328
|
+
|
|
3329
|
+
// β Bad β hardcoded user-facing strings
|
|
3330
|
+
<button>Submit Form</button>
|
|
3331
|
+
<span>Something went wrong</span>
|
|
3332
|
+
const message = "Welcome to the application";
|
|
3333
|
+
return "User not found";
|
|
3334
|
+
```
|
|
3335
|
+
|
|
3336
|
+
**Configuration example:**
|
|
3337
|
+
|
|
3338
|
+
```javascript
|
|
3339
|
+
// Allow more attributes, add custom ignore patterns
|
|
3340
|
+
"code-style/no-hardcoded-strings": ["error", {
|
|
3341
|
+
extraIgnoreAttributes: ["tooltip", "placeholder"],
|
|
3342
|
+
ignorePatterns: ["^TODO:", "^FIXME:"]
|
|
3343
|
+
}]
|
|
3344
|
+
```
|
|
3345
|
+
|
|
3346
|
+
**Valid import paths for constants:**
|
|
3347
|
+
- `@/constants` or `@/@constants`
|
|
3348
|
+
- `@/strings` or `@/@strings`
|
|
3349
|
+
- `@/data/constants` or `@/data/strings`
|
|
3350
|
+
|
|
3351
|
+
---
|
|
3352
|
+
|
|
3353
|
+
<br />
|
|
3354
|
+
|
|
3276
3355
|
## π Variable Rules
|
|
3277
3356
|
|
|
3278
3357
|
### `variable-naming-convention`
|
|
@@ -3306,7 +3385,7 @@ const UseAuth = () => {}; // hooks should be camelCase
|
|
|
3306
3385
|
|
|
3307
3386
|
## π§ Auto-fixing
|
|
3308
3387
|
|
|
3309
|
-
63 of
|
|
3388
|
+
63 of 70 rules support auto-fixing. Run ESLint with the `--fix` flag:
|
|
3310
3389
|
|
|
3311
3390
|
```bash
|
|
3312
3391
|
# Fix all files in src directory
|
package/index.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export type RuleNames =
|
|
|
59
59
|
| "code-style/no-empty-lines-in-jsx"
|
|
60
60
|
| "code-style/no-empty-lines-in-objects"
|
|
61
61
|
| "code-style/no-empty-lines-in-switch-cases"
|
|
62
|
+
| "code-style/no-hardcoded-strings"
|
|
62
63
|
| "code-style/object-property-per-line"
|
|
63
64
|
| "code-style/object-property-value-brace"
|
|
64
65
|
| "code-style/object-property-value-format"
|
|
@@ -150,6 +151,7 @@ interface PluginRules {
|
|
|
150
151
|
"no-empty-lines-in-jsx": Rule.RuleModule;
|
|
151
152
|
"no-empty-lines-in-objects": Rule.RuleModule;
|
|
152
153
|
"no-empty-lines-in-switch-cases": Rule.RuleModule;
|
|
154
|
+
"no-hardcoded-strings": Rule.RuleModule;
|
|
153
155
|
"object-property-per-line": Rule.RuleModule;
|
|
154
156
|
"object-property-value-brace": Rule.RuleModule;
|
|
155
157
|
"object-property-value-format": Rule.RuleModule;
|