eslint-plugin-code-style 1.2.7 → 1.3.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.
- package/AGENTS.md +461 -27
- package/README.md +68 -26
- package/index.d.ts +2 -0
- package/index.js +142 -20
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -4,9 +4,9 @@ Instructions for AI coding agents working with this codebase.
|
|
|
4
4
|
|
|
5
5
|
## Project Overview
|
|
6
6
|
|
|
7
|
-
**eslint-plugin-code-style** is an ESLint plugin providing
|
|
7
|
+
**eslint-plugin-code-style** is an ESLint plugin providing 61 custom auto-fixable formatting rules for React/JSX projects. It's designed for ESLint v9+ flat config system.
|
|
8
8
|
|
|
9
|
-
- **Main entry:** `index.js` - Contains all
|
|
9
|
+
- **Main entry:** `index.js` - Contains all 61 rules in a single file
|
|
10
10
|
- **Type definitions:** `index.d.ts` - TypeScript declarations for IDE support
|
|
11
11
|
- **Recommended configs:** `recommended-configs/` - Ready-to-use ESLint configurations
|
|
12
12
|
- **Test apps:** `_tests_/` - Sample apps for testing rules
|
|
@@ -44,7 +44,7 @@ index.js
|
|
|
44
44
|
├── imports (fs, path, url)
|
|
45
45
|
├── Rule 1 definition (const ruleName = { create(), meta: {} })
|
|
46
46
|
├── Rule 2 definition
|
|
47
|
-
├── ... (
|
|
47
|
+
├── ... (61 rules total)
|
|
48
48
|
└── export default { meta: {}, rules: {} }
|
|
49
49
|
```
|
|
50
50
|
|
|
@@ -111,15 +111,113 @@ const ruleName = {
|
|
|
111
111
|
};
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
### Adding a New Rule
|
|
114
|
+
### Adding a New Rule — Complete Checklist
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
116
|
+
When creating a new rule, ALL of the following files must be updated:
|
|
117
|
+
|
|
118
|
+
#### 1. `index.js` — Rule Implementation
|
|
119
|
+
- [ ] Add JSDoc comment block with the standard format (see Rule Implementation Pattern above)
|
|
120
|
+
- [ ] Include: Description, Options (if any), Good examples, Bad examples
|
|
121
|
+
- [ ] Add `const ruleName = { create(), meta: {} }` definition
|
|
122
|
+
- [ ] Add to `rules` object in default export (keep alphabetical order)
|
|
123
|
+
- [ ] Update the rule count in any comments if present
|
|
124
|
+
|
|
125
|
+
#### 2. `index.d.ts` — TypeScript Types
|
|
126
|
+
- [ ] Add rule name to `RuleNames` type union (alphabetically sorted)
|
|
127
|
+
- [ ] Add rule to `PluginRules` interface (alphabetically sorted)
|
|
128
|
+
|
|
129
|
+
#### 3. `AGENTS.md` — Agent Instructions
|
|
130
|
+
- [ ] Update rule count in "Project Overview" section (e.g., "61 custom auto-fixable formatting rules")
|
|
131
|
+
- [ ] Update rule count in "Code Structure" section
|
|
132
|
+
- [ ] Add rule to its category in "[Rule Categories](#rule-categories)" section (see list below for all categories)
|
|
133
|
+
- [ ] Update rule count in "Documentation Files" section
|
|
134
|
+
|
|
135
|
+
#### 4. `README.md` — Main Documentation
|
|
136
|
+
- [ ] Update rule count in badges/header section
|
|
137
|
+
- [ ] Update rule count in "Why This Plugin?" section
|
|
138
|
+
- [ ] Update rule count in "Key Features" section
|
|
139
|
+
- [ ] Update rule count in "Auto-Fixable Rules" section
|
|
140
|
+
- [ ] Add rule to `rules: {}` example in "Quick Start" section
|
|
141
|
+
- [ ] Add rule to "Rules Summary" table (with description)
|
|
142
|
+
- [ ] Add detailed rule documentation with:
|
|
143
|
+
- "What it does" description
|
|
144
|
+
- Code examples (Good ✅ and Bad ❌)
|
|
145
|
+
- Options table (if rule has options)
|
|
146
|
+
- Configuration example (if rule has options)
|
|
147
|
+
|
|
148
|
+
#### 5. Config Files — Add Rule to Configs
|
|
149
|
+
- [ ] `recommended-configs/react/eslint.config.js`
|
|
150
|
+
- [ ] `recommended-configs/react-ts-tw/eslint.config.js`
|
|
151
|
+
- [ ] `_tests_/react/eslint.config.js`
|
|
152
|
+
- [ ] `_tests_/react-ts-tw/eslint.config.js`
|
|
153
|
+
|
|
154
|
+
#### 6. Config READMEs (if rule count changed)
|
|
155
|
+
- [ ] `recommended-configs/react/README.md` — Update any rule counts
|
|
156
|
+
- [ ] `recommended-configs/react-ts-tw/README.md` — Update any rule counts
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
### Editing an Existing Rule — Checklist
|
|
161
|
+
|
|
162
|
+
When modifying an existing rule, check if these need updates:
|
|
163
|
+
|
|
164
|
+
#### If changing rule behavior:
|
|
165
|
+
- [ ] Update JSDoc in `index.js` (Good/Bad examples)
|
|
166
|
+
- [ ] Update `README.md` rule documentation (examples, description)
|
|
167
|
+
- [ ] Test in `_tests_/` apps with `npm run lint` and `npm run lint:fix`
|
|
168
|
+
|
|
169
|
+
#### If adding new options:
|
|
170
|
+
- [ ] Add option to `schema` in rule's `meta` object
|
|
171
|
+
- [ ] Add option handling in `create()` function
|
|
172
|
+
- [ ] Update JSDoc Options section in `index.js`
|
|
173
|
+
- [ ] Update README.md options table for the rule
|
|
174
|
+
- [ ] Add configuration example in README.md
|
|
175
|
+
|
|
176
|
+
#### If adding auto-fix to rule that didn't have it:
|
|
177
|
+
- [ ] Add `fixable: "code"` to rule's `meta` object
|
|
178
|
+
- [ ] Add `fix()` function in `context.report()`
|
|
179
|
+
|
|
180
|
+
#### If changing default values:
|
|
181
|
+
- [ ] Update JSDoc in `index.js`
|
|
182
|
+
- [ ] Update README.md options table
|
|
183
|
+
- [ ] Consider if this is a MAJOR version bump (breaking change)
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### Rule Documentation Format in README.md
|
|
188
|
+
|
|
189
|
+
Each rule should have this format in the Rules Reference section:
|
|
190
|
+
|
|
191
|
+
```markdown
|
|
192
|
+
### `rule-name`
|
|
193
|
+
|
|
194
|
+
**What it does:** One-line description of the rule's purpose.
|
|
195
|
+
|
|
196
|
+
**Why use it:** Optional context for why this rule is helpful.
|
|
197
|
+
|
|
198
|
+
> **Note:** Any special notes or dependencies (optional).
|
|
199
|
+
|
|
200
|
+
\`\`\`javascript
|
|
201
|
+
// ✅ Good — description
|
|
202
|
+
const example = "correct code";
|
|
203
|
+
|
|
204
|
+
// ❌ Bad — description
|
|
205
|
+
const example = "incorrect code";
|
|
206
|
+
\`\`\`
|
|
207
|
+
|
|
208
|
+
**Options:** (if rule has options)
|
|
209
|
+
|
|
210
|
+
| Option | Type | Default | Description |
|
|
211
|
+
|--------|------|---------|-------------|
|
|
212
|
+
| `optionName` | `string` | `"value"` | What the option does |
|
|
213
|
+
|
|
214
|
+
\`\`\`javascript
|
|
215
|
+
// Configuration example
|
|
216
|
+
"code-style/rule-name": ["error", { optionName: "value" }]
|
|
217
|
+
\`\`\`
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
```
|
|
123
221
|
|
|
124
222
|
## Key Patterns & Conventions
|
|
125
223
|
|
|
@@ -200,21 +298,36 @@ if (node.parent?.type === "CallExpression") return;
|
|
|
200
298
|
|
|
201
299
|
Rules are organized in these categories (alphabetically sorted in index.js and README.md):
|
|
202
300
|
|
|
203
|
-
- **Array Rules
|
|
204
|
-
-
|
|
205
|
-
- **
|
|
206
|
-
-
|
|
207
|
-
- **
|
|
208
|
-
-
|
|
209
|
-
- **
|
|
210
|
-
-
|
|
211
|
-
- **
|
|
212
|
-
-
|
|
213
|
-
- **
|
|
214
|
-
-
|
|
215
|
-
- **
|
|
216
|
-
-
|
|
217
|
-
- **
|
|
301
|
+
- **Array Rules** — Rules for array formatting
|
|
302
|
+
- `array-items-per-line`, `array-objects-on-new-lines`
|
|
303
|
+
- **Arrow Function Rules** — Arrow function syntax and style
|
|
304
|
+
- `arrow-function-block-body`, `arrow-function-simple-jsx`, `arrow-function-simplify`, `curried-arrow-same-line`
|
|
305
|
+
- **Call Expression Rules** — Function call formatting
|
|
306
|
+
- `function-arguments-format`, `nested-call-closing-brackets`, `no-empty-lines-in-function-calls`, `opening-brackets-same-line`, `simple-call-single-line`, `single-argument-on-one-line`
|
|
307
|
+
- **Comment Rules** — Comment formatting
|
|
308
|
+
- `comment-format`
|
|
309
|
+
- **Component Rules** — React component patterns
|
|
310
|
+
- `component-props-destructure`, `component-props-inline-type`
|
|
311
|
+
- **Control Flow Rules** — if/switch/block statements
|
|
312
|
+
- `block-statement-newlines`, `if-statement-format`, `multiline-if-conditions`, `no-empty-lines-in-switch-cases`
|
|
313
|
+
- **Function Rules** — Function declarations and params
|
|
314
|
+
- `function-call-spacing`, `function-declaration-style`, `function-naming-convention`, `function-object-destructure`, `function-params-per-line`, `no-empty-lines-in-function-params`
|
|
315
|
+
- **Hook Rules** — React hooks formatting
|
|
316
|
+
- `hook-callback-format`, `hook-deps-per-line`
|
|
317
|
+
- **Import/Export Rules** — Import/export statements
|
|
318
|
+
- `absolute-imports-only`, `export-format`, `import-format`, `import-source-spacing`, `index-export-style`, `module-index-exports`
|
|
319
|
+
- **JSX Rules** — JSX elements and attributes
|
|
320
|
+
- `classname-dynamic-at-end`, `classname-multiline`, `classname-no-extra-spaces`, `classname-order`, `jsx-children-on-new-line`, `jsx-closing-bracket-spacing`, `jsx-element-child-new-line`, `jsx-logical-expression-simplify`, `jsx-parentheses-position`, `jsx-prop-naming-convention`, `jsx-simple-element-one-line`, `jsx-string-value-trim`, `jsx-ternary-format`, `no-empty-lines-in-jsx`
|
|
321
|
+
- **Object Rules** — Object literal formatting
|
|
322
|
+
- `no-empty-lines-in-objects`, `object-property-per-line`, `object-property-value-brace`, `object-property-value-format`, `string-property-spacing`
|
|
323
|
+
- **React Rules** — React-specific patterns
|
|
324
|
+
- `react-code-order`
|
|
325
|
+
- **Spacing Rules** — General spacing rules
|
|
326
|
+
- `assignment-value-same-line`, `member-expression-bracket-spacing`
|
|
327
|
+
- **TypeScript Rules** — TypeScript-specific rules (TS configs only)
|
|
328
|
+
- `enum-format`, `interface-format`, `type-annotation-spacing`, `type-format`, `typescript-definition-location`
|
|
329
|
+
- **Variable Rules** — Variable declarations and naming
|
|
330
|
+
- `variable-naming-convention`
|
|
218
331
|
|
|
219
332
|
## Naming Conventions
|
|
220
333
|
|
|
@@ -230,7 +343,7 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
|
|
|
230
343
|
|
|
231
344
|
## Documentation Files
|
|
232
345
|
|
|
233
|
-
- `README.md` - Main documentation with all
|
|
346
|
+
- `README.md` - Main documentation with all 61 rules
|
|
234
347
|
- `recommended-configs/<config-name>/README.md` - Config-specific documentation (references main README for rule details)
|
|
235
348
|
- `index.d.ts` - TypeScript types for IDE autocomplete
|
|
236
349
|
|
|
@@ -241,3 +354,324 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
|
|
|
241
354
|
- Object properties in `context.report()` must be alphabetically sorted
|
|
242
355
|
- Keep rules self-sufficient (no dependencies on other ESLint rules)
|
|
243
356
|
- Test with relevant test app in `_tests_/` before publishing
|
|
357
|
+
|
|
358
|
+
## Git Workflow
|
|
359
|
+
|
|
360
|
+
### Commit Message Format
|
|
361
|
+
|
|
362
|
+
Follow [Conventional Commits](https://www.conventionalcommits.org/) specification:
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
<type>: <subject>
|
|
366
|
+
|
|
367
|
+
[optional body]
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Types:**
|
|
371
|
+
- `feat` - New feature or rule
|
|
372
|
+
- `fix` - Bug fix
|
|
373
|
+
- `docs` - Documentation only changes
|
|
374
|
+
- `refactor` - Code change that neither fixes a bug nor adds a feature
|
|
375
|
+
- `chore` - Maintenance tasks (deps, configs)
|
|
376
|
+
|
|
377
|
+
**Subject line rules:**
|
|
378
|
+
- Use lowercase (except proper nouns)
|
|
379
|
+
- No period at the end
|
|
380
|
+
- Maximum 72 characters
|
|
381
|
+
- Use imperative mood ("add" not "added")
|
|
382
|
+
|
|
383
|
+
**Examples:**
|
|
384
|
+
```
|
|
385
|
+
feat: add function-declaration-style rule
|
|
386
|
+
fix: allow relative imports in entry files
|
|
387
|
+
docs: update options descriptions
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Multi-feature commits:**
|
|
391
|
+
```
|
|
392
|
+
feat: add function-declaration-style rule and enhancements
|
|
393
|
+
|
|
394
|
+
New rule:
|
|
395
|
+
- function-declaration-style: auto-fixes to arrow expressions
|
|
396
|
+
|
|
397
|
+
Enhancements:
|
|
398
|
+
- function-naming-convention: add auto-fix
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### Versioning (SemVer)
|
|
404
|
+
|
|
405
|
+
Format: `MAJOR.MINOR.PATCH` (e.g., `1.2.8`)
|
|
406
|
+
|
|
407
|
+
| Change Type | Version | Examples |
|
|
408
|
+
|-------------|---------|----------|
|
|
409
|
+
| **PATCH** | `x.x.+1` | Bug fixes, typo corrections, doc updates |
|
|
410
|
+
| **MINOR** | `x.+1.0` | New rules, new features, new options |
|
|
411
|
+
| **MAJOR** | `+1.0.0` | Breaking changes, removed/renamed rules |
|
|
412
|
+
|
|
413
|
+
**Decision guide:**
|
|
414
|
+
- New rule → MINOR
|
|
415
|
+
- Auto-fix to existing rule → MINOR
|
|
416
|
+
- New option → MINOR
|
|
417
|
+
- Bug fix → PATCH
|
|
418
|
+
- Doc update only → PATCH
|
|
419
|
+
- Change default values → MAJOR (breaking)
|
|
420
|
+
- Rename/remove rule → MAJOR (breaking)
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
### Release Steps
|
|
425
|
+
|
|
426
|
+
1. **Update version in package.json**
|
|
427
|
+
2. **Commit changes:** `git commit -m "feat: description"`
|
|
428
|
+
3. **Create annotated tag:**
|
|
429
|
+
```bash
|
|
430
|
+
git tag -a v1.2.9 -m "v1.2.9
|
|
431
|
+
|
|
432
|
+
- Feature description 1
|
|
433
|
+
- Feature description 2"
|
|
434
|
+
```
|
|
435
|
+
4. **Push (requires explicit approval):** `git push origin HEAD && git push origin v1.2.9`
|
|
436
|
+
5. **Publish (requires explicit approval):** `npm publish`
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
### GitHub Releases (Grouped Tags)
|
|
441
|
+
|
|
442
|
+
GitHub Releases group multiple version tags into a single release announcement. Create a release when a significant milestone is reached (new features, major enhancements).
|
|
443
|
+
|
|
444
|
+
**When to create a GitHub Release:**
|
|
445
|
+
- After multiple PATCH/MINOR versions accumulate significant changes
|
|
446
|
+
- When a new major feature is complete
|
|
447
|
+
- At logical milestones (e.g., v1.2.0 → v1.3.0)
|
|
448
|
+
|
|
449
|
+
**Release format:**
|
|
450
|
+
|
|
451
|
+
```markdown
|
|
452
|
+
## Release Title
|
|
453
|
+
<Short, descriptive title summarizing the main changes>
|
|
454
|
+
|
|
455
|
+
## Version Range
|
|
456
|
+
vX.X.X → vY.Y.Y
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## What's New
|
|
461
|
+
|
|
462
|
+
<Brief intro paragraph mentioning key highlights and rule count change>
|
|
463
|
+
|
|
464
|
+
### New Rules
|
|
465
|
+
|
|
466
|
+
| Rule | Description |
|
|
467
|
+
|------|-------------|
|
|
468
|
+
| `rule-name` | What it does |
|
|
469
|
+
|
|
470
|
+
### Enhancements
|
|
471
|
+
|
|
472
|
+
| Rule | Enhancement |
|
|
473
|
+
|------|-------------|
|
|
474
|
+
| `rule-name` | What was improved |
|
|
475
|
+
|
|
476
|
+
### New Features
|
|
477
|
+
|
|
478
|
+
- Feature 1 description
|
|
479
|
+
- Feature 2 description
|
|
480
|
+
|
|
481
|
+
### Bug Fixes
|
|
482
|
+
|
|
483
|
+
- Fix 1 description
|
|
484
|
+
- Fix 2 description
|
|
485
|
+
|
|
486
|
+
### Documentation
|
|
487
|
+
|
|
488
|
+
- Doc change 1
|
|
489
|
+
- Doc change 2
|
|
490
|
+
|
|
491
|
+
## Installation
|
|
492
|
+
|
|
493
|
+
\`\`\`bash
|
|
494
|
+
npm install eslint-plugin-code-style@Y.Y.Y
|
|
495
|
+
\`\`\`
|
|
496
|
+
|
|
497
|
+
## Stats
|
|
498
|
+
|
|
499
|
+
- Total Rules: X (was Y)
|
|
500
|
+
- All rules are auto-fixable with `eslint --fix`
|
|
501
|
+
|
|
502
|
+
**Full Changelog**: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/vX.X.X...vY.Y.Y
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Steps to create a GitHub Release:**
|
|
506
|
+
|
|
507
|
+
1. Go to repository → Releases → "Draft a new release"
|
|
508
|
+
2. Choose the latest tag (e.g., `v1.3.0`)
|
|
509
|
+
3. Set release title (short, descriptive)
|
|
510
|
+
4. Paste the release description following the format above
|
|
511
|
+
5. Update `CHANGELOG.md` with the same information
|
|
512
|
+
6. Publish release
|
|
513
|
+
|
|
514
|
+
**CHANGELOG.md:**
|
|
515
|
+
|
|
516
|
+
All releases are documented in `CHANGELOG.md` at the project root. Update this file whenever creating a GitHub Release.
|
|
517
|
+
|
|
518
|
+
Each release entry in CHANGELOG.md must include a **Full Changelog** link at the end:
|
|
519
|
+
|
|
520
|
+
```markdown
|
|
521
|
+
**Full Changelog:** https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/vFIRST...vLAST
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
Where:
|
|
525
|
+
- `vFIRST` = First version tag in the release range (the tag after the last tag of the previous release)
|
|
526
|
+
- `vLAST` = Last version tag in the release range (current release)
|
|
527
|
+
|
|
528
|
+
Example: For release 1.2.0 with version range v1.1.10 → v1.2.0:
|
|
529
|
+
```markdown
|
|
530
|
+
**Full Changelog:** https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.1.10...v1.2.0
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
## Skills
|
|
534
|
+
|
|
535
|
+
This project includes reusable skills in the `.skills/` directory following the [Agent Skills](https://agentskills.io) open standard. These work with Claude Code, Cursor, VS Code, GitHub Copilot, Gemini CLI, and other compatible agents.
|
|
536
|
+
|
|
537
|
+
| Skill | Description |
|
|
538
|
+
|-------|-------------|
|
|
539
|
+
| `test-rule` | Test an ESLint rule after creating or modifying it |
|
|
540
|
+
| `validate-types` | Verify TypeScript definitions match rules in index.js |
|
|
541
|
+
| `review-config` | Review a recommended ESLint configuration |
|
|
542
|
+
| `audit-docs` | Verify documentation accuracy across all files |
|
|
543
|
+
|
|
544
|
+
See `.skills/*/SKILL.md` for detailed instructions.
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## Workflows
|
|
549
|
+
|
|
550
|
+
Reusable workflows for common tasks. Any AI agent should follow these when performing the specified task.
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
### Workflow: Test Rule
|
|
555
|
+
|
|
556
|
+
Test an ESLint rule to verify it works correctly.
|
|
557
|
+
|
|
558
|
+
**When to use:** After creating or modifying a rule.
|
|
559
|
+
|
|
560
|
+
**Steps:**
|
|
561
|
+
|
|
562
|
+
1. **Find the rule** in `index.js` and understand what it checks
|
|
563
|
+
2. **Identify test app** — Use `_tests_/react/` for JS rules or `_tests_/react-ts-tw/` for TS rules
|
|
564
|
+
3. **Create test cases** in the test app:
|
|
565
|
+
- Add code that should PASS (no violations)
|
|
566
|
+
- Add code that should FAIL (triggers violations)
|
|
567
|
+
4. **Run the linter:**
|
|
568
|
+
```bash
|
|
569
|
+
cd _tests_/<config-name>
|
|
570
|
+
npm run lint # Check for violations
|
|
571
|
+
npm run lint:fix # Verify auto-fix works
|
|
572
|
+
```
|
|
573
|
+
5. **Verify results:**
|
|
574
|
+
- Valid code produces no errors
|
|
575
|
+
- Invalid code triggers the expected error message
|
|
576
|
+
- Auto-fix transforms code correctly
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
### Workflow: Validate Types
|
|
581
|
+
|
|
582
|
+
Verify TypeScript definitions match the rules in `index.js`.
|
|
583
|
+
|
|
584
|
+
**When to use:** After adding new rules or before releases.
|
|
585
|
+
|
|
586
|
+
**Steps:**
|
|
587
|
+
|
|
588
|
+
1. **Count rules in index.js:**
|
|
589
|
+
```bash
|
|
590
|
+
grep -c "^const .* = {$" index.js
|
|
591
|
+
```
|
|
592
|
+
Or count entries in the `rules` export object.
|
|
593
|
+
|
|
594
|
+
2. **Check index.d.ts:**
|
|
595
|
+
- Verify `RuleNames` type includes all rule names (alphabetically sorted)
|
|
596
|
+
- Verify `PluginRules` interface includes all rules
|
|
597
|
+
|
|
598
|
+
3. **Look for mismatches:**
|
|
599
|
+
- Rules in `index.js` missing from `index.d.ts`?
|
|
600
|
+
- Rules in `index.d.ts` that don't exist in `index.js`?
|
|
601
|
+
|
|
602
|
+
4. **Report:**
|
|
603
|
+
- Total rules: X
|
|
604
|
+
- Types match: Yes/No
|
|
605
|
+
- Missing types: [list]
|
|
606
|
+
- Extra types: [list]
|
|
607
|
+
|
|
608
|
+
---
|
|
609
|
+
|
|
610
|
+
### Workflow: Review Config
|
|
611
|
+
|
|
612
|
+
Review a recommended ESLint configuration for consistency.
|
|
613
|
+
|
|
614
|
+
**When to use:** After adding rules or modifying configs.
|
|
615
|
+
|
|
616
|
+
**Arguments:** `<config-name>` (e.g., `react`, `react-ts-tw`)
|
|
617
|
+
|
|
618
|
+
**Steps:**
|
|
619
|
+
|
|
620
|
+
1. **Check config file:** `recommended-configs/<config-name>/eslint.config.js`
|
|
621
|
+
- Does it import the plugin correctly?
|
|
622
|
+
- Are rules set to `"error"` (not `"off"`)?
|
|
623
|
+
- Are rule options valid per the rule's schema?
|
|
624
|
+
|
|
625
|
+
2. **Compare with test config:** `_tests_/<config-name>/eslint.config.js`
|
|
626
|
+
- Should have the same rules enabled
|
|
627
|
+
- Test config may have additional test-specific settings
|
|
628
|
+
|
|
629
|
+
3. **Test the config:**
|
|
630
|
+
```bash
|
|
631
|
+
cd _tests_/<config-name>
|
|
632
|
+
npm run lint
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
4. **Check README:** `recommended-configs/<config-name>/README.md`
|
|
636
|
+
- Does it list all enabled rules?
|
|
637
|
+
- Are rule counts accurate?
|
|
638
|
+
|
|
639
|
+
5. **Report:**
|
|
640
|
+
- Config valid: Yes/No
|
|
641
|
+
- Rules enabled: X
|
|
642
|
+
- Issues found: [list]
|
|
643
|
+
|
|
644
|
+
---
|
|
645
|
+
|
|
646
|
+
### Workflow: Audit Docs
|
|
647
|
+
|
|
648
|
+
Verify documentation accuracy across all files.
|
|
649
|
+
|
|
650
|
+
**When to use:** Before releases or after adding rules.
|
|
651
|
+
|
|
652
|
+
**Steps:**
|
|
653
|
+
|
|
654
|
+
1. **Count actual rules:**
|
|
655
|
+
```bash
|
|
656
|
+
grep -c "^const .* = {$" index.js
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
2. **Check rule count references:**
|
|
660
|
+
- `AGENTS.md`: "61 custom auto-fixable formatting rules"
|
|
661
|
+
- `README.md`: Multiple mentions of rule count
|
|
662
|
+
- `recommended-configs/*/README.md`: Any rule count mentions
|
|
663
|
+
|
|
664
|
+
3. **Verify version consistency:**
|
|
665
|
+
- `package.json` version matches latest tag
|
|
666
|
+
- No outdated version references in docs
|
|
667
|
+
|
|
668
|
+
4. **Check links:**
|
|
669
|
+
- Config paths in README exist
|
|
670
|
+
- Test app paths exist
|
|
671
|
+
- Internal markdown links work
|
|
672
|
+
|
|
673
|
+
5. **Report:**
|
|
674
|
+
- Actual rule count: X
|
|
675
|
+
- Documented counts match: Yes/No
|
|
676
|
+
- Outdated references: [list]
|
|
677
|
+
- Broken links: [list]
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](https://nodejs.org/)
|
|
11
11
|
[](https://react.dev/)
|
|
12
12
|
[](https://www.typescriptlang.org/)
|
|
13
|
-
[](https://tailwindcss.com/)
|
|
14
14
|
|
|
15
15
|
[](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/stargazers)
|
|
16
16
|
[](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/issues)
|
|
@@ -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
|
+
*61 auto-fixable rules 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 **61 custom auto-fixable rules** 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 **60 custom auto-fixable rules** for code formatting. Built
|
|
|
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
|
-
- **Fully automated** — All
|
|
39
|
+
- **Fully automated** — All 61 rules support auto-fix, eliminating manual style reviews
|
|
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
|
|
|
@@ -60,7 +60,7 @@ We provide **ready-to-use ESLint flat configuration files** that combine `eslint
|
|
|
60
60
|
|
|
61
61
|
### 💡 Why Use These Configs?
|
|
62
62
|
|
|
63
|
-
- **Complete Coverage** — Combines ESLint built-in rules, third-party plugins, and all
|
|
63
|
+
- **Complete Coverage** — Combines ESLint built-in rules, third-party plugins, and all 61 code-style rules
|
|
64
64
|
- **Ready-to-Use** — Copy the config file and start linting immediately
|
|
65
65
|
- **Battle-Tested** — These configurations have been refined through real-world usage
|
|
66
66
|
- **Fully Documented** — Each config includes detailed instructions and explanations
|
|
@@ -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
|
-
All **
|
|
100
|
+
All **61 rules** support automatic fixing with `eslint --fix`. No manual code changes needed.
|
|
101
101
|
|
|
102
102
|
</td>
|
|
103
103
|
<td width="50%">
|
|
@@ -200,6 +200,7 @@ rules: {
|
|
|
200
200
|
"code-style/export-format": "error",
|
|
201
201
|
"code-style/function-arguments-format": "error",
|
|
202
202
|
"code-style/function-call-spacing": "error",
|
|
203
|
+
"code-style/function-declaration-style": "error",
|
|
203
204
|
"code-style/function-naming-convention": "error",
|
|
204
205
|
"code-style/function-object-destructure": "error",
|
|
205
206
|
"code-style/function-params-per-line": "error",
|
|
@@ -247,9 +248,9 @@ rules: {
|
|
|
247
248
|
|
|
248
249
|
---
|
|
249
250
|
|
|
250
|
-
## 📖 Rules
|
|
251
|
+
## 📖 Rules Categories
|
|
251
252
|
|
|
252
|
-
> All **
|
|
253
|
+
> All **61 rules** are auto-fixable. See detailed examples for each rule in the [Rules Reference](#-rules-reference) section below.
|
|
253
254
|
>
|
|
254
255
|
> Rules marked with ⚙️ support customization options (e.g., extending default folder lists).
|
|
255
256
|
|
|
@@ -282,6 +283,7 @@ rules: {
|
|
|
282
283
|
| `no-empty-lines-in-switch-cases` | No empty line after `case X:` before code, no empty lines between cases |
|
|
283
284
|
| **Function Rules** | |
|
|
284
285
|
| `function-call-spacing` | No space between function name and `(`: `fn()` not `fn ()` |
|
|
286
|
+
| `function-declaration-style` | Auto-fix for `func-style`: converts function declarations to arrow expressions |
|
|
285
287
|
| `function-naming-convention` | Functions use camelCase, start with verb (get/set/handle/is/has), handlers end with Handler |
|
|
286
288
|
| `function-object-destructure` | Non-component functions: use typed params (not destructured), destructure in body; report dot notation access |
|
|
287
289
|
| `function-params-per-line` | When multiline, each param on own line with consistent indentation |
|
|
@@ -1079,6 +1081,46 @@ array.map ((x) => x * 2);
|
|
|
1079
1081
|
|
|
1080
1082
|
---
|
|
1081
1083
|
|
|
1084
|
+
### `function-declaration-style`
|
|
1085
|
+
|
|
1086
|
+
**What it does:** Converts function declarations to `const` arrow function expressions. This is the auto-fixable companion to ESLint's built-in `func-style` rule.
|
|
1087
|
+
|
|
1088
|
+
**Why use it:** The built-in `func-style: ["error", "expression"]` rule reports function declarations but does not auto-fix them. This rule provides the auto-fix. Both rules should be used together for the best experience.
|
|
1089
|
+
|
|
1090
|
+
> **Important:** This rule depends on `func-style: ["error", "expression"]` being configured. If `func-style` is set to `"declaration"` or is disabled, do not enable this rule — it would conflict.
|
|
1091
|
+
|
|
1092
|
+
```typescript
|
|
1093
|
+
// ✅ Good — arrow function expression
|
|
1094
|
+
export const getToken = (): string | null => getCookie(tokenKey);
|
|
1095
|
+
|
|
1096
|
+
export const clearAuth = (): void => {
|
|
1097
|
+
removeToken();
|
|
1098
|
+
clearStorage();
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1101
|
+
const isAuthenticated = (): boolean => {
|
|
1102
|
+
const token = getToken();
|
|
1103
|
+
return !!token;
|
|
1104
|
+
};
|
|
1105
|
+
|
|
1106
|
+
// ❌ Bad — function declaration
|
|
1107
|
+
export function getToken(): string | null {
|
|
1108
|
+
return getCookie(tokenKey);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
export function clearAuth(): void {
|
|
1112
|
+
removeToken();
|
|
1113
|
+
clearStorage();
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
function isAuthenticated(): boolean {
|
|
1117
|
+
const token = getToken();
|
|
1118
|
+
return !!token;
|
|
1119
|
+
}
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
---
|
|
1123
|
+
|
|
1082
1124
|
### `function-naming-convention`
|
|
1083
1125
|
|
|
1084
1126
|
**What it does:** Enforces naming conventions for functions:
|
|
@@ -1373,24 +1415,24 @@ import { fetchUsers } from "@/apis/users/fetchUsers";
|
|
|
1373
1415
|
```
|
|
1374
1416
|
|
|
1375
1417
|
**Default Allowed Folders:**
|
|
1376
|
-
`actions`, `apis`, `assets`, `atoms`, `components`, `config`, `configs`, `constants`, `contexts`, `data`, `enums`, `helpers`, `hooks`, `interfaces`, `layouts`, `lib`, `middlewares`, `providers`, `reducers`, `redux`, `requests`, `routes`, `schemas`, `services`, `store`, `styles`, `theme`, `thunks`, `types`, `ui`, `utils`, `utilities`, `views`
|
|
1418
|
+
`actions`, `apis`, `assets`, `atoms`, `components`, `config`, `configs`, `constants`, `contexts`, `data`, `enums`, `helpers`, `hooks`, `interfaces`, `layouts`, `lib`, `middlewares`, `pages`, `providers`, `reducers`, `redux`, `requests`, `routes`, `schemas`, `services`, `store`, `styles`, `theme`, `thunks`, `types`, `ui`, `utils`, `utilities`, `views`
|
|
1377
1419
|
|
|
1378
1420
|
**Customization Options:**
|
|
1379
1421
|
|
|
1380
1422
|
| Option | Type | Description |
|
|
1381
1423
|
|--------|------|-------------|
|
|
1382
|
-
| `extraAllowedFolders` | `string[]` | Add
|
|
1383
|
-
| `extraReduxSubfolders` | `string[]` | Add
|
|
1384
|
-
| `extraDeepImportFolders` | `string[]` | Add
|
|
1385
|
-
| `aliasPrefix` | `string` | Change the
|
|
1386
|
-
| `allowedFolders` | `string[]` |
|
|
1387
|
-
| `reduxSubfolders` | `string[]` |
|
|
1388
|
-
| `deepImportFolders` | `string[]` |
|
|
1424
|
+
| `extraAllowedFolders` | `string[]` | Add custom folders that can be imported with `@/folder`. Extends defaults without replacing them. Use when your project has folders like `features/`, `modules/`, etc. |
|
|
1425
|
+
| `extraReduxSubfolders` | `string[]` | Add Redux-related subfolders that can be imported directly (`@/selectors`) or nested (`@/redux/selectors`). Default subfolders: `actions`, `reducers`, `store`, `thunks`, `types` |
|
|
1426
|
+
| `extraDeepImportFolders` | `string[]` | Add folders where direct file imports are allowed (`@/assets/images/logo.svg`). Use for folders without index files like images, fonts, etc. Default: `assets` |
|
|
1427
|
+
| `aliasPrefix` | `string` | Change the path alias prefix if your project uses something other than `@/` (e.g., `~/`, `src/`) |
|
|
1428
|
+
| `allowedFolders` | `string[]` | Completely replace the default allowed folders list. Use only if you need full control over which folders are valid |
|
|
1429
|
+
| `reduxSubfolders` | `string[]` | Completely replace the default Redux subfolders list |
|
|
1430
|
+
| `deepImportFolders` | `string[]` | Completely replace the default deep import folders list |
|
|
1389
1431
|
|
|
1390
1432
|
```javascript
|
|
1391
1433
|
// Example: Add custom folders to the defaults
|
|
1392
1434
|
"code-style/absolute-imports-only": ["error", {
|
|
1393
|
-
extraAllowedFolders: ["features", "modules"
|
|
1435
|
+
extraAllowedFolders: ["features", "modules"],
|
|
1394
1436
|
extraDeepImportFolders: ["images", "fonts"]
|
|
1395
1437
|
}]
|
|
1396
1438
|
```
|
|
@@ -1617,7 +1659,7 @@ import { Button } from "@/components/Button/Button"; // Avoid this!
|
|
|
1617
1659
|
```
|
|
1618
1660
|
|
|
1619
1661
|
**Default Module Folders:**
|
|
1620
|
-
`actions`, `apis`, `assets`, `atoms`, `components`, `config`, `configs`, `constants`, `contexts`, `data`, `enums`, `helpers`, `hooks`, `interfaces`, `layouts`, `lib`, `middlewares`, `providers`, `reducers`, `redux`, `requests`, `routes`, `schemas`, `services`, `store`, `styles`, `theme`, `thunks`, `types`, `ui`, `utils`, `utilities`, `views`
|
|
1662
|
+
`actions`, `apis`, `assets`, `atoms`, `components`, `config`, `configs`, `constants`, `contexts`, `data`, `enums`, `helpers`, `hooks`, `interfaces`, `layouts`, `lib`, `middlewares`, `pages`, `providers`, `reducers`, `redux`, `requests`, `routes`, `schemas`, `services`, `store`, `styles`, `theme`, `thunks`, `types`, `ui`, `utils`, `utilities`, `views`
|
|
1621
1663
|
|
|
1622
1664
|
**Default Ignore Patterns:**
|
|
1623
1665
|
`index.js`, `index.jsx`, `index.ts`, `index.tsx`, `.DS_Store`, `__tests__`, `__mocks__`, `*.test.js`, `*.test.jsx`, `*.test.ts`, `*.test.tsx`, `*.spec.js`, `*.spec.jsx`, `*.spec.ts`, `*.spec.tsx`
|
|
@@ -1626,18 +1668,18 @@ import { Button } from "@/components/Button/Button"; // Avoid this!
|
|
|
1626
1668
|
|
|
1627
1669
|
| Option | Type | Description |
|
|
1628
1670
|
|--------|------|-------------|
|
|
1629
|
-
| `extraModuleFolders` | `string[]` | Add
|
|
1630
|
-
| `extraLazyLoadFolders` | `string[]` | Add
|
|
1631
|
-
| `extraIgnorePatterns` | `string[]` | Add
|
|
1632
|
-
| `moduleFolders` | `string[]` |
|
|
1633
|
-
| `lazyLoadFolders` | `string[]` |
|
|
1634
|
-
| `ignorePatterns` | `string[]` |
|
|
1671
|
+
| `extraModuleFolders` | `string[]` | Add folders that should have an `index.js` re-exporting all public files. Use for project-specific folders like `features/`, `modules/` that follow the same pattern |
|
|
1672
|
+
| `extraLazyLoadFolders` | `string[]` | Add folders exempt from index file requirements. Use for route/page components loaded via dynamic `import()`. Default: `pages`, `views` |
|
|
1673
|
+
| `extraIgnorePatterns` | `string[]` | Add file patterns to skip when checking for index exports. Supports wildcards like `*.stories.js`, `*.mock.js` |
|
|
1674
|
+
| `moduleFolders` | `string[]` | Completely replace the default module folders list. Use only if you need full control over which folders require index files |
|
|
1675
|
+
| `lazyLoadFolders` | `string[]` | Completely replace the default lazy load folders list |
|
|
1676
|
+
| `ignorePatterns` | `string[]` | Completely replace the default ignore patterns list |
|
|
1635
1677
|
|
|
1636
1678
|
```javascript
|
|
1637
1679
|
// Example: Add custom folders and patterns
|
|
1638
1680
|
"code-style/module-index-exports": ["error", {
|
|
1639
|
-
extraModuleFolders: ["features", "modules"
|
|
1640
|
-
extraLazyLoadFolders: ["
|
|
1681
|
+
extraModuleFolders: ["features", "modules"],
|
|
1682
|
+
extraLazyLoadFolders: ["screens"],
|
|
1641
1683
|
extraIgnorePatterns: ["*.stories.js", "*.mock.js"]
|
|
1642
1684
|
}]
|
|
1643
1685
|
```
|
package/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export type RuleNames =
|
|
|
20
20
|
| "code-style/export-format"
|
|
21
21
|
| "code-style/function-arguments-format"
|
|
22
22
|
| "code-style/function-call-spacing"
|
|
23
|
+
| "code-style/function-declaration-style"
|
|
23
24
|
| "code-style/function-naming-convention"
|
|
24
25
|
| "code-style/function-object-destructure"
|
|
25
26
|
| "code-style/function-params-per-line"
|
|
@@ -101,6 +102,7 @@ interface PluginRules {
|
|
|
101
102
|
"export-format": Rule.RuleModule;
|
|
102
103
|
"function-arguments-format": Rule.RuleModule;
|
|
103
104
|
"function-call-spacing": Rule.RuleModule;
|
|
105
|
+
"function-declaration-style": Rule.RuleModule;
|
|
104
106
|
"function-naming-convention": Rule.RuleModule;
|
|
105
107
|
"function-object-destructure": Rule.RuleModule;
|
|
106
108
|
"function-params-per-line": Rule.RuleModule;
|
package/index.js
CHANGED
|
@@ -1679,6 +1679,92 @@ const functionCallSpacing = {
|
|
|
1679
1679
|
},
|
|
1680
1680
|
};
|
|
1681
1681
|
|
|
1682
|
+
/**
|
|
1683
|
+
* ───────────────────────────────────────────────────────────────
|
|
1684
|
+
* Rule: Function Declaration Style
|
|
1685
|
+
* ───────────────────────────────────────────────────────────────
|
|
1686
|
+
*
|
|
1687
|
+
* Description:
|
|
1688
|
+
* Enforce function expressions (arrow functions) instead of
|
|
1689
|
+
* function declarations. Auto-fixes by converting to const
|
|
1690
|
+
* arrow function expressions.
|
|
1691
|
+
*
|
|
1692
|
+
* ✓ Good:
|
|
1693
|
+
* const getToken = (): string | null => getCookie(tokenKey);
|
|
1694
|
+
* const clearAuth = (): void => {
|
|
1695
|
+
* removeToken();
|
|
1696
|
+
* clearStorage();
|
|
1697
|
+
* };
|
|
1698
|
+
*
|
|
1699
|
+
* ✗ Bad:
|
|
1700
|
+
* function getToken(): string | null { return getCookie(tokenKey); }
|
|
1701
|
+
* function clearAuth(): void {
|
|
1702
|
+
* removeToken();
|
|
1703
|
+
* clearStorage();
|
|
1704
|
+
* }
|
|
1705
|
+
*/
|
|
1706
|
+
const functionDeclarationStyle = {
|
|
1707
|
+
create(context) {
|
|
1708
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
1709
|
+
|
|
1710
|
+
return {
|
|
1711
|
+
FunctionDeclaration(node) {
|
|
1712
|
+
if (!node.id) return;
|
|
1713
|
+
|
|
1714
|
+
const name = node.id.name;
|
|
1715
|
+
|
|
1716
|
+
// Build the params text
|
|
1717
|
+
const paramsText = node.params.map((p) => sourceCode.getText(p)).join(", ");
|
|
1718
|
+
|
|
1719
|
+
// Build return type annotation if present
|
|
1720
|
+
let returnType = "";
|
|
1721
|
+
|
|
1722
|
+
if (node.returnType) {
|
|
1723
|
+
returnType = sourceCode.getText(node.returnType);
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
// Build type parameters if present (generics)
|
|
1727
|
+
let typeParams = "";
|
|
1728
|
+
|
|
1729
|
+
if (node.typeParameters) {
|
|
1730
|
+
typeParams = sourceCode.getText(node.typeParameters);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
// Check if async
|
|
1734
|
+
const isAsync = node.async;
|
|
1735
|
+
const asyncPrefix = isAsync ? "async " : "";
|
|
1736
|
+
|
|
1737
|
+
// Get the body text
|
|
1738
|
+
const bodyText = sourceCode.getText(node.body);
|
|
1739
|
+
|
|
1740
|
+
// Check for export keywords
|
|
1741
|
+
const parentNode = node.parent;
|
|
1742
|
+
const isExported = parentNode && parentNode.type === "ExportNamedDeclaration";
|
|
1743
|
+
|
|
1744
|
+
const exportPrefix = isExported ? "export " : "";
|
|
1745
|
+
|
|
1746
|
+
context.report({
|
|
1747
|
+
fix(fixer) {
|
|
1748
|
+
const fixTarget = isExported ? parentNode : node;
|
|
1749
|
+
|
|
1750
|
+
const replacement = `${exportPrefix}const ${name} = ${asyncPrefix}(${paramsText})${returnType} => ${bodyText};`;
|
|
1751
|
+
|
|
1752
|
+
return fixer.replaceText(fixTarget, replacement);
|
|
1753
|
+
},
|
|
1754
|
+
message: `Expected a function expression. Use \`const ${name} = ${asyncPrefix}(${paramsText})${returnType} => ...\` instead.`,
|
|
1755
|
+
node: node.id,
|
|
1756
|
+
});
|
|
1757
|
+
},
|
|
1758
|
+
};
|
|
1759
|
+
},
|
|
1760
|
+
meta: {
|
|
1761
|
+
docs: { description: "Enforce arrow function expressions instead of function declarations" },
|
|
1762
|
+
fixable: "code",
|
|
1763
|
+
schema: [],
|
|
1764
|
+
type: "suggestion",
|
|
1765
|
+
},
|
|
1766
|
+
};
|
|
1767
|
+
|
|
1682
1768
|
/**
|
|
1683
1769
|
* ───────────────────────────────────────────────────────────────
|
|
1684
1770
|
* Rule: Function Naming Convention
|
|
@@ -1772,9 +1858,37 @@ const functionNamingConvention = {
|
|
|
1772
1858
|
node: node.id || node.parent.id,
|
|
1773
1859
|
});
|
|
1774
1860
|
} else if (!hasHandlerSuffix) {
|
|
1861
|
+
const identifierNode = node.id || node.parent.id;
|
|
1862
|
+
const newName = `${name}Handler`;
|
|
1863
|
+
|
|
1775
1864
|
context.report({
|
|
1776
|
-
|
|
1777
|
-
|
|
1865
|
+
fix(fixer) {
|
|
1866
|
+
const scope = context.sourceCode
|
|
1867
|
+
? context.sourceCode.getScope(node)
|
|
1868
|
+
: context.getScope();
|
|
1869
|
+
|
|
1870
|
+
// Find all references to this variable in the scope
|
|
1871
|
+
const variable = scope.variables.find((v) => v.name === name)
|
|
1872
|
+
|| (scope.upper && scope.upper.variables.find((v) => v.name === name));
|
|
1873
|
+
|
|
1874
|
+
if (!variable) return fixer.replaceText(identifierNode, newName);
|
|
1875
|
+
|
|
1876
|
+
const fixes = [];
|
|
1877
|
+
|
|
1878
|
+
// Fix the definition
|
|
1879
|
+
variable.defs.forEach((def) => {
|
|
1880
|
+
fixes.push(fixer.replaceText(def.name, newName));
|
|
1881
|
+
});
|
|
1882
|
+
|
|
1883
|
+
// Fix all references
|
|
1884
|
+
variable.references.forEach((ref) => {
|
|
1885
|
+
fixes.push(fixer.replaceText(ref.identifier, newName));
|
|
1886
|
+
});
|
|
1887
|
+
|
|
1888
|
+
return fixes;
|
|
1889
|
+
},
|
|
1890
|
+
message: `Function "${name}" should end with "Handler" suffix (e.g., ${newName})`,
|
|
1891
|
+
node: identifierNode,
|
|
1778
1892
|
});
|
|
1779
1893
|
}
|
|
1780
1894
|
};
|
|
@@ -1787,6 +1901,7 @@ const functionNamingConvention = {
|
|
|
1787
1901
|
},
|
|
1788
1902
|
meta: {
|
|
1789
1903
|
docs: { description: "Enforce function names to start with a verb AND end with Handler" },
|
|
1904
|
+
fixable: "code",
|
|
1790
1905
|
schema: [],
|
|
1791
1906
|
type: "suggestion",
|
|
1792
1907
|
},
|
|
@@ -3113,13 +3228,13 @@ const multilineIfConditions = {
|
|
|
3113
3228
|
* folder-level index files.
|
|
3114
3229
|
*
|
|
3115
3230
|
* Options:
|
|
3116
|
-
* - aliasPrefix: string (default: "@/") -
|
|
3117
|
-
* - extraAllowedFolders: string[] -
|
|
3118
|
-
* - extraReduxSubfolders: string[] -
|
|
3119
|
-
* - extraDeepImportFolders: string[] -
|
|
3120
|
-
* - allowedFolders: string[] -
|
|
3121
|
-
* - reduxSubfolders: string[] -
|
|
3122
|
-
* - deepImportFolders: string[] -
|
|
3231
|
+
* - aliasPrefix: string (default: "@/") - Change path alias prefix if your project uses something other than @/ (e.g., ~/, src/)
|
|
3232
|
+
* - extraAllowedFolders: string[] - Add custom folders that can be imported with @/folder. Extends defaults without replacing them
|
|
3233
|
+
* - extraReduxSubfolders: string[] - Add Redux subfolders importable directly (@/selectors) or nested (@/redux/selectors). Default: actions, reducers, store, thunks, types
|
|
3234
|
+
* - extraDeepImportFolders: string[] - Add folders where direct file imports are allowed (@/assets/images/logo.svg). Use for folders without index files. Default: assets
|
|
3235
|
+
* - allowedFolders: string[] - Completely replace the default allowed folders list. Use only if you need full control
|
|
3236
|
+
* - reduxSubfolders: string[] - Completely replace the default Redux subfolders list
|
|
3237
|
+
* - deepImportFolders: string[] - Completely replace the default deep import folders list
|
|
3123
3238
|
*
|
|
3124
3239
|
* ✓ Good:
|
|
3125
3240
|
* import { Button } from "@/components";
|
|
@@ -3131,7 +3246,7 @@ const multilineIfConditions = {
|
|
|
3131
3246
|
*
|
|
3132
3247
|
* Configuration Example:
|
|
3133
3248
|
* "code-style/absolute-imports-only": ["error", {
|
|
3134
|
-
* extraAllowedFolders: ["features", "modules"
|
|
3249
|
+
* extraAllowedFolders: ["features", "modules"],
|
|
3135
3250
|
* extraDeepImportFolders: ["images", "fonts"]
|
|
3136
3251
|
* }]
|
|
3137
3252
|
*/
|
|
@@ -3170,6 +3285,7 @@ const absoluteImportsOnly = {
|
|
|
3170
3285
|
"layouts",
|
|
3171
3286
|
"lib",
|
|
3172
3287
|
"middlewares",
|
|
3288
|
+
"pages",
|
|
3173
3289
|
"providers",
|
|
3174
3290
|
"reducers",
|
|
3175
3291
|
"redux",
|
|
@@ -3216,10 +3332,14 @@ const absoluteImportsOnly = {
|
|
|
3216
3332
|
// for re-exporting their contents
|
|
3217
3333
|
const isIndexFile = /\/index\.(js|jsx|ts|tsx)$/.test(normalizedFilename);
|
|
3218
3334
|
|
|
3335
|
+
// Check if this is an entry file (main.tsx, main.ts, etc.) - entry files are allowed
|
|
3336
|
+
// to use relative imports for app root and styles (e.g., ./index.css, ./app)
|
|
3337
|
+
const isEntryFile = /\/main\.(js|jsx|ts|tsx)$/.test(normalizedFilename);
|
|
3338
|
+
|
|
3219
3339
|
// 1. Disallow relative imports (starting with ./ or ../)
|
|
3220
3340
|
// EXCEPT in index files which need relative imports for re-exports
|
|
3221
3341
|
if (importPath.startsWith("./") || importPath.startsWith("../")) {
|
|
3222
|
-
if (!isIndexFile) {
|
|
3342
|
+
if (!isIndexFile && !isEntryFile) {
|
|
3223
3343
|
context.report({
|
|
3224
3344
|
message: `Relative imports are not allowed. Use absolute imports with "${aliasPrefix}" prefix instead.`,
|
|
3225
3345
|
node: node.source,
|
|
@@ -3780,12 +3900,12 @@ const importSourceSpacing = {
|
|
|
3780
3900
|
* subfolders and files in the module.
|
|
3781
3901
|
*
|
|
3782
3902
|
* Options:
|
|
3783
|
-
* - extraModuleFolders: string[] -
|
|
3784
|
-
* - extraLazyLoadFolders: string[] -
|
|
3785
|
-
* - extraIgnorePatterns: string[] -
|
|
3786
|
-
* - moduleFolders: string[] -
|
|
3787
|
-
* - lazyLoadFolders: string[] -
|
|
3788
|
-
* - ignorePatterns: string[] -
|
|
3903
|
+
* - extraModuleFolders: string[] - Add folders that should have an index.js re-exporting all public files. Use for project-specific folders like features/, modules/
|
|
3904
|
+
* - extraLazyLoadFolders: string[] - Add folders exempt from index file requirements. Use for route/page components loaded via dynamic import(). Default: pages, views
|
|
3905
|
+
* - extraIgnorePatterns: string[] - Add file patterns to skip when checking for index exports. Supports wildcards like *.stories.js, *.mock.js
|
|
3906
|
+
* - moduleFolders: string[] - Completely replace the default module folders list. Use only if you need full control
|
|
3907
|
+
* - lazyLoadFolders: string[] - Completely replace the default lazy load folders list
|
|
3908
|
+
* - ignorePatterns: string[] - Completely replace the default ignore patterns list
|
|
3789
3909
|
*
|
|
3790
3910
|
* ✓ Good:
|
|
3791
3911
|
* // index.js
|
|
@@ -3797,8 +3917,8 @@ const importSourceSpacing = {
|
|
|
3797
3917
|
*
|
|
3798
3918
|
* Configuration Example:
|
|
3799
3919
|
* "code-style/module-index-exports": ["error", {
|
|
3800
|
-
* extraModuleFolders: ["features", "modules"
|
|
3801
|
-
* extraLazyLoadFolders: ["
|
|
3920
|
+
* extraModuleFolders: ["features", "modules"],
|
|
3921
|
+
* extraLazyLoadFolders: ["screens"],
|
|
3802
3922
|
* extraIgnorePatterns: ["*.stories.js", "*.mock.js"]
|
|
3803
3923
|
* }]
|
|
3804
3924
|
*/
|
|
@@ -3829,6 +3949,7 @@ const moduleIndexExports = {
|
|
|
3829
3949
|
"layouts",
|
|
3830
3950
|
"lib",
|
|
3831
3951
|
"middlewares",
|
|
3952
|
+
"pages",
|
|
3832
3953
|
"providers",
|
|
3833
3954
|
"reducers",
|
|
3834
3955
|
"redux",
|
|
@@ -3853,7 +3974,7 @@ const moduleIndexExports = {
|
|
|
3853
3974
|
|| [...defaultModuleFolders, ...(options.extraModuleFolders || [])];
|
|
3854
3975
|
|
|
3855
3976
|
// Default lazy load folders
|
|
3856
|
-
const defaultLazyLoadFolders = ["views"];
|
|
3977
|
+
const defaultLazyLoadFolders = ["pages", "views"];
|
|
3857
3978
|
|
|
3858
3979
|
// Folders that use lazy loading and shouldn't require index exports
|
|
3859
3980
|
// These folders typically have components loaded via dynamic import()
|
|
@@ -14184,6 +14305,7 @@ export default {
|
|
|
14184
14305
|
|
|
14185
14306
|
// Function rules
|
|
14186
14307
|
"function-call-spacing": functionCallSpacing,
|
|
14308
|
+
"function-declaration-style": functionDeclarationStyle,
|
|
14187
14309
|
"function-naming-convention": functionNamingConvention,
|
|
14188
14310
|
"function-object-destructure": functionObjectDestructure,
|
|
14189
14311
|
"function-params-per-line": functionParamsPerLine,
|
package/package.json
CHANGED