eslint-plugin-code-style 1.8.3 → 1.9.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 CHANGED
@@ -7,6 +7,66 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [1.9.1] - 2026-02-03
11
+
12
+ ### Enhanced
13
+
14
+ - **`no-hardcoded-strings`** - Now detects additional hardcoded values:
15
+ - HTTP status codes (4xx, 5xx like "404", "422", "500") with descriptive error message
16
+ - Role/permission names ("admin", "user", "moderator", etc.) with descriptive error message
17
+ - Added `@/data` as preferred import source for enums/objects
18
+ - Improved error messages to mention all valid import sources
19
+
20
+ ### Fixed
21
+
22
+ - **`no-hardcoded-strings`** - Fixed bug where `isInConstantsObjectHandler` incorrectly matched camelCase variable names due to case-insensitive regex flag
23
+
24
+ ---
25
+
26
+ ## [1.9.0] - 2026-02-03
27
+
28
+ **New Rule: class-method-definition-format + Enhanced Spacing Rules**
29
+
30
+ **Version Range:** v1.8.1 → v1.9.0
31
+
32
+ ### Added
33
+
34
+ **New Rules (1)**
35
+ - **`class-method-definition-format`** - Enforce consistent spacing in class and method definitions 🔧
36
+ - Space before opening brace `{` in class declarations
37
+ - No space between method name and opening parenthesis `(`
38
+ - Space before opening brace `{` in method definitions
39
+ - Opening brace must be on same line as class/method signature
40
+
41
+ ### Enhanced
42
+
43
+ - **`function-call-spacing`** - Now also handles:
44
+ - `new` expressions (`new Class ()` → `new Class()`)
45
+ - Generic type calls (`get <Type>()` → `get<Type>()`)
46
+ - **`member-expression-bracket-spacing`** - Now also handles:
47
+ - TypeScript indexed access types (`Type ["prop"]` → `Type["prop"]`)
48
+
49
+ ### Stats
50
+
51
+ - Total Rules: 71 (was 70)
52
+ - Auto-fixable: 64 rules 🔧 (was 63)
53
+ - Report-only: 7 rules
54
+
55
+ **Full Changelog:** [v1.8.1...v1.9.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.8.1...v1.9.0)
56
+
57
+ ---
58
+
59
+ ## [1.8.4] - 2026-02-03
60
+
61
+ ### Documentation
62
+
63
+ - Fix v1.8.0 CHANGELOG entry to include Release Title, Version Range, and Full Changelog link (required for MINOR releases)
64
+ - Add missing comparison links in CHANGELOG.md (v1.3.9 through v1.8.3)
65
+ - Update manage-rule skill with CHANGELOG format requirements for new rules
66
+ - Update Current releases list in AGENTS.md to include v1.8.0
67
+
68
+ ---
69
+
10
70
  ## [1.8.3] - 2026-02-03
11
71
 
12
72
  ### Fixed
@@ -41,9 +101,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
41
101
 
42
102
  ## [1.8.0] - 2026-02-03
43
103
 
104
+ **New Rule: no-hardcoded-strings**
105
+
106
+ **Version Range:** v1.7.1 → v1.8.0
107
+
44
108
  ### Added
45
109
 
46
- - **New Rule: `no-hardcoded-strings`** - Enforce importing strings from constants/strings modules instead of hardcoding them inline. Promotes maintainability, consistency, and easier internationalization.
110
+ **New Rules (1)**
111
+ - **`no-hardcoded-strings`** - Enforce importing strings from constants/strings modules instead of hardcoding them inline 🔧
47
112
  - Detects hardcoded strings in JSX text content, attributes, and component logic
48
113
  - Configurable `ignoreAttributes`, `extraIgnoreAttributes`, `ignorePatterns` options
49
114
  - Automatically ignores technical strings (CSS units, URLs, paths, identifiers, etc.)
@@ -60,6 +125,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
60
125
  - Auto-fixable: 63 rules 🔧
61
126
  - Report-only: 7 rules (was 6)
62
127
 
128
+ **Full Changelog:** [v1.7.1...v1.8.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.7.1...v1.8.0)
129
+
63
130
  ---
64
131
 
65
132
  ## [1.7.6] - 2026-02-02
@@ -1193,6 +1260,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1193
1260
 
1194
1261
  ---
1195
1262
 
1263
+ [1.9.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.9.0...v1.9.1
1264
+ [1.9.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.8.4...v1.9.0
1265
+ [1.8.4]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.8.3...v1.8.4
1266
+ [1.8.3]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.8.2...v1.8.3
1267
+ [1.8.2]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.8.1...v1.8.2
1196
1268
  [1.8.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.8.0...v1.8.1
1197
1269
  [1.8.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.7.6...v1.8.0
1198
1270
  [1.7.6]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.7.5...v1.7.6
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
- *70 rules (63 auto-fixable) to keep your codebase clean and consistent*
22
+ *71 rules (64 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 **70 custom rules** (63 auto-fixable) for code formatting. Built for **ESLint v9 flat configs**.
30
+ This plugin provides **71 custom rules** (64 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 **70 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 70 rules support auto-fix with `eslint --fix`
39
+ - **Highly automated** — 64 of 71 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
 
@@ -97,7 +97,7 @@ We provide **ready-to-use ESLint flat configuration files** that combine `eslint
97
97
  <td width="50%">
98
98
 
99
99
  ### 🔧 Auto-Fixable Rules
100
- **63 rules** support automatic fixing with `eslint --fix`. 6 rules are report-only (require manual changes).
100
+ **64 rules** support automatic fixing with `eslint --fix`. 6 rules are report-only (require manual changes).
101
101
 
102
102
  </td>
103
103
  <td width="50%">
@@ -190,6 +190,7 @@ rules: {
190
190
  "code-style/arrow-function-simplify": "error",
191
191
  "code-style/assignment-value-same-line": "error",
192
192
  "code-style/block-statement-newlines": "error",
193
+ "code-style/class-method-definition-format": "error",
193
194
  "code-style/class-naming-convention": "error",
194
195
  "code-style/classname-dynamic-at-end": "error",
195
196
  "code-style/classname-multiline": "error",
@@ -260,7 +261,7 @@ rules: {
260
261
 
261
262
  ## 📖 Rules Categories
262
263
 
263
- > **70 rules total** — 63 with auto-fix 🔧, 7 report-only. See detailed examples in [Rules Reference](#-rules-reference) below.
264
+ > **71 rules total** — 64 with auto-fix 🔧, 7 report-only. See detailed examples in [Rules Reference](#-rules-reference) below.
264
265
  >
265
266
  > **Legend:** 🔧 Auto-fixable with `eslint --fix` • ⚙️ Customizable options
266
267
 
@@ -288,6 +289,7 @@ rules: {
288
289
  | `component-props-destructure` | Component props must be destructured `({ prop })` not received as `(props)` 🔧 |
289
290
  | `component-props-inline-type` | Inline type annotation `} : {` with matching props, proper spacing, commas, no interface reference 🔧 |
290
291
  | **Class Rules** | |
292
+ | `class-method-definition-format` | Consistent spacing in class/method definitions: space before `{`, no space before `(` 🔧 |
291
293
  | `class-naming-convention` | Class declarations must end with "Class" suffix (e.g., `ApiServiceClass`) 🔧 |
292
294
  | **Control Flow Rules** | |
293
295
  | `block-statement-newlines` | Newline after `{` and before `}` in if/for/while/function blocks 🔧 |
@@ -893,6 +895,60 @@ dispatch(
893
895
 
894
896
  ## 🏛️ Class Rules
895
897
 
898
+ ### `class-method-definition-format`
899
+
900
+ **What it does:** Enforces consistent spacing in class and method definitions:
901
+ - Space before opening brace `{` in class declarations
902
+ - No space between method name and opening parenthesis `(`
903
+ - Space before opening brace `{` in method definitions
904
+ - Opening brace must be on same line as class/method signature
905
+
906
+ **Why use it:** Consistent formatting makes code more readable and prevents common spacing inconsistencies in class definitions.
907
+
908
+ ```javascript
909
+ // ✅ Good — proper spacing in class and methods
910
+ class ApiServiceClass {
911
+ getDataHandler(): string {
912
+ return "data";
913
+ }
914
+
915
+ async fetchUserHandler(id: string): Promise<User> {
916
+ return await this.fetch(id);
917
+ }
918
+ }
919
+
920
+ // ❌ Bad — missing space before { in class
921
+ class ApiServiceClass{
922
+ getDataHandler(): string {
923
+ return "data";
924
+ }
925
+ }
926
+
927
+ // ❌ Bad — space between method name and (
928
+ class ApiServiceClass {
929
+ getDataHandler (): string {
930
+ return "data";
931
+ }
932
+ }
933
+
934
+ // ❌ Bad — missing space before { in method
935
+ class ApiServiceClass {
936
+ getDataHandler(): string{
937
+ return "data";
938
+ }
939
+ }
940
+
941
+ // ❌ Bad — opening brace on different line
942
+ class ApiServiceClass {
943
+ getDataHandler(): string
944
+ {
945
+ return "data";
946
+ }
947
+ }
948
+ ```
949
+
950
+ ---
951
+
896
952
  ### `class-naming-convention`
897
953
 
898
954
  **What it does:** Enforces that class declarations must end with "Class" suffix. This distinguishes class definitions from other PascalCase names like React components or type definitions.
@@ -3367,10 +3423,14 @@ const YetAnotherBad = ({ title }) => {
3367
3423
 
3368
3424
  ### `no-hardcoded-strings`
3369
3425
 
3370
- **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.
3426
+ **What it does:** Enforces that user-facing strings should be imported from constants/strings/data modules rather than hardcoded inline. This promotes maintainability, consistency, and enables easier internationalization.
3371
3427
 
3372
3428
  **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.
3373
3429
 
3430
+ **Special detection:**
3431
+ - **HTTP status codes** (4xx, 5xx like "404", "500") — should be imported from `@/data` as enums/objects
3432
+ - **Role/permission names** ("admin", "user", "moderator", etc.) — should be imported from `@/data` as enums/objects
3433
+
3374
3434
  **Options:**
3375
3435
 
3376
3436
  | Option | Type | Default | Description |
@@ -3387,8 +3447,9 @@ const YetAnotherBad = ({ title }) => {
3387
3447
  // ✅ Good — strings imported from constants
3388
3448
  import { BUTTON_LABEL, ERROR_MESSAGE, welcomeText } from "@/constants";
3389
3449
  import { FORM_LABELS } from "@/strings";
3450
+ import { HttpStatus, UserRole } from "@/data";
3390
3451
 
3391
- const Component = () => (
3452
+ const ComponentHandler = () => (
3392
3453
  <div>
3393
3454
  <button>{BUTTON_LABEL}</button>
3394
3455
  <span>{ERROR_MESSAGE}</span>
@@ -3396,7 +3457,11 @@ const Component = () => (
3396
3457
  </div>
3397
3458
  );
3398
3459
 
3399
- const getMessage = () => ERROR_MESSAGE;
3460
+ const getMessageHandler = () => ERROR_MESSAGE;
3461
+
3462
+ // ✅ Good — using enums for status codes and roles
3463
+ if (status === HttpStatus.NOT_FOUND) { ... }
3464
+ if (role === UserRole.ADMIN) { ... }
3400
3465
 
3401
3466
  // ✅ Good — technical strings are allowed
3402
3467
  <input type="text" className="input-field" />
@@ -3409,6 +3474,10 @@ const size = "100px";
3409
3474
  <span>Something went wrong</span>
3410
3475
  const message = "Welcome to the application";
3411
3476
  return "User not found";
3477
+
3478
+ // ❌ Bad — hardcoded status codes and roles
3479
+ if (status === "404") { ... }
3480
+ if (role === "admin") { ... }
3412
3481
  ```
3413
3482
 
3414
3483
  **Configuration example:**
@@ -3422,6 +3491,7 @@ return "User not found";
3422
3491
  ```
3423
3492
 
3424
3493
  **Valid import paths for constants:**
3494
+ - `@/data` (preferred for enums/objects like HttpStatus, UserRole)
3425
3495
  - `@/constants` or `@/@constants`
3426
3496
  - `@/strings` or `@/@strings`
3427
3497
  - `@/data/constants` or `@/data/strings`
@@ -3463,7 +3533,7 @@ const UseAuth = () => {}; // hooks should be camelCase
3463
3533
 
3464
3534
  ## 🔧 Auto-fixing
3465
3535
 
3466
- 63 of 70 rules support auto-fixing. Run ESLint with the `--fix` flag:
3536
+ 64 of 71 rules support auto-fixing. Run ESLint with the `--fix` flag:
3467
3537
 
3468
3538
  ```bash
3469
3539
  # Fix all files in src directory
package/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export type RuleNames =
13
13
  | "code-style/arrow-function-simplify"
14
14
  | "code-style/assignment-value-same-line"
15
15
  | "code-style/block-statement-newlines"
16
+ | "code-style/class-method-definition-format"
16
17
  | "code-style/class-naming-convention"
17
18
  | "code-style/comment-format"
18
19
  | "code-style/component-props-destructure"
@@ -105,6 +106,7 @@ interface PluginRules {
105
106
  "arrow-function-simplify": Rule.RuleModule;
106
107
  "assignment-value-same-line": Rule.RuleModule;
107
108
  "block-statement-newlines": Rule.RuleModule;
109
+ "class-method-definition-format": Rule.RuleModule;
108
110
  "class-naming-convention": Rule.RuleModule;
109
111
  "comment-format": Rule.RuleModule;
110
112
  "component-props-destructure": Rule.RuleModule;
package/index.js CHANGED
@@ -1850,31 +1850,80 @@ const functionCallSpacing = {
1850
1850
  create(context) {
1851
1851
  const sourceCode = context.sourceCode || context.getSourceCode();
1852
1852
 
1853
- return {
1854
- CallExpression(node) {
1855
- const { callee } = node;
1853
+ const checkCallSpacingHandler = (node, callee) => {
1854
+ // Get the last token of the callee (function name or member expression)
1855
+ const calleeLastToken = sourceCode.getLastToken(callee);
1856
1856
 
1857
- // Get the last token of the callee (function name or member expression)
1858
- const calleeLastToken = sourceCode.getLastToken(callee);
1857
+ // For calls with type arguments (generics), check space before <
1858
+ // e.g., axiosClient.get <Type>() should be axiosClient.get<Type>()
1859
+ if (node.typeArguments || node.typeParameters) {
1860
+ const typeArgs = node.typeArguments || node.typeParameters;
1861
+ const openAngle = sourceCode.getFirstToken(typeArgs);
1859
1862
 
1860
- // Get the opening parenthesis
1861
- const openParen = sourceCode.getTokenAfter(callee);
1863
+ if (openAngle && openAngle.value === "<") {
1864
+ const textBeforeAngle = sourceCode.text.slice(calleeLastToken.range[1], openAngle.range[0]);
1862
1865
 
1863
- if (!openParen || openParen.value !== "(") return;
1866
+ if (/\s/.test(textBeforeAngle)) {
1867
+ context.report({
1868
+ fix: (fixer) => fixer.replaceTextRange(
1869
+ [calleeLastToken.range[1], openAngle.range[0]],
1870
+ "",
1871
+ ),
1872
+ message: "No space between function name and generic type arguments",
1873
+ node: openAngle,
1874
+ });
1875
+ }
1876
+ }
1864
1877
 
1865
- // Check if there's space between callee and opening paren
1866
- const textBetween = sourceCode.text.slice(calleeLastToken.range[1], openParen.range[0]);
1878
+ // Also check space between closing > and opening (
1879
+ const closeAngle = sourceCode.getLastToken(typeArgs);
1880
+ const openParen = sourceCode.getTokenAfter(typeArgs);
1867
1881
 
1868
- if (textBetween.length > 0) {
1869
- context.report({
1870
- fix: (fixer) => fixer.replaceTextRange(
1871
- [calleeLastToken.range[1], openParen.range[0]],
1872
- "",
1873
- ),
1874
- message: "No space between function name and opening parenthesis",
1875
- node: openParen,
1876
- });
1882
+ if (openParen && openParen.value === "(") {
1883
+ const textBetween = sourceCode.text.slice(closeAngle.range[1], openParen.range[0]);
1884
+
1885
+ if (/\s/.test(textBetween)) {
1886
+ context.report({
1887
+ fix: (fixer) => fixer.replaceTextRange(
1888
+ [closeAngle.range[1], openParen.range[0]],
1889
+ "",
1890
+ ),
1891
+ message: "No space between generic type arguments and opening parenthesis",
1892
+ node: openParen,
1893
+ });
1894
+ }
1877
1895
  }
1896
+
1897
+ return;
1898
+ }
1899
+
1900
+ // Get the opening parenthesis
1901
+ const openParen = sourceCode.getTokenAfter(callee);
1902
+
1903
+ if (!openParen || openParen.value !== "(") return;
1904
+
1905
+ // Check if there's space between callee and opening paren
1906
+ const textBetween = sourceCode.text.slice(calleeLastToken.range[1], openParen.range[0]);
1907
+
1908
+ if (textBetween.length > 0) {
1909
+ context.report({
1910
+ fix: (fixer) => fixer.replaceTextRange(
1911
+ [calleeLastToken.range[1], openParen.range[0]],
1912
+ "",
1913
+ ),
1914
+ message: "No space between function name and opening parenthesis",
1915
+ node: openParen,
1916
+ });
1917
+ }
1918
+ };
1919
+
1920
+ return {
1921
+ CallExpression(node) {
1922
+ checkCallSpacingHandler(node, node.callee);
1923
+ },
1924
+
1925
+ NewExpression(node) {
1926
+ checkCallSpacingHandler(node, node.callee);
1878
1927
  },
1879
1928
  };
1880
1929
  },
@@ -5384,6 +5433,180 @@ const classNamingConvention = {
5384
5433
  },
5385
5434
  };
5386
5435
 
5436
+ /**
5437
+ * ───────────────────────────────────────────────────────────────
5438
+ * Rule: Class/Method Definition Format
5439
+ * ───────────────────────────────────────────────────────────────
5440
+ *
5441
+ * Description:
5442
+ * Enforce consistent spacing in class and method definitions:
5443
+ * - Space before opening brace { in class declarations
5444
+ * - No space between method name and opening parenthesis (
5445
+ * - Space before opening brace { in method definitions
5446
+ * - Opening brace must be on same line as method signature
5447
+ *
5448
+ * ✓ Good:
5449
+ * class ApiServiceClass {
5450
+ * getDataHandler(): string {
5451
+ * return "data";
5452
+ * }
5453
+ * async fetchUserHandler(id: string): Promise<User> {
5454
+ * return await fetch(id);
5455
+ * }
5456
+ * }
5457
+ *
5458
+ * ✗ Bad:
5459
+ * class ApiServiceClass{ // Missing space before {
5460
+ * class ApiServiceClass
5461
+ * { // Opening brace on different line
5462
+ * getDataHandler (): string { // Space before (
5463
+ * getDataHandler(): string{ // Missing space before {
5464
+ * getDataHandler(): string
5465
+ * { // Opening brace on different line
5466
+ */
5467
+ const classMethodDefinitionFormat = {
5468
+ create(context) {
5469
+ const sourceCode = context.sourceCode || context.getSourceCode();
5470
+
5471
+ return {
5472
+ ClassDeclaration(node) {
5473
+ const classBody = node.body;
5474
+
5475
+ if (!classBody) return;
5476
+
5477
+ // Find the opening brace of the class body
5478
+ const openBrace = sourceCode.getFirstToken(classBody);
5479
+
5480
+ if (!openBrace || openBrace.value !== "{") return;
5481
+
5482
+ // Get the token before the opening brace (class name or extends clause)
5483
+ const tokenBefore = sourceCode.getTokenBefore(openBrace);
5484
+
5485
+ if (!tokenBefore) return;
5486
+
5487
+ // Check if opening brace is on same line as class declaration
5488
+ if (tokenBefore.loc.end.line !== openBrace.loc.start.line) {
5489
+ context.report({
5490
+ fix: (fixer) => fixer.replaceTextRange(
5491
+ [tokenBefore.range[1], openBrace.range[0]],
5492
+ " ",
5493
+ ),
5494
+ message: "Opening brace should be on the same line as class declaration",
5495
+ node: openBrace,
5496
+ });
5497
+
5498
+ return;
5499
+ }
5500
+
5501
+ // Check for space before opening brace
5502
+ const textBetween = sourceCode.text.slice(tokenBefore.range[1], openBrace.range[0]);
5503
+
5504
+ if (textBetween !== " ") {
5505
+ context.report({
5506
+ fix: (fixer) => fixer.replaceTextRange(
5507
+ [tokenBefore.range[1], openBrace.range[0]],
5508
+ " ",
5509
+ ),
5510
+ message: "Expected single space before opening brace in class declaration",
5511
+ node: openBrace,
5512
+ });
5513
+ }
5514
+ },
5515
+
5516
+ MethodDefinition(node) {
5517
+ const methodKey = node.key;
5518
+ const methodValue = node.value;
5519
+
5520
+ if (!methodKey || !methodValue) return;
5521
+
5522
+ // Check for space between method name and opening parenthesis
5523
+ // For computed properties, we need to get the ] token
5524
+ const keyLastToken = node.computed
5525
+ ? sourceCode.getTokenAfter(methodKey, { filter: (t) => t.value === "]" })
5526
+ : sourceCode.getLastToken(methodKey);
5527
+
5528
+ if (!keyLastToken) return;
5529
+
5530
+ // Find the opening parenthesis of the parameters
5531
+ let openParen = sourceCode.getTokenAfter(keyLastToken);
5532
+
5533
+ // Skip over async, static, get, set keywords and * for generators
5534
+ while (openParen && openParen.value !== "(") {
5535
+ openParen = sourceCode.getTokenAfter(openParen);
5536
+ }
5537
+
5538
+ if (!openParen || openParen.value !== "(") return;
5539
+
5540
+ // Get the token immediately before the opening paren (method name or modifier)
5541
+ const tokenBeforeParen = sourceCode.getTokenBefore(openParen);
5542
+
5543
+ if (tokenBeforeParen) {
5544
+ const textBeforeParen = sourceCode.text.slice(tokenBeforeParen.range[1], openParen.range[0]);
5545
+
5546
+ if (/\s/.test(textBeforeParen)) {
5547
+ context.report({
5548
+ fix: (fixer) => fixer.replaceTextRange(
5549
+ [tokenBeforeParen.range[1], openParen.range[0]],
5550
+ "",
5551
+ ),
5552
+ message: "No space between method name and opening parenthesis",
5553
+ node: openParen,
5554
+ });
5555
+ }
5556
+ }
5557
+
5558
+ // Check for space before opening brace and brace on same line
5559
+ const functionBody = methodValue.body;
5560
+
5561
+ if (!functionBody || functionBody.type !== "BlockStatement") return;
5562
+
5563
+ const openBrace = sourceCode.getFirstToken(functionBody);
5564
+
5565
+ if (!openBrace || openBrace.value !== "{") return;
5566
+
5567
+ // Get the token before the opening brace (return type annotation or closing paren)
5568
+ const tokenBeforeBrace = sourceCode.getTokenBefore(openBrace);
5569
+
5570
+ if (!tokenBeforeBrace) return;
5571
+
5572
+ // Check if opening brace is on same line
5573
+ if (tokenBeforeBrace.loc.end.line !== openBrace.loc.start.line) {
5574
+ context.report({
5575
+ fix: (fixer) => fixer.replaceTextRange(
5576
+ [tokenBeforeBrace.range[1], openBrace.range[0]],
5577
+ " ",
5578
+ ),
5579
+ message: "Opening brace should be on the same line as method signature",
5580
+ node: openBrace,
5581
+ });
5582
+
5583
+ return;
5584
+ }
5585
+
5586
+ // Check for space before opening brace
5587
+ const textBeforeBrace = sourceCode.text.slice(tokenBeforeBrace.range[1], openBrace.range[0]);
5588
+
5589
+ if (textBeforeBrace !== " ") {
5590
+ context.report({
5591
+ fix: (fixer) => fixer.replaceTextRange(
5592
+ [tokenBeforeBrace.range[1], openBrace.range[0]],
5593
+ " ",
5594
+ ),
5595
+ message: "Expected single space before opening brace in method definition",
5596
+ node: openBrace,
5597
+ });
5598
+ }
5599
+ },
5600
+ };
5601
+ },
5602
+ meta: {
5603
+ docs: { description: "Enforce consistent spacing in class and method definitions" },
5604
+ fixable: "whitespace",
5605
+ schema: [],
5606
+ type: "layout",
5607
+ },
5608
+ };
5609
+
5387
5610
  /**
5388
5611
  * ───────────────────────────────────────────────────────────────
5389
5612
  * Rule: Enum Type Enforcement
@@ -9921,44 +10144,71 @@ const memberExpressionBracketSpacing = {
9921
10144
  create(context) {
9922
10145
  const sourceCode = context.sourceCode || context.getSourceCode();
9923
10146
 
9924
- return {
9925
- MemberExpression(node) {
9926
- // Only check computed member expressions (bracket notation)
9927
- if (!node.computed) return;
10147
+ const checkBracketSpacingHandler = (node, objectPart, indexPart) => {
10148
+ const openBracket = sourceCode.getTokenBefore(indexPart);
10149
+ const closeBracket = sourceCode.getTokenAfter(indexPart);
9928
10150
 
9929
- const openBracket = sourceCode.getTokenBefore(node.property);
9930
- const closeBracket = sourceCode.getTokenAfter(node.property);
10151
+ if (!openBracket || openBracket.value !== "[") return;
10152
+ if (!closeBracket || closeBracket.value !== "]") return;
9931
10153
 
9932
- if (!openBracket || openBracket.value !== "[") return;
9933
- if (!closeBracket || closeBracket.value !== "]") return;
10154
+ // Check for space before [ (between object and bracket)
10155
+ const objectLastToken = sourceCode.getLastToken(objectPart);
9934
10156
 
9935
- // Check for space after [
9936
- const textAfterOpen = sourceCode.text.slice(openBracket.range[1], node.property.range[0]);
10157
+ if (objectLastToken) {
10158
+ const textBeforeOpen = sourceCode.text.slice(objectLastToken.range[1], openBracket.range[0]);
9937
10159
 
9938
- if (textAfterOpen.includes(" ") || textAfterOpen.includes("\n")) {
10160
+ if (/\s/.test(textBeforeOpen)) {
9939
10161
  context.report({
9940
10162
  fix: (fixer) => fixer.replaceTextRange(
9941
- [openBracket.range[1], node.property.range[0]],
10163
+ [objectLastToken.range[1], openBracket.range[0]],
9942
10164
  "",
9943
10165
  ),
9944
- message: "No space after opening bracket in member expression",
10166
+ message: "No space before opening bracket in member expression",
9945
10167
  node: openBracket,
9946
10168
  });
9947
10169
  }
10170
+ }
9948
10171
 
9949
- // Check for space before ]
9950
- const textBeforeClose = sourceCode.text.slice(node.property.range[1], closeBracket.range[0]);
10172
+ // Check for space after [
10173
+ const textAfterOpen = sourceCode.text.slice(openBracket.range[1], indexPart.range[0]);
9951
10174
 
9952
- if (textBeforeClose.includes(" ") || textBeforeClose.includes("\n")) {
9953
- context.report({
9954
- fix: (fixer) => fixer.replaceTextRange(
9955
- [node.property.range[1], closeBracket.range[0]],
9956
- "",
9957
- ),
9958
- message: "No space before closing bracket in member expression",
9959
- node: closeBracket,
9960
- });
9961
- }
10175
+ if (textAfterOpen.includes(" ") || textAfterOpen.includes("\n")) {
10176
+ context.report({
10177
+ fix: (fixer) => fixer.replaceTextRange(
10178
+ [openBracket.range[1], indexPart.range[0]],
10179
+ "",
10180
+ ),
10181
+ message: "No space after opening bracket in member expression",
10182
+ node: openBracket,
10183
+ });
10184
+ }
10185
+
10186
+ // Check for space before ]
10187
+ const textBeforeClose = sourceCode.text.slice(indexPart.range[1], closeBracket.range[0]);
10188
+
10189
+ if (textBeforeClose.includes(" ") || textBeforeClose.includes("\n")) {
10190
+ context.report({
10191
+ fix: (fixer) => fixer.replaceTextRange(
10192
+ [indexPart.range[1], closeBracket.range[0]],
10193
+ "",
10194
+ ),
10195
+ message: "No space before closing bracket in member expression",
10196
+ node: closeBracket,
10197
+ });
10198
+ }
10199
+ };
10200
+
10201
+ return {
10202
+ MemberExpression(node) {
10203
+ // Only check computed member expressions (bracket notation)
10204
+ if (!node.computed) return;
10205
+
10206
+ checkBracketSpacingHandler(node, node.object, node.property);
10207
+ },
10208
+
10209
+ // Handle TypeScript indexed access types: Type["prop"]
10210
+ TSIndexedAccessType(node) {
10211
+ checkBracketSpacingHandler(node, node.objectType, node.indexType);
9962
10212
  },
9963
10213
  };
9964
10214
  },
@@ -13572,10 +13822,21 @@ const stringPropertySpacing = {
13572
13822
  *
13573
13823
  * Description:
13574
13824
  * Enforces that user-facing strings should be imported from
13575
- * constants/strings modules rather than hardcoded inline.
13825
+ * constants/strings/data modules rather than hardcoded inline.
13576
13826
  * This promotes maintainability, consistency, and enables
13577
13827
  * easier internationalization.
13578
13828
  *
13829
+ * The rule also detects:
13830
+ * - HTTP status codes (4xx, 5xx) that should be imported from @/data or enums
13831
+ * - Role/permission names (admin, user, moderator, etc.) that should be from @/data
13832
+ *
13833
+ * Valid import sources:
13834
+ * - @/data (enums, objects)
13835
+ * - @/strings
13836
+ * - @/constants
13837
+ * - @/@strings
13838
+ * - @/@constants
13839
+ *
13579
13840
  * Options:
13580
13841
  * { ignoreAttributes: ["className", "id", ...] } - JSX attributes to ignore (replaces defaults)
13581
13842
  * { extraIgnoreAttributes: ["tooltip", ...] } - Additional JSX attributes to ignore (extends defaults)
@@ -13584,16 +13845,21 @@ const stringPropertySpacing = {
13584
13845
  * ✓ Good:
13585
13846
  * import { BUTTON_LABEL, ERROR_MESSAGE } from "@/constants";
13586
13847
  * import { welcomeText } from "@/strings";
13848
+ * import { HttpStatus, UserRole } from "@/data";
13587
13849
  *
13588
13850
  * <button>{BUTTON_LABEL}</button>
13589
13851
  * <span>{ERROR_MESSAGE}</span>
13590
13852
  * const message = welcomeText;
13853
+ * if (status === HttpStatus.NOT_FOUND) { ... }
13854
+ * if (role === UserRole.ADMIN) { ... }
13591
13855
  *
13592
13856
  * ✗ Bad:
13593
13857
  * <button>Submit</button>
13594
13858
  * <span>Something went wrong</span>
13595
13859
  * const message = "Welcome to the app";
13596
13860
  * return "User not found";
13861
+ * if (status === "404") { ... } // HTTP status code
13862
+ * if (role === "admin") { ... } // Role name
13597
13863
  */
13598
13864
  const noHardcodedStrings = {
13599
13865
  create(context) {
@@ -13816,16 +14082,68 @@ const noHardcodedStrings = {
13816
14082
 
13817
14083
  const allIgnorePatterns = [...technicalPatterns, ...extraIgnorePatterns];
13818
14084
 
13819
- // Check if a string matches any ignore pattern
13820
- const shouldIgnoreStringHandler = (str) => allIgnorePatterns.some((pattern) => pattern.test(str));
14085
+ // HTTP status codes that should NOT be hardcoded (4xx and 5xx error codes)
14086
+ const httpStatusCodePattern = /^[45]\d{2}$/;
14087
+
14088
+ // Common role/permission names that should be imported from data/enums
14089
+ const rolePermissionNames = new Set([
14090
+ "admin",
14091
+ "administrator",
14092
+ "editor",
14093
+ "guest",
14094
+ "manager",
14095
+ "member",
14096
+ "moderator",
14097
+ "operator",
14098
+ "owner",
14099
+ "reviewer",
14100
+ "subscriber",
14101
+ "superadmin",
14102
+ "supervisor",
14103
+ "user",
14104
+ "viewer",
14105
+ ]);
14106
+
14107
+ // Check if string looks like an HTTP status code
14108
+ const isHttpStatusCodeHandler = (str) => httpStatusCodePattern.test(str);
14109
+
14110
+ // Check if string is a role/permission name
14111
+ const isRoleNameHandler = (str) => rolePermissionNames.has(str.toLowerCase());
14112
+
14113
+ // Check if string should be flagged even if it matches technical patterns
14114
+ const isFlaggedSpecialStringHandler = (str) => isHttpStatusCodeHandler(str) || isRoleNameHandler(str);
14115
+
14116
+ // Get descriptive error message based on string type
14117
+ const getErrorMessageHandler = (str, context = "") => {
14118
+ const truncatedStr = str.length > 30 ? `${str.substring(0, 30)}...` : str;
14119
+ const contextPart = context ? ` in ${context}` : "";
14120
+
14121
+ if (isHttpStatusCodeHandler(str)) {
14122
+ return `Hardcoded HTTP status code "${truncatedStr}"${contextPart} should be imported from @/data (enum/object) or @/constants`;
14123
+ }
14124
+
14125
+ if (isRoleNameHandler(str)) {
14126
+ return `Hardcoded role/permission "${truncatedStr}"${contextPart} should be imported from @/data (enum/object) or @/constants`;
14127
+ }
14128
+
14129
+ return `Hardcoded string "${truncatedStr}"${contextPart} should be imported from @/data, @/strings, @/constants, or constants module`;
14130
+ };
14131
+
14132
+ // Check if a string matches any ignore pattern (but not if it's a flagged special string)
14133
+ const shouldIgnoreStringHandler = (str) => {
14134
+ // Always flag HTTP status codes and role names
14135
+ if (isFlaggedSpecialStringHandler(str)) return false;
14136
+
14137
+ return allIgnorePatterns.some((pattern) => pattern.test(str));
14138
+ };
13821
14139
 
13822
- // Check if we're inside a constants/strings file
14140
+ // Check if we're inside a constants/strings/data file
13823
14141
  const isConstantsFileHandler = () => {
13824
14142
  const filename = context.filename || context.getFilename();
13825
14143
  const normalizedPath = filename.replace(/\\/g, "/").toLowerCase();
13826
14144
 
13827
- // Check if file is in constants/strings folders
13828
- return /\/(constants|strings|@constants|@strings)(\/|\.)/i.test(normalizedPath)
14145
+ // Check if file is in constants/strings/data folders
14146
+ return /\/(constants|strings|@constants|@strings|data|@data)(\/|\.)/i.test(normalizedPath)
13829
14147
  || /\/data\/(constants|strings)/i.test(normalizedPath);
13830
14148
  };
13831
14149
 
@@ -13838,8 +14156,8 @@ const noHardcodedStrings = {
13838
14156
 
13839
14157
  if (typeof importPath !== "string") return;
13840
14158
 
13841
- // Check if import is from constants/strings
13842
- const isFromConstants = /@?\/?(@?constants|@?strings|data\/constants|data\/strings)/i
14159
+ // Check if import is from constants/strings/data
14160
+ const isFromConstants = /@?\/?(@?constants|@?strings|@?data|data\/constants|data\/strings)/i
13843
14161
  .test(importPath);
13844
14162
 
13845
14163
  if (isFromConstants) {
@@ -13931,9 +14249,16 @@ const noHardcodedStrings = {
13931
14249
  if (current.type === "VariableDeclarator") {
13932
14250
  const varName = current.id && current.id.name;
13933
14251
 
13934
- // Check if variable name suggests it's a constants object
13935
- if (varName && /^[A-Z][A-Z0-9_]*$|CONSTANTS?|STRINGS?|MESSAGES?|LABELS?|TEXTS?/i.test(varName)) {
13936
- return true;
14252
+ if (varName) {
14253
+ // Check for SCREAMING_SNAKE_CASE (e.g., MY_CONSTANT, API_URL)
14254
+ if (/^[A-Z][A-Z0-9_]*$/.test(varName)) {
14255
+ return true;
14256
+ }
14257
+
14258
+ // Check for keywords that suggest constants (case-insensitive)
14259
+ if (/CONSTANTS?|STRINGS?|MESSAGES?|LABELS?|TEXTS?|DATA$/i.test(varName)) {
14260
+ return true;
14261
+ }
13937
14262
  }
13938
14263
  }
13939
14264
 
@@ -13960,13 +14285,18 @@ const noHardcodedStrings = {
13960
14285
  JSXText(node) {
13961
14286
  const text = node.value.trim();
13962
14287
 
13963
- if (!text || shouldIgnoreStringHandler(text)) return;
14288
+ if (!text) return;
14289
+
14290
+ // Check if it's a flagged special string (status code, role name)
14291
+ const isSpecialString = isFlaggedSpecialStringHandler(text);
14292
+
14293
+ if (!isSpecialString && shouldIgnoreStringHandler(text)) return;
13964
14294
 
13965
- // Check if it looks like user-facing text (contains letters and spaces)
13966
- if (!/[a-zA-Z]/.test(text)) return;
14295
+ // Check if it looks like user-facing text (contains letters) - skip for special strings
14296
+ if (!isSpecialString && !/[a-zA-Z]/.test(text)) return;
13967
14297
 
13968
14298
  context.report({
13969
- message: `Hardcoded string "${text.substring(0, 30)}${text.length > 30 ? "..." : ""}" should be imported from constants/strings module`,
14299
+ message: getErrorMessageHandler(text, "JSX"),
13970
14300
  node,
13971
14301
  });
13972
14302
  },
@@ -13982,13 +14312,16 @@ const noHardcodedStrings = {
13982
14312
  if (expression.type === "Literal" && typeof expression.value === "string") {
13983
14313
  const str = expression.value;
13984
14314
 
13985
- if (shouldIgnoreStringHandler(str)) return;
14315
+ // Check if it's a flagged special string (status code, role name)
14316
+ const isSpecialString = isFlaggedSpecialStringHandler(str);
13986
14317
 
13987
- // Check if it looks like user-facing text
13988
- if (!/[a-zA-Z]/.test(str)) return;
14318
+ if (!isSpecialString && shouldIgnoreStringHandler(str)) return;
14319
+
14320
+ // Check if it looks like user-facing text - skip for special strings
14321
+ if (!isSpecialString && !/[a-zA-Z]/.test(str)) return;
13989
14322
 
13990
14323
  context.report({
13991
- message: `Hardcoded string "${str.substring(0, 30)}${str.length > 30 ? "..." : ""}" should be imported from constants/strings module`,
14324
+ message: getErrorMessageHandler(str, "JSX expression"),
13992
14325
  node: expression,
13993
14326
  });
13994
14327
  }
@@ -13998,16 +14331,19 @@ const noHardcodedStrings = {
13998
14331
  expression.quasis.forEach((quasi) => {
13999
14332
  const str = quasi.value.cooked || quasi.value.raw;
14000
14333
 
14001
- if (shouldIgnoreStringHandler(str)) return;
14334
+ // Check if it's a flagged special string (status code, role name)
14335
+ const isSpecialString = isFlaggedSpecialStringHandler(str);
14336
+
14337
+ if (!isSpecialString && shouldIgnoreStringHandler(str)) return;
14002
14338
 
14003
- // Check if it contains user-facing text (more than just variable placeholders)
14004
- if (!/[a-zA-Z]{2,}/.test(str)) return;
14339
+ // Check if it contains user-facing text - skip for special strings
14340
+ if (!isSpecialString && !/[a-zA-Z]{2,}/.test(str)) return;
14005
14341
 
14006
14342
  // Skip if it looks like a path or URL pattern
14007
14343
  if (/^[/.]|https?:\/\//.test(str)) return;
14008
14344
 
14009
14345
  context.report({
14010
- message: `Hardcoded string in template literal "${str.substring(0, 30)}${str.length > 30 ? "..." : ""}" should be imported from constants/strings module`,
14346
+ message: getErrorMessageHandler(str, "template literal"),
14011
14347
  node: quasi,
14012
14348
  });
14013
14349
  });
@@ -14034,15 +14370,19 @@ const noHardcodedStrings = {
14034
14370
  if (node.value.type === "Literal" && typeof node.value.value === "string") {
14035
14371
  const str = node.value.value;
14036
14372
 
14037
- if (shouldIgnoreStringHandler(str)) return;
14373
+ // Check if it's a flagged special string (status code, role name)
14374
+ const isSpecialString = isFlaggedSpecialStringHandler(str);
14375
+
14376
+ if (!isSpecialString && shouldIgnoreStringHandler(str)) return;
14038
14377
 
14039
- // Check if it looks like user-facing text (contains letters and multiple words or is long)
14040
- if (!/[a-zA-Z]/.test(str)) return;
14378
+ // Check if it looks like user-facing text - skip for special strings
14379
+ if (!isSpecialString && !/[a-zA-Z]/.test(str)) return;
14041
14380
 
14042
- if (str.split(/\s+/).length < 2 && str.length < 10) return;
14381
+ // Require multiple words or reasonable length for non-special strings
14382
+ if (!isSpecialString && str.split(/\s+/).length < 2 && str.length < 10) return;
14043
14383
 
14044
14384
  context.report({
14045
- message: `Hardcoded string "${str.substring(0, 30)}${str.length > 30 ? "..." : ""}" in attribute "${attrName}" should be imported from constants/strings module`,
14385
+ message: getErrorMessageHandler(str, `attribute "${attrName}"`),
14046
14386
  node: node.value,
14047
14387
  });
14048
14388
  }
@@ -14057,14 +14397,18 @@ const noHardcodedStrings = {
14057
14397
  if (expression.type === "Literal" && typeof expression.value === "string") {
14058
14398
  const str = expression.value;
14059
14399
 
14060
- if (shouldIgnoreStringHandler(str)) return;
14400
+ // Check if it's a flagged special string (status code, role name)
14401
+ const isSpecialString = isFlaggedSpecialStringHandler(str);
14061
14402
 
14062
- if (!/[a-zA-Z]/.test(str)) return;
14403
+ if (!isSpecialString && shouldIgnoreStringHandler(str)) return;
14063
14404
 
14064
- if (str.split(/\s+/).length < 2 && str.length < 10) return;
14405
+ if (!isSpecialString && !/[a-zA-Z]/.test(str)) return;
14406
+
14407
+ // Require multiple words or reasonable length for non-special strings
14408
+ if (!isSpecialString && str.split(/\s+/).length < 2 && str.length < 10) return;
14065
14409
 
14066
14410
  context.report({
14067
- message: `Hardcoded string "${str.substring(0, 30)}${str.length > 30 ? "..." : ""}" in attribute "${attrName}" should be imported from constants/strings module`,
14411
+ message: getErrorMessageHandler(str, `attribute "${attrName}"`),
14068
14412
  node: expression,
14069
14413
  });
14070
14414
  }
@@ -14078,8 +14422,11 @@ const noHardcodedStrings = {
14078
14422
 
14079
14423
  const str = node.value;
14080
14424
 
14081
- // Skip if it matches ignore patterns
14082
- if (shouldIgnoreStringHandler(str)) return;
14425
+ // Check if it's a flagged special string (status code, role name)
14426
+ const isSpecialString = isFlaggedSpecialStringHandler(str);
14427
+
14428
+ // Skip if it matches ignore patterns (but not special strings)
14429
+ if (!isSpecialString && shouldIgnoreStringHandler(str)) return;
14083
14430
 
14084
14431
  // Skip if not in relevant context
14085
14432
  if (!isInRelevantContextHandler(node)) return;
@@ -14096,14 +14443,14 @@ const noHardcodedStrings = {
14096
14443
  // Skip object property keys
14097
14444
  if (node.parent.type === "Property" && node.parent.key === node) return;
14098
14445
 
14099
- // Skip if it doesn't look like user-facing text
14100
- if (!/[a-zA-Z]/.test(str)) return;
14446
+ // Skip if it doesn't look like user-facing text - but not for special strings
14447
+ if (!isSpecialString && !/[a-zA-Z]/.test(str)) return;
14101
14448
 
14102
- // Require at least 2 words or be reasonably long to be considered user-facing
14103
- if (str.split(/\s+/).length < 2 && str.length < 15) return;
14449
+ // Require at least 2 words or be reasonably long - but not for special strings
14450
+ if (!isSpecialString && str.split(/\s+/).length < 2 && str.length < 15) return;
14104
14451
 
14105
14452
  context.report({
14106
- message: `Hardcoded string "${str.substring(0, 30)}${str.length > 30 ? "..." : ""}" should be imported from constants/strings module`,
14453
+ message: getErrorMessageHandler(str),
14107
14454
  node,
14108
14455
  });
14109
14456
  },
@@ -14123,10 +14470,13 @@ const noHardcodedStrings = {
14123
14470
  node.quasis.forEach((quasi) => {
14124
14471
  const str = quasi.value.cooked || quasi.value.raw;
14125
14472
 
14126
- if (shouldIgnoreStringHandler(str)) return;
14473
+ // Check if it's a flagged special string (status code, role name)
14474
+ const isSpecialString = isFlaggedSpecialStringHandler(str);
14475
+
14476
+ if (!isSpecialString && shouldIgnoreStringHandler(str)) return;
14127
14477
 
14128
- // Check if it contains substantial user-facing text
14129
- if (!/[a-zA-Z]{3,}/.test(str)) return;
14478
+ // Check if it contains substantial user-facing text - but not for special strings
14479
+ if (!isSpecialString && !/[a-zA-Z]{3,}/.test(str)) return;
14130
14480
 
14131
14481
  // Skip if it looks like a path, URL, or query
14132
14482
  if (/^[/.]|^https?:\/\/|^[?&]/.test(str)) return;
@@ -14135,7 +14485,7 @@ const noHardcodedStrings = {
14135
14485
  if (node.expressions.length > node.quasis.length) return;
14136
14486
 
14137
14487
  context.report({
14138
- message: `Hardcoded string in template literal "${str.substring(0, 30)}${str.length > 30 ? "..." : ""}" should be imported from constants/strings module`,
14488
+ message: getErrorMessageHandler(str, "template literal"),
14139
14489
  node: quasi,
14140
14490
  });
14141
14491
  });
@@ -19291,6 +19641,7 @@ export default {
19291
19641
  "ternary-condition-multiline": ternaryConditionMultiline,
19292
19642
 
19293
19643
  // Class rules
19644
+ "class-method-definition-format": classMethodDefinitionFormat,
19294
19645
  "class-naming-convention": classNamingConvention,
19295
19646
 
19296
19647
  // Function rules
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-code-style",
3
- "version": "1.8.3",
3
+ "version": "1.9.1",
4
4
  "description": "A custom ESLint plugin for enforcing consistent code formatting and style rules in React/JSX projects",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",