eslint-plugin-code-style 2.0.0 → 2.0.2

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.
@@ -1,482 +0,0 @@
1
- # TypeScript Rules
2
-
3
- ### `enum-format`
4
-
5
- **What it does:** Enforces consistent formatting for TypeScript enums:
6
- - Enum names must be PascalCase and end with `Enum` suffix
7
- - Enum members must be UPPER_CASE (for string enums) or PascalCase (for numeric enums)
8
- - No empty lines between enum members
9
- - Members must end with commas, not semicolons
10
-
11
- **Why use it:** Consistent enum naming makes enums instantly recognizable. UPPER_CASE members follow common conventions for constants.
12
-
13
- ```typescript
14
- // Good — proper enum format
15
- export enum StatusEnum {
16
- ACTIVE = "active",
17
- INACTIVE = "inactive",
18
- PENDING = "pending",
19
- }
20
-
21
- export enum HttpMethodEnum {
22
- DELETE = "DELETE",
23
- GET = "GET",
24
- POST = "POST",
25
- PUT = "PUT",
26
- }
27
-
28
- // Bad — wrong naming
29
- export enum Status { // Missing Enum suffix
30
- active = "active", // Should be UPPER_CASE
31
- inactive = "inactive"; // Should use comma, not semicolon
32
- }
33
-
34
- // Bad — empty lines between members
35
- export enum UserStatusEnum {
36
- ACTIVE = "active",
37
-
38
- INACTIVE = "inactive",
39
- }
40
- ```
41
-
42
- ---
43
-
44
- ### `enum-type-enforcement`
45
-
46
- **What it does:** When a variable or parameter has a type ending in `Type` (like `ButtonVariantType`), enforces using the corresponding enum (`ButtonVariantEnum.VALUE`) instead of string literals.
47
-
48
- **Why use it:** Using enum values instead of string literals provides type safety, autocompletion, and prevents typos. Changes to enum values automatically propagate.
49
-
50
- ```javascript
51
- // Good — using enum values
52
- const Button = ({
53
- variant = ButtonVariantEnum.PRIMARY,
54
- }: {
55
- variant?: ButtonVariantType,
56
- }) => { ... };
57
-
58
- if (variant === ButtonVariantEnum.GHOST) {
59
- // ...
60
- }
61
-
62
- // Bad — using string literals
63
- const Button = ({
64
- variant = "primary", // Should use ButtonVariantEnum.PRIMARY
65
- }: {
66
- variant?: ButtonVariantType,
67
- }) => { ... };
68
-
69
- if (variant === "ghost") { // Should use ButtonVariantEnum.GHOST
70
- // ...
71
- }
72
- ```
73
-
74
- ---
75
-
76
- ### `interface-format`
77
-
78
- **What it does:** Enforces consistent formatting for TypeScript interfaces:
79
- - Interface names must be PascalCase and end with `Interface` suffix
80
- - Properties must be camelCase
81
- - No empty lines between properties
82
- - Properties must end with commas, not semicolons
83
-
84
- **Why use it:** Consistent interface naming makes interfaces instantly recognizable. The suffix clearly distinguishes interfaces from types and classes.
85
-
86
- ```typescript
87
- // Good — proper interface format
88
- export interface UserInterface {
89
- email: string,
90
- id: string,
91
- isActive: boolean,
92
- name: string,
93
- }
94
-
95
- export interface ApiResponseInterface<T> {
96
- data: T,
97
- error: string | null,
98
- status: number,
99
- success: boolean,
100
- }
101
-
102
- // Bad — wrong naming
103
- export interface User { // Missing Interface suffix
104
- Email: string; // Should be camelCase
105
- ID: string; // Should be camelCase
106
- is_active: boolean; // Should be camelCase, use comma
107
- }
108
-
109
- // Bad — semicolons and empty lines
110
- export interface UserInterface {
111
- email: string; // Should use comma
112
-
113
- name: string; // Empty line not allowed
114
- }
115
- ```
116
-
117
- ---
118
-
119
- ### `no-inline-type-definitions`
120
-
121
- **What it does:** Reports when function parameters have inline union types that are too complex (too many members or too long). These should be extracted to a named type in a types file.
122
-
123
- **Why use it:** Complex inline types make function signatures hard to read. Named types are reusable, self-documenting, and easier to maintain.
124
-
125
- **Options:**
126
-
127
- | Option | Type | Default | Description |
128
- |--------|------|---------|-------------|
129
- | `maxUnionMembers` | `integer` | `2` | Maximum union members before requiring extraction |
130
- | `maxLength` | `integer` | `50` | Maximum character length before requiring extraction |
131
-
132
- ```javascript
133
- // Good — type extracted to separate file
134
- // types.ts
135
- export type ButtonVariantType = "primary" | "muted" | "danger";
136
-
137
- // Button.tsx
138
- import { ButtonVariantType } from "./types";
139
- export const Button = ({
140
- variant,
141
- }: {
142
- variant?: ButtonVariantType,
143
- }) => { ... };
144
-
145
- // Bad — complex inline union type
146
- export const Button = ({
147
- variant,
148
- }: {
149
- variant?: "primary" | "muted" | "danger", // Extract to named type
150
- }) => { ... };
151
- ```
152
-
153
- ---
154
-
155
- ### `prop-naming-convention`
156
-
157
- **What it does:** Enforces naming conventions for boolean and callback props in TypeScript interfaces, types, and inline type definitions:
158
- - Boolean props must start with: `is`, `has`, `with`, or `without` (followed by capital letter)
159
- - Callback props must start with: `on` (followed by capital letter)
160
- - Detects React event handler types: `MouseEventHandler`, `ChangeEventHandler`, `FormEventHandler`, `KeyboardEventHandler`, etc.
161
- - Applies to all nesting levels (nested object types are checked recursively)
162
- - Does NOT apply to JSX element attributes (external components have their own props)
163
-
164
- **Why use it:** Consistent prop naming makes props self-documenting. Boolean prefixes clarify intent (`isLoading` vs `loading`), and `on` prefix clearly identifies event handlers.
165
-
166
- **Options:**
167
-
168
- | Option | Type | Default | Description |
169
- |--------|------|---------|-------------|
170
- | `booleanPrefixes` | `string[]` | - | Replace default prefixes entirely (overrides defaults) |
171
- | `extendBooleanPrefixes` | `string[]` | `[]` | Add to default prefixes (`is`, `has`, `with`, `without`) |
172
- | `allowPastVerbBoolean` | `boolean` | `false` | Allow past verb booleans (e.g., `disabled`, `selected`, `checked`, `opened`) |
173
- | `allowContinuousVerbBoolean` | `boolean` | `false` | Allow continuous verb booleans (e.g., `loading`, `saving`, `fetching`) |
174
- | `callbackPrefix` | `string` | `"on"` | Required prefix for callback props |
175
- | `allowActionSuffix` | `boolean` | `false` | Allow `xxxAction` pattern for callbacks |
176
-
177
- ```typescript
178
- // Good — proper prop naming
179
- interface ButtonPropsInterface {
180
- isDisabled: boolean,
181
- isLoading: boolean,
182
- hasError: boolean,
183
- onClick: () => void,
184
- onSubmit: (data: FormData) => void,
185
- }
186
-
187
- type CardPropsType = {
188
- isExpanded: boolean,
189
- hasChildren: boolean,
190
- onToggle: () => void,
191
- };
192
-
193
- // Good — nested types are also checked
194
- interface FormPropsInterface {
195
- isValid: boolean,
196
- config: {
197
- isEnabled: boolean, // Nested - checked
198
- onValidate: () => void, // Nested - checked
199
- settings: {
200
- isActive: boolean, // Deep nested - also checked
201
- },
202
- },
203
- }
204
-
205
- // Good — inline component props
206
- const Button = ({
207
- isLoading,
208
- onClick,
209
- }: {
210
- isLoading: boolean,
211
- onClick: () => void,
212
- }) => { ... };
213
-
214
- // Bad — missing prefixes
215
- interface ButtonPropsInterface {
216
- disabled: boolean, // Should be isDisabled
217
- loading: boolean, // Should be isLoading
218
- error: boolean, // Should be hasError
219
- click: () => void, // Should be onClick
220
- handleSubmit: () => void, // Should be onSubmit
221
- }
222
-
223
- // Bad — nested types also checked
224
- type PropsType = {
225
- config: {
226
- enabled: boolean, // Should be isEnabled
227
- toggle: () => void, // Should be onToggle
228
- },
229
- };
230
- ```
231
-
232
- **Past Verb Booleans** (`allowPastVerbBoolean: true`):
233
-
234
- When enabled, allows boolean props that are past tense verbs (ending in `-ed`):
235
-
236
- ```typescript
237
- // Allowed with allowPastVerbBoolean: true
238
- interface PropsInterface {
239
- disabled: boolean, // Past verb - ends with -ed
240
- selected: boolean, // Past verb - ends with -ed
241
- checked: boolean, // Past verb - ends with -ed
242
- opened: boolean, // Past verb - ends with -ed
243
- closed: boolean, // Past verb - ends with -ed
244
- expanded: boolean, // Past verb - ends with -ed
245
- collapsed: boolean, // Past verb - ends with -ed
246
- focused: boolean, // Past verb - ends with -ed
247
- hidden: boolean, // Past verb - ends with -ed
248
- connected: boolean, // Past verb - ends with -ed
249
- }
250
- ```
251
-
252
- **Continuous Verb Booleans** (`allowContinuousVerbBoolean: true`):
253
-
254
- When enabled, allows boolean props that are continuous tense verbs (ending in `-ing`):
255
-
256
- ```typescript
257
- // Allowed with allowContinuousVerbBoolean: true
258
- interface PropsInterface {
259
- loading: boolean, // Continuous verb - ends with -ing
260
- saving: boolean, // Continuous verb - ends with -ing
261
- fetching: boolean, // Continuous verb - ends with -ing
262
- closing: boolean, // Continuous verb - ends with -ing
263
- opening: boolean, // Continuous verb - ends with -ing
264
- submitting: boolean, // Continuous verb - ends with -ing
265
- processing: boolean, // Continuous verb - ends with -ing
266
- updating: boolean, // Continuous verb - ends with -ing
267
- deleting: boolean, // Continuous verb - ends with -ing
268
- pending: boolean, // Continuous verb - ends with -ing
269
- }
270
- ```
271
-
272
- **Configuration Examples:**
273
-
274
- ```javascript
275
- // Default configuration (strict)
276
- "code-style/prop-naming-convention": "error"
277
-
278
- // Allow past verb booleans (disabled, selected, checked, etc.)
279
- "code-style/prop-naming-convention": ["error", {
280
- allowPastVerbBoolean: true,
281
- }]
282
-
283
- // Allow continuous verb booleans (loading, saving, fetching, etc.)
284
- "code-style/prop-naming-convention": ["error", {
285
- allowContinuousVerbBoolean: true,
286
- }]
287
-
288
- // Allow both past and continuous verb booleans
289
- "code-style/prop-naming-convention": ["error", {
290
- allowPastVerbBoolean: true,
291
- allowContinuousVerbBoolean: true,
292
- }]
293
-
294
- // Extend default prefixes with additional ones
295
- "code-style/prop-naming-convention": ["error", {
296
- extendBooleanPrefixes: ["should", "can", "will", "did"],
297
- }]
298
-
299
- // Replace default prefixes entirely
300
- "code-style/prop-naming-convention": ["error", {
301
- booleanPrefixes: ["is", "has"], // Only these prefixes allowed
302
- }]
303
-
304
- // Allow "xxxAction" suffix for callbacks
305
- "code-style/prop-naming-convention": ["error", {
306
- allowActionSuffix: true, // Allows: submitAction, copyAction, deleteAction
307
- }]
308
-
309
- // Full custom configuration
310
- "code-style/prop-naming-convention": ["error", {
311
- extendBooleanPrefixes: ["should", "can"],
312
- allowPastVerbBoolean: true,
313
- allowContinuousVerbBoolean: true,
314
- callbackPrefix: "on",
315
- allowActionSuffix: true,
316
- }]
317
- ```
318
-
319
- ---
320
-
321
- ### `type-format`
322
-
323
- **What it does:** Enforces consistent formatting for TypeScript type aliases:
324
- - Type names must be PascalCase and end with `Type` suffix
325
- - Properties must be camelCase
326
- - No empty lines between properties
327
- - Properties must end with commas, not semicolons
328
- - Union types with 5+ members must be multiline (one per line)
329
- - Union types with <5 members must be single line
330
-
331
- **Why use it:** Consistent type naming makes types instantly recognizable. The suffix clearly distinguishes types from interfaces and classes.
332
-
333
- ```typescript
334
- // Good — proper type format
335
- export type UserType = {
336
- email: string,
337
- id: string,
338
- name: string,
339
- };
340
-
341
- export type ApiResponseType<T> = {
342
- data: T,
343
- error: string | null,
344
- status: number,
345
- };
346
-
347
- // Good — union type with 6 members (multiline)
348
- export type ButtonVariantType =
349
- "danger"
350
- | "ghost"
351
- | "ghost-danger"
352
- | "link"
353
- | "muted"
354
- | "primary";
355
-
356
- // Good — union type with 2 members (single line)
357
- export type CodeLayoutVariantType = "default" | "error";
358
-
359
- // Bad — 6 members should be multiline
360
- export type BadUnionType = "a" | "b" | "c" | "d" | "e" | "f";
361
-
362
- // Bad — 2 members should be single line
363
- export type BadSingleType =
364
- "default"
365
- | "error";
366
-
367
- // Bad — wrong naming
368
- export type User = { // Missing Type suffix
369
- Email: string; // Should be camelCase
370
- ID: string; // Should use comma
371
- };
372
-
373
- // Bad — empty lines
374
- export type ConfigType = {
375
- debug: boolean,
376
-
377
- port: number, // Empty line not allowed
378
- };
379
- ```
380
-
381
- **Options:**
382
-
383
- | Option | Type | Default | Description |
384
- |--------|------|---------|-------------|
385
- | `minUnionMembersForMultiline` | `integer` | `5` | Minimum number of union members to require multiline format |
386
-
387
- ```javascript
388
- // Configuration example - require multiline for 4+ union members
389
- "code-style/type-format": ["error", { minUnionMembersForMultiline: 4 }]
390
- ```
391
-
392
- ---
393
-
394
- ### `type-annotation-spacing`
395
-
396
- **What it does:** Enforces consistent spacing in TypeScript type annotations:
397
- - No space before the colon in type annotations: `name: string` not `name : string`
398
- - One space after the colon: `name: string` not `name:string`
399
- - No space before generic type parameters: `Array<T>` not `Array <T>`
400
- - No space before array brackets: `string[]` not `string []`
401
-
402
- **Why use it:** Consistent type annotation spacing follows TypeScript conventions and improves code readability.
403
-
404
- ```typescript
405
- // Good — proper spacing
406
- const name: string = "John";
407
- const items: string[] = [];
408
- const data: Array<number> = [];
409
- const handler = (value: string): boolean => true;
410
-
411
- function getData<T>(id: string): Promise<T> {
412
- return fetch(id);
413
- }
414
-
415
- // Bad — space before colon
416
- const name : string = "John";
417
- const handler = (value : string) : boolean => true;
418
-
419
- // Bad — no space after colon
420
- const name:string = "John";
421
- const handler = (value:string):boolean => true;
422
-
423
- // Bad — space before generic
424
- const data: Array <number> = [];
425
- function getData <T>(id: string): Promise <T> {}
426
-
427
- // Bad — space before array brackets
428
- const items: string [] = [];
429
- ```
430
-
431
- ---
432
-
433
- ### `typescript-definition-location`
434
-
435
- **What it does:** Enforces that TypeScript definitions are placed in their designated folders:
436
- - Interfaces must be in files inside the `interfaces` folder
437
- - Types must be in files inside the `types` folder
438
- - Enums must be in files inside the `enums` folder
439
-
440
- **Why use it:** Separating type definitions by category makes them easier to find, maintain, and share across the codebase. It promotes a clean and organized project structure.
441
-
442
- ```typescript
443
- // Good — definitions in correct folders
444
- // src/interfaces/user.ts
445
- export interface UserInterface {
446
- id: string,
447
- name: string,
448
- }
449
-
450
- // src/types/config.ts
451
- export type ConfigType = {
452
- apiUrl: string,
453
- timeout: number,
454
- };
455
-
456
- // src/enums/status.ts
457
- export enum UserRoleEnum {
458
- ADMIN = "admin",
459
- USER = "user",
460
- }
461
-
462
- // Bad — definitions in wrong folders
463
- // src/components/user-card.tsx
464
- interface UserProps { // Should be in interfaces folder
465
- name: string,
466
- }
467
-
468
- // src/types/user.ts
469
- export interface UserInterface { // Should be in interfaces folder, not types
470
- id: string,
471
- }
472
-
473
- export enum StatusEnum { // Should be in enums folder, not types
474
- ACTIVE = "active",
475
- }
476
- ```
477
-
478
- <br />
479
-
480
- ---
481
-
482
- [<- Back to Rules Index](./README.md) | [<- Back to Main README](../../README.md)
@@ -1,32 +0,0 @@
1
- # Variable Rules
2
-
3
- ### `variable-naming-convention`
4
-
5
- **What it does:** Enforces naming conventions for variables:
6
- - **camelCase** for all variables and constants
7
- - **PascalCase** for React components and classes
8
- - **camelCase with `use` prefix** for hooks
9
-
10
- **Why use it:** Consistent naming makes code predictable. You can tell what something is by how it's named.
11
-
12
- ```javascript
13
- // Good — correct conventions
14
- const userName = "John"; // camelCase for variables
15
- const itemCount = 42; // camelCase for variables
16
- const maxRetries = 3; // camelCase for constants
17
- const apiBaseUrl = "/api"; // camelCase for constants
18
- const UserProfile = () => <div />; // PascalCase for components
19
- const useAuth = () => {}; // camelCase with use prefix for hooks
20
-
21
- // Bad — wrong conventions
22
- const user_name = "John"; // snake_case
23
- const MAX_RETRIES = 3; // should be camelCase
24
- const userProfile = () => <div />; // should be PascalCase
25
- const UseAuth = () => {}; // hooks should be camelCase
26
- ```
27
-
28
- <br />
29
-
30
- ---
31
-
32
- [<- Back to Rules Index](./README.md) | [<- Back to Main README](../../README.md)