eslint-plugin-code-style 1.14.3 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md ADDED
@@ -0,0 +1,1358 @@
1
+ # AGENTS.md
2
+
3
+ Instructions for AI coding agents working with this codebase.
4
+
5
+ ## Project Overview
6
+
7
+ **eslint-plugin-code-style** is an ESLint plugin providing 79 custom formatting rules (70 auto-fixable, 19 configurable, 9 report-only) for React/JSX projects. It's designed for ESLint v9+ flat config system.
8
+
9
+ - **Main entry:** `index.js` - Contains all 79 rules in a single file
10
+ - **Type definitions:** `index.d.ts` - TypeScript declarations for IDE support
11
+ - **Recommended configs:** `recommended-configs/` - Ready-to-use ESLint configurations
12
+ - **Test apps:** `_tests_/` - Sample apps for testing rules
13
+
14
+ ### Available Configurations
15
+
16
+ | Config | Recommended Folder | Test Folder | Status |
17
+ |--------|-------------------|-------------|--------|
18
+ | React (JS) | `recommended-configs/react/` | `_tests_/react/` | Available |
19
+ | React + TS + Tailwind | `recommended-configs/react-ts-tw/` | `_tests_/react-ts-tw/` | Available |
20
+ | React + TypeScript | - | - | Coming Soon |
21
+ | React + Tailwind | - | - | Coming Soon |
22
+
23
+ ### Test Projects & Rule Compatibility
24
+
25
+ **IMPORTANT:** When adding/editing rules, they must be tested in ALL applicable test projects.
26
+
27
+ Each test project in `_tests_/` corresponds to a specific tech stack. Rules should ONLY be added to projects that support them:
28
+
29
+ | Rule Category | `react/` (JS only) | `react-ts-tw/` (TS + Tailwind) | Future: `react-ts/` | Future: `react-tw/` |
30
+ |---------------|:------------------:|:------------------------------:|:-------------------:|:-------------------:|
31
+ | **General rules** (arrays, functions, etc.) | ✅ | ✅ | ✅ | ✅ |
32
+ | **JSX/React rules** | ✅ | ✅ | ✅ | ✅ |
33
+ | **TypeScript rules** | ❌ | ✅ | ✅ | ❌ |
34
+ | **Tailwind rules** | ❌ | ✅ | ❌ | ✅ |
35
+
36
+ **TypeScript-only rules** (71 rules in JS projects, 79 in TS projects):
37
+ - `component-props-inline-type`
38
+ - `enum-format`
39
+ - `interface-format`
40
+ - `no-inline-type-definitions`
41
+ - `prop-naming-convention`
42
+ - `type-annotation-spacing`
43
+ - `type-format`
44
+ - `typescript-definition-location`
45
+
46
+ **Tailwind-related rules** (work in all projects but most useful with Tailwind):
47
+ - `classname-dynamic-at-end` - Enforce dynamic expressions at end of className
48
+ - `classname-multiline` - Format long className strings with one class per line
49
+ - `classname-no-extra-spaces` - Remove extra/leading/trailing spaces in className
50
+ - `classname-order` - Enforce Tailwind CSS class ordering in variables, object properties, and return statements
51
+
52
+ > **Note:** `classname-order` complements the official `tailwindcss/classnames-order` plugin:
53
+ > - **`tailwindcss/classnames-order`** - Handles JSX `className` attributes directly
54
+ > - **`classname-order`** - Handles class strings in variables, object properties, and return statements (areas the Tailwind plugin doesn't cover)
55
+ >
56
+ > Both rules should be enabled together for complete Tailwind class ordering coverage.
57
+
58
+ **When adding a new test project:**
59
+ 1. Create folder: `_tests_/<project-name>/`
60
+ 2. Copy structure from similar existing project
61
+ 3. Create `eslint.config.js` with appropriate rules for that stack
62
+ 4. Add ALL applicable rules (skip rules for unsupported tech)
63
+ 5. Update this table in AGENTS.md
64
+ 6. Update "Available Configurations" table above
65
+
66
+ ## Build & Test Commands
67
+
68
+ ```bash
69
+ # No build step required - plain JavaScript ES modules
70
+
71
+ # Test rules against a test app (e.g., react, react-ts, react-ts-tw)
72
+ cd _tests_/<config-name>
73
+ npm install
74
+ npm run lint # Check for errors
75
+ npm run lint:fix # Auto-fix issues
76
+
77
+ # Publish (from root folder only)
78
+ npm publish
79
+ ```
80
+
81
+ ## Code Structure
82
+
83
+ All rules are defined in `index.js` with this structure:
84
+
85
+ ```
86
+ index.js
87
+ ├── imports (fs, path, url)
88
+ ├── Rule 1 definition (const ruleName = { create(), meta: {} })
89
+ ├── Rule 2 definition
90
+ ├── ... (79 rules total)
91
+ └── export default { meta: {}, rules: {} }
92
+ ```
93
+
94
+ ## Rule Implementation Pattern
95
+
96
+ Every rule follows this exact structure:
97
+
98
+ ```javascript
99
+ /**
100
+ * ───────────────────────────────────────────────────────────────
101
+ * Rule: Rule Name Here
102
+ * ───────────────────────────────────────────────────────────────
103
+ *
104
+ * Description:
105
+ * Brief description of what the rule does.
106
+ *
107
+ * Options:
108
+ * { optionName: defaultValue } - Description of option
109
+ *
110
+ * ✓ Good:
111
+ * // Example of correct code
112
+ *
113
+ * ✗ Bad:
114
+ * // Example of incorrect code
115
+ */
116
+ const ruleName = {
117
+ create(context) {
118
+ const sourceCode = context.sourceCode || context.getSourceCode();
119
+ const options = context.options[0] || {};
120
+ const optionName = options.optionName !== undefined ? options.optionName : defaultValue;
121
+
122
+ return {
123
+ NodeType(node) {
124
+ // Rule logic here
125
+
126
+ // Report issues with auto-fix
127
+ context.report({
128
+ fix: (fixer) => fixer.replaceText(node, "fixed code"),
129
+ message: "Error message describing the issue",
130
+ node,
131
+ });
132
+ },
133
+ };
134
+ },
135
+ meta: {
136
+ docs: { description: "Short description for documentation" },
137
+ fixable: "code", // Required for auto-fix rules
138
+ schema: [
139
+ {
140
+ additionalProperties: false,
141
+ properties: {
142
+ optionName: {
143
+ default: 3,
144
+ description: "Option description",
145
+ minimum: 1,
146
+ type: "integer",
147
+ },
148
+ },
149
+ type: "object",
150
+ },
151
+ ],
152
+ type: "layout", // "layout" for formatting, "suggestion" for conventions
153
+ },
154
+ };
155
+ ```
156
+
157
+ ### Adding a New Rule — Complete Checklist
158
+
159
+ **IMPORTANT:** Adding a new rule requires a **MINOR version bump** (e.g., 1.5.0 → 1.6.0).
160
+
161
+ When creating a new rule, ALL of the following files must be updated:
162
+
163
+ #### 1. `index.js` — Rule Implementation
164
+
165
+ - [ ] Add JSDoc comment block with the standard format:
166
+ ```javascript
167
+ /**
168
+ * ───────────────────────────────────────────────────────────────
169
+ * Rule: Rule Name Here
170
+ * ───────────────────────────────────────────────────────────────
171
+ *
172
+ * Description:
173
+ * Brief description of what the rule does.
174
+ *
175
+ * ✓ Good:
176
+ * // Example of correct code
177
+ *
178
+ * ✗ Bad:
179
+ * // Example of incorrect code
180
+ */
181
+ ```
182
+ - [ ] Add `const ruleName = { create(), meta: {} }` definition
183
+ - [ ] Include `fixable: "code"` or `fixable: "whitespace"` in meta if auto-fixable
184
+ - [ ] Add to `rules` object in default export (keep **alphabetical order**)
185
+
186
+ #### 2. `index.d.ts` — TypeScript Types
187
+
188
+ - [ ] Add rule name to `RuleNames` type union (**alphabetically sorted**):
189
+ ```typescript
190
+ | "code-style/new-rule-name"
191
+ ```
192
+ - [ ] Add rule to `PluginRules` interface (**alphabetically sorted**):
193
+ ```typescript
194
+ "new-rule-name": Rule.RuleModule;
195
+ ```
196
+
197
+ #### 3. `README.md` — Main Documentation
198
+
199
+ > ⚠️ **IMPORTANT:** README.md has **four separate sections** that mention rules. When adding or editing a rule, you must update ALL relevant sections:
200
+ > - **Rule counts** (6 locations) — must match actual rule count
201
+ > - **Quick Start example** (~line 184) — alphabetically sorted configuration example
202
+ > - **Rules Summary table** — brief description with emoji indicators
203
+ > - **Detailed documentation** — full examples, options, and explanations
204
+ >
205
+ > Missing any section will leave documentation inconsistent. Use the `audit-docs` skill to verify all sections are in sync.
206
+
207
+ **a) Update rule counts** (see [Rule Count Locations](#rule-count-locations) for all positions):
208
+ - [ ] Line ~22: `*XX rules (YY auto-fixable)*`
209
+ - [ ] Line ~30: `**XX custom rules** (YY auto-fixable)`
210
+ - [ ] Line ~39: `YY of XX rules support auto-fix`
211
+ - [ ] Line ~100: `**YY rules** support automatic fixing`
212
+ - [ ] Line ~254: `**XX rules total** — YY with auto-fix`
213
+ - [ ] Line ~3037: `YY of XX rules support auto-fixing`
214
+
215
+ **b) Add rule to Quick Start example** (~line 184, alphabetically sorted):
216
+ ```javascript
217
+ "code-style/new-rule-name": "error",
218
+ ```
219
+
220
+ **c) Add rule to Rules Summary table** (find the appropriate category):
221
+ ```markdown
222
+ | `new-rule-name` | Brief description of what it does 🔧 |
223
+ ```
224
+ - Add 🔧 emoji if auto-fixable
225
+ - Add ⚙️ emoji if has configurable options
226
+
227
+ **d) Add detailed rule documentation section** (in appropriate category section):
228
+ ```markdown
229
+ ### `new-rule-name`
230
+
231
+ **What it does:** One-line description of the rule's purpose.
232
+
233
+ **Why use it:** Context for why this rule is helpful (optional).
234
+
235
+ \`\`\`javascript
236
+ // ✅ Good — description of correct pattern
237
+ const example = "correct code";
238
+
239
+ // ✅ Good — another correct example
240
+ const another = "also correct";
241
+
242
+ // ❌ Bad — description of incorrect pattern
243
+ const example = "incorrect code";
244
+
245
+ // ❌ Bad — another incorrect example
246
+ const wrong = "also wrong";
247
+ \`\`\`
248
+
249
+ **Options:** (only if rule has options)
250
+
251
+ | Option | Type | Default | Description |
252
+ |--------|------|---------|-------------|
253
+ | `optionName` | `string` | `"value"` | What the option does |
254
+
255
+ \`\`\`javascript
256
+ // Configuration example
257
+ "code-style/new-rule-name": ["error", { optionName: "value" }]
258
+ \`\`\`
259
+
260
+ ---
261
+ ```
262
+
263
+ #### 4. `AGENTS.md` — Agent Instructions
264
+
265
+ - [ ] Update rule counts in [Rule Count Locations](#rule-count-locations) section (Current Counts table)
266
+ - [ ] Update all rule count references (see table in Rule Count Locations)
267
+ - [ ] Add rule to its category in [Rule Categories](#rule-categories) section
268
+
269
+ #### 5. Config Files — Add Rule to Configs
270
+
271
+ Add the rule (**alphabetically sorted**) to ALL config files:
272
+
273
+ - [ ] `recommended-configs/react-ts-tw/eslint.config.js`
274
+ - [ ] `recommended-configs/react/eslint.config.js` (skip if TypeScript-only rule)
275
+ - [ ] `_tests_/react-ts-tw/eslint.config.js`
276
+ - [ ] `_tests_/react/eslint.config.js` (skip if TypeScript-only rule)
277
+
278
+ **TypeScript-only rules** (only add to `-ts-tw` configs):
279
+ - `component-props-inline-type`, `enum-format`, `interface-format`
280
+ - `no-inline-type-definitions`, `type-annotation-spacing`, `type-format`
281
+ - `typescript-definition-location`
282
+
283
+ #### 6. Config READMEs — Update Rule Counts
284
+
285
+ - [ ] `recommended-configs/react-ts-tw/README.md` (~line 396)
286
+ - [ ] `recommended-configs/react/README.md` (~line 286)
287
+
288
+ #### 7. Version & Tag
289
+
290
+ - [ ] Update `package.json` version (MINOR bump: x.Y.0)
291
+ - [ ] Commit with message: `feat: add rule-name rule`
292
+ - [ ] Create tag: `git tag vX.Y.0`
293
+
294
+ #### 8. Testing the Rule
295
+
296
+ **IMPORTANT:** Every new rule MUST be tested before committing.
297
+
298
+ **a) Add examples to existing test project code:**
299
+
300
+ The test projects (`_tests_/react/`, `_tests_/react-ts-tw/`, etc.) contain real code (components, hooks, utils, etc.) that should naturally exercise all rules. When adding a new rule:
301
+
302
+ - Add code examples to **existing files** in the test project that are relevant to the rule
303
+ - For example: if adding an array rule, add array code to existing component files
304
+ - The test project code should cover ALL rules through its natural structure
305
+
306
+ ```
307
+ _tests_/react-ts-tw/src/
308
+ ├── app.tsx # Main app - exercises component rules
309
+ ├── components/ # Components - exercises JSX, props rules
310
+ │ ├── button.tsx
311
+ │ └── card.tsx
312
+ ├── hooks/ # Hooks - exercises hook rules
313
+ ├── utils/ # Utils - exercises function rules
314
+ ├── interfaces/ # Interfaces - exercises TS rules
315
+ └── types/ # Types - exercises type rules
316
+ ```
317
+
318
+ **b) Create temporary test file for quick verification:**
319
+
320
+ For quick testing during development, create a temporary test file:
321
+
322
+ ```bash
323
+ # Create temp test file
324
+ _tests_/react-ts-tw/src/test-rule-name.tsx
325
+ ```
326
+
327
+ ```javascript
328
+ // Temporary test file: test-rule-name.tsx
329
+
330
+ // Test case 1: Should trigger error (BAD code)
331
+ const badExample = /* code that violates the rule */;
332
+
333
+ // Test case 2: Should NOT trigger error (GOOD code)
334
+ const goodExample = /* code that follows the rule */;
335
+ ```
336
+
337
+ **c) Run the linter to verify:**
338
+
339
+ ```bash
340
+ cd _tests_/react-ts-tw
341
+
342
+ # Check errors are reported for bad code
343
+ npx eslint src/test-rule-name.tsx
344
+
345
+ # Verify auto-fix works (if rule is fixable)
346
+ npx eslint src/test-rule-name.tsx --fix
347
+ cat src/test-rule-name.tsx # Verify fixed code is correct
348
+
349
+ # Also run on entire project to ensure no regressions
350
+ npx eslint src/
351
+ ```
352
+
353
+ **d) Clean up temporary test file:**
354
+
355
+ ```bash
356
+ rm _tests_/react-ts-tw/src/test-rule-name.tsx
357
+ rm _tests_/react/src/test-rule-name.jsx # if created
358
+ ```
359
+
360
+ **e) Ensure test project code covers the new rule:**
361
+
362
+ After temporary testing, make sure the actual test project code (components, hooks, etc.) includes examples that exercise the new rule. This provides ongoing regression testing.
363
+
364
+ #### 9. Verification
365
+
366
+ Run these commands to verify all rules are in sync:
367
+
368
+ ```bash
369
+ # Count rules in each location
370
+ grep -c "^const [a-zA-Z]* = {$" index.js
371
+ grep -c 'code-style/' index.d.ts
372
+ grep -c '"code-style/' recommended-configs/react-ts-tw/eslint.config.js
373
+
374
+ # Find rules missing from README
375
+ grep -oE '"[a-z-]+":' index.js | tr -d '":' | sort > /tmp/a.txt
376
+ grep -oE '\`[a-z-]+\`' README.md | tr -d '\`' | sort | uniq > /tmp/b.txt
377
+ comm -23 /tmp/a.txt /tmp/b.txt
378
+ ```
379
+
380
+ ---
381
+
382
+ ### Removing a Rule — Complete Checklist
383
+
384
+ **IMPORTANT:** Removing a rule is a **BREAKING CHANGE** requiring a **MAJOR version bump** (e.g., 1.6.0 → 2.0.0).
385
+
386
+ #### 1. `index.js`
387
+ - [ ] Remove the rule's JSDoc comment block
388
+ - [ ] Remove the `const ruleName = { ... }` definition
389
+ - [ ] Remove from `rules` object in default export
390
+
391
+ #### 2. `index.d.ts`
392
+ - [ ] Remove from `RuleNames` type union
393
+ - [ ] Remove from `PluginRules` interface
394
+
395
+ #### 3. `README.md` (all four sections)
396
+ - [ ] Update all rule counts (see [Rule Count Locations](#rule-count-locations))
397
+ - [ ] Remove from `rules: {}` example in Quick Start
398
+ - [ ] Remove from Rules Summary table
399
+ - [ ] Remove detailed documentation section
400
+
401
+ #### 4. `AGENTS.md`
402
+ - [ ] Update all rule counts
403
+ - [ ] Remove from Rule Categories section
404
+
405
+ #### 5. Config Files
406
+ - [ ] Remove from `recommended-configs/react-ts-tw/eslint.config.js`
407
+ - [ ] Remove from `recommended-configs/react/eslint.config.js`
408
+ - [ ] Remove from `_tests_/react-ts-tw/eslint.config.js`
409
+ - [ ] Remove from `_tests_/react/eslint.config.js`
410
+
411
+ #### 6. Config READMEs
412
+ - [ ] Update `recommended-configs/react-ts-tw/README.md`
413
+ - [ ] Update `recommended-configs/react/README.md`
414
+
415
+ #### 7. Version & Tag
416
+ - [ ] Update `package.json` version (MAJOR bump: X.0.0)
417
+ - [ ] Commit with message: `feat!: remove rule-name rule` (note the `!` for breaking change)
418
+ - [ ] Create tag: `git tag vX.0.0`
419
+
420
+ ---
421
+
422
+ ### Editing an Existing Rule — Checklist
423
+
424
+ When modifying an existing rule, check if these need updates:
425
+
426
+ > ⚠️ **README.md Reminder:** If the rule's behavior, examples, or options change, remember that README.md has multiple sections to update (Quick Start example, Rules Summary table, detailed documentation). See the note in "Adding a New Rule" section for details.
427
+
428
+ #### If fixing a bug (PATCH version: x.x.+1):
429
+ - [ ] Fix the issue in rule's `create()` function in `index.js`
430
+ - [ ] Test in `_tests_/` apps with `npm run lint` and `npm run lint:fix`
431
+ - [ ] Commit: `fix: description of what was fixed in rule-name`
432
+
433
+ #### If changing rule behavior (PATCH or MINOR depending on scope):
434
+ - [ ] Update rule logic in `index.js`
435
+ - [ ] Update JSDoc in `index.js` (Good/Bad examples if they changed)
436
+ - [ ] Update `README.md` rule documentation section:
437
+ - Update "What it does" if behavior changed
438
+ - Update code examples (✅ Good / ❌ Bad) to reflect new behavior
439
+ - [ ] Test in `_tests_/` apps with `npm run lint` and `npm run lint:fix`
440
+
441
+ #### If adding new options (MINOR version: x.+1.0):
442
+ - [ ] Add option to `schema` in rule's `meta` object in `index.js`
443
+ - [ ] Add option handling in `create()` function with default value:
444
+ ```javascript
445
+ const options = context.options[0] || {};
446
+ const newOption = options.newOption !== undefined ? options.newOption : defaultValue;
447
+ ```
448
+ - [ ] Update JSDoc Options section in `index.js`
449
+ - [ ] Update README.md rule documentation:
450
+ - Add row to Options table
451
+ - Add configuration example showing the new option
452
+
453
+ #### If adding auto-fix to rule that didn't have it (MINOR version: x.+1.0):
454
+ - [ ] Add `fixable: "code"` or `fixable: "whitespace"` to rule's `meta` object
455
+ - [ ] Add `fix()` function in `context.report()`:
456
+ ```javascript
457
+ context.report({
458
+ fix: (fixer) => fixer.replaceText(node, "fixed code"),
459
+ message: "Error message",
460
+ node,
461
+ });
462
+ ```
463
+ - [ ] Update README.md Rules Summary table: add 🔧 emoji
464
+ - [ ] Update rule counts: increment auto-fixable count, decrement report-only count
465
+ - [ ] Test auto-fix with `npm run lint:fix`
466
+
467
+ #### If changing default values (MAJOR version: +1.0.0 — breaking change):
468
+ - [ ] Update default value in `create()` function
469
+ - [ ] Update JSDoc in `index.js`
470
+ - [ ] Update README.md options table (Default column)
471
+ - [ ] Commit with `!`: `feat!: change default value for rule-name option`
472
+
473
+ #### Testing After Any Edit
474
+
475
+ **IMPORTANT:** Always test rule changes before committing.
476
+
477
+ 1. **Create a temporary test file** for quick verification:
478
+ ```bash
479
+ # Create in appropriate project(s)
480
+ _tests_/react-ts-tw/src/test-rule-name.tsx # For TS rules
481
+ _tests_/react/src/test-rule-name.jsx # For general rules (test in both)
482
+ ```
483
+
484
+ 2. **Add test cases:**
485
+ ```javascript
486
+ // Temporary test file
487
+
488
+ // Should trigger the rule (BAD - test this fails)
489
+ const badCode = /* code that should fail */;
490
+
491
+ // Should pass (GOOD - test this passes)
492
+ const goodCode = /* code that should pass */;
493
+ ```
494
+
495
+ 3. **Run tests:**
496
+ ```bash
497
+ cd _tests_/react-ts-tw
498
+ npx eslint src/test-rule-name.tsx # Verify error is reported
499
+ npx eslint src/test-rule-name.tsx --fix # Verify auto-fix works
500
+ npx eslint src/ # Ensure no regressions
501
+ ```
502
+
503
+ 4. **Clean up temporary test file:**
504
+ ```bash
505
+ rm _tests_/react-ts-tw/src/test-rule-name.tsx
506
+ rm _tests_/react/src/test-rule-name.jsx # if created
507
+ ```
508
+
509
+ 5. **Ensure test project code covers the change:**
510
+ - Update existing code in test project (components, hooks, etc.) if needed
511
+ - The test project should naturally exercise the edited rule behavior
512
+
513
+ #### Version Bump After Edits
514
+
515
+ **IMPORTANT:** Every commit requires a version bump and tag. After committing your changes:
516
+
517
+ 1. Bump version in `package.json` (PATCH for fixes, MINOR for new features)
518
+ 2. Update `CHANGELOG.md`:
519
+ - Add new version entry at the top
520
+ - Add comparison link at the bottom: `[X.Y.Z]: https://github.com/.../compare/vPREV...vX.Y.Z`
521
+ 3. Commit: `chore: bump version to X.Y.Z`
522
+ 4. Create tag: `git tag -a vX.Y.Z -m "vX.Y.Z - description"`
523
+ 5. Push: `git push origin main --tags`
524
+
525
+ See "When to Bump Version & Create Tag" section in Git Workflow for details.
526
+
527
+ ---
528
+
529
+ ### Rule Documentation Format in README.md
530
+
531
+ Each rule should have this format in the Rules Reference section:
532
+
533
+ ```markdown
534
+ ### `rule-name`
535
+
536
+ **What it does:** One-line description of the rule's purpose.
537
+
538
+ **Why use it:** Optional context for why this rule is helpful.
539
+
540
+ > **Note:** Any special notes or dependencies (optional).
541
+
542
+ \`\`\`javascript
543
+ // ✅ Good — description
544
+ const example = "correct code";
545
+
546
+ // ❌ Bad — description
547
+ const example = "incorrect code";
548
+ \`\`\`
549
+
550
+ **Options:** (if rule has options)
551
+
552
+ | Option | Type | Default | Description |
553
+ |--------|------|---------|-------------|
554
+ | `optionName` | `string` | `"value"` | What the option does |
555
+
556
+ \`\`\`javascript
557
+ // Configuration example
558
+ "code-style/rule-name": ["error", { optionName: "value" }]
559
+ \`\`\`
560
+
561
+ ---
562
+ ```
563
+
564
+ ## Key Patterns & Conventions
565
+
566
+ ### Source Code Access
567
+ ```javascript
568
+ const sourceCode = context.sourceCode || context.getSourceCode();
569
+ ```
570
+
571
+ ### Options with Defaults
572
+ ```javascript
573
+ const options = context.options[0] || {};
574
+ const maxItems = options.maxItems !== undefined ? options.maxItems : 3;
575
+ ```
576
+
577
+ ### Getting Tokens
578
+ ```javascript
579
+ const openBracket = sourceCode.getFirstToken(node);
580
+ const closeBracket = sourceCode.getLastToken(node);
581
+ const tokenBefore = sourceCode.getTokenBefore(node);
582
+ const tokenAfter = sourceCode.getTokenAfter(node);
583
+ ```
584
+
585
+ ### Getting Text
586
+ ```javascript
587
+ const text = sourceCode.getText(node);
588
+ const lines = sourceCode.lines; // Array of all lines
589
+ ```
590
+
591
+ ### Indentation Calculation
592
+ ```javascript
593
+ const lineText = sourceCode.lines[node.loc.start.line - 1];
594
+ const baseIndent = lineText.match(/^\s*/)[0];
595
+ const itemIndent = baseIndent + " "; // 4 spaces
596
+ ```
597
+
598
+ ### Fixer Methods
599
+ ```javascript
600
+ fixer.replaceText(node, "new text")
601
+ fixer.replaceTextRange([start, end], "new text")
602
+ fixer.insertTextBefore(node, "text")
603
+ fixer.insertTextAfter(node, "text")
604
+ fixer.remove(node)
605
+ fixer.removeRange([start, end])
606
+ ```
607
+
608
+ ### Common Node Type Checks
609
+ ```javascript
610
+ // Check parent type
611
+ if (node.parent && node.parent.type === "Property") { }
612
+
613
+ // Check for specific patterns
614
+ if (node.type === "ArrowFunctionExpression") { }
615
+ if (node.type === "JSXElement") { }
616
+ if (node.type === "ObjectExpression") { }
617
+
618
+ // React hooks detection
619
+ if (/^use[A-Z]/.test(node.callee.name)) { }
620
+ ```
621
+
622
+ ### Skip Conditions (Common Patterns)
623
+ ```javascript
624
+ // Skip empty structures
625
+ if (elements.length === 0) return;
626
+
627
+ // Skip complex elements
628
+ const hasComplexElement = elements.some((el) =>
629
+ el.type === "SpreadElement" ||
630
+ el.type === "ObjectExpression" ||
631
+ el.type === "ArrowFunctionExpression"
632
+ );
633
+ if (hasComplexElement) return;
634
+
635
+ // Skip specific parent contexts
636
+ if (node.parent?.type === "CallExpression") return;
637
+ ```
638
+
639
+ ## Rule Categories
640
+
641
+ Rules are organized in these categories (alphabetically sorted in index.js and README.md):
642
+
643
+ - **Array Rules** — Rules for array formatting
644
+ - `array-callback-destructure`, `array-items-per-line`, `array-objects-on-new-lines`
645
+ - **Arrow Function Rules** — Arrow function syntax and style
646
+ - `arrow-function-block-body`, `arrow-function-simple-jsx`, `arrow-function-simplify`, `curried-arrow-same-line`
647
+ - **Call Expression Rules** — Function call formatting
648
+ - `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`
649
+ - **Class Rules** — Class and method definition formatting
650
+ - `class-method-definition-format`, `class-naming-convention`
651
+ - **Comment Rules** — Comment formatting
652
+ - `comment-format`
653
+ - **Component Rules** — React component patterns
654
+ - `component-props-destructure`, `component-props-inline-type`, `folder-based-naming-convention`, `folder-structure-consistency`, `no-redundant-folder-suffix`, `svg-icon-naming-convention`
655
+ - **Control Flow Rules** — if/switch/block statements
656
+ - `block-statement-newlines`, `if-else-spacing`, `if-statement-format`, `multiline-if-conditions`, `no-empty-lines-in-switch-cases`, `ternary-condition-multiline`
657
+ - **Function Rules** — Function declarations and params
658
+ - `function-call-spacing`, `function-declaration-style`, `function-naming-convention`, `function-object-destructure`, `function-params-per-line`, `no-empty-lines-in-function-params`
659
+ - **Hook Rules** — React hooks formatting
660
+ - `hook-callback-format`, `hook-deps-per-line`
661
+ - **Import/Export Rules** — Import/export statements
662
+ - `absolute-imports-only`, `export-format`, `import-format`, `import-source-spacing`, `index-export-style`, `index-exports-only`, `inline-export-declaration`, `module-index-exports`
663
+ - **JSX Rules** — JSX elements and attributes
664
+ - `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`
665
+ - **Object Rules** — Object literal formatting
666
+ - `no-empty-lines-in-objects`, `object-property-per-line`, `object-property-value-brace`, `object-property-value-format`, `string-property-spacing`
667
+ - **React Rules** — React-specific patterns
668
+ - `react-code-order`
669
+ - **Spacing Rules** — General spacing rules
670
+ - `assignment-value-same-line`, `member-expression-bracket-spacing`
671
+ - **TypeScript Rules** — TypeScript-specific rules (TS configs only)
672
+ - `enum-format`, `interface-format`, `no-inline-type-definitions`, `prop-naming-convention`, `type-annotation-spacing`, `type-format`, `typescript-definition-location`
673
+ - **Variable Rules** — Variable declarations and naming
674
+ - `variable-naming-convention`
675
+
676
+ ## Naming Conventions
677
+
678
+ - **Rule names:** kebab-case (e.g., `array-items-per-line`)
679
+ - **Internal variables:** camelCase (e.g., `arrayItemsPerLine`)
680
+ - **Handler functions:** end with `Handler` (e.g., `checkPatternHandler`)
681
+ - **Options:** camelCase (e.g., `maxItems`, `minProperties`)
682
+
683
+ ## Meta Types
684
+
685
+ - `type: "layout"` - Formatting/whitespace rules (most rules)
686
+ - `type: "suggestion"` - Code convention rules (naming conventions)
687
+
688
+ ## Documentation Files
689
+
690
+ - `README.md` - Main documentation with all 79 rules
691
+ - `recommended-configs/<config-name>/README.md` - Config-specific documentation (references main README for rule details)
692
+ - `index.d.ts` - TypeScript types for IDE autocomplete
693
+
694
+ ## Important Notes
695
+
696
+ - Most rules should be auto-fixable (`fixable: "code"` or `fixable: "whitespace"` in meta)
697
+ - Rules that require file creation/movement or architectural decisions may be report-only
698
+ - Currently: 70 auto-fixable rules, 19 configurable rules, 9 report-only rules
699
+ - Use 4-space indentation throughout
700
+ - Object properties in `context.report()` must be alphabetically sorted
701
+ - Keep rules self-sufficient (no dependencies on other ESLint rules)
702
+ - Test with relevant test app in `_tests_/` before publishing
703
+
704
+ ---
705
+
706
+ ## Rule Count Locations
707
+
708
+ **IMPORTANT:** When adding/removing rules, update the rule counts in ALL these locations:
709
+
710
+ ### Current Counts (update these when changing rules)
711
+ - **Total rules:** 79
712
+ - **Auto-fixable:** 70
713
+ - **Configurable:** 19 (rules with ⚙️ that have options)
714
+ - **Report-only:** 9
715
+
716
+ **IMPORTANT:** All counts must be uniform across ALL files. When updating:
717
+ - Total rules, auto-fixable count, configurable count, and report-only count must match everywhere
718
+ - The auto-fixable breakdown (code vs whitespace) in this section must match actual `grep` counts
719
+ - Use the Quick Verification Commands below to verify counts before committing
720
+
721
+ ### Files & Line Numbers to Update
722
+
723
+ | File | Line(s) | What to Update |
724
+ |------|---------|----------------|
725
+ | `README.md` | ~22 | `*79 rules (70 auto-fixable, 19 configurable)*` |
726
+ | `README.md` | ~30 | `**79 custom rules** (70 auto-fixable, 19 configurable)` |
727
+ | `README.md` | ~39 | `70 of 79 rules support auto-fix` |
728
+ | `README.md` | ~100 | `**70 rules** support automatic fixing. **19 rules** have configurable options` |
729
+ | `README.md` | ~266 | `**79 rules total** — 70 with auto-fix, 19 configurable` |
730
+ | `README.md` | ~3650 | `70 of 79 rules support auto-fixing` |
731
+ | `AGENTS.md` | ~7 | `79 custom formatting rules (70 auto-fixable, 19 configurable, 9 report-only)` |
732
+ | `AGENTS.md` | ~9 | `Contains all 79 rules` |
733
+ | `AGENTS.md` | ~36 | `(71 rules in JS projects, 79 in TS projects)` |
734
+ | `AGENTS.md` | ~89 | `(79 rules total)` |
735
+ | `AGENTS.md` | ~675 | `all 79 rules` |
736
+ | `AGENTS.md` | ~697 | `70 auto-fixable rules, 19 configurable rules, 9 report-only` |
737
+ | `AGENTS.md` | Rule Count Locations section | Current Counts table |
738
+ | `recommended-configs/react-ts-tw/README.md` | ~396 | `**70 auto-fixable rules** (79 total, 19 configurable, 9 report-only)` |
739
+ | `recommended-configs/react/README.md` | ~286 | `**70 auto-fixable rules** (79 total, 19 configurable, 9 report-only)` |
740
+
741
+ ### Quick Verification Commands
742
+
743
+ ```bash
744
+ # Count total rules
745
+ grep -c "^const [a-zA-Z]* = {$" index.js
746
+
747
+ # Count auto-fixable (code)
748
+ grep -c 'fixable: "code"' index.js
749
+
750
+ # Count auto-fixable (whitespace)
751
+ grep -c 'fixable: "whitespace"' index.js
752
+
753
+ # Count configurable rules (rules with ⚙️ in README table)
754
+ grep "| \`" README.md | grep -c "⚙️"
755
+
756
+ # Find all rule count mentions (excluding CHANGELOG)
757
+ grep -rn "[0-9][0-9] rules\|[0-9][0-9] auto" --include="*.md" | grep -v CHANGELOG
758
+ ```
759
+
760
+ ---
761
+
762
+ ## Git Workflow
763
+
764
+ ### Commit Message Format
765
+
766
+ Follow [Conventional Commits](https://www.conventionalcommits.org/) specification:
767
+
768
+ ```
769
+ <type>: <subject>
770
+
771
+ [optional body]
772
+ ```
773
+
774
+ **Types:**
775
+ - `feat` - New feature or rule
776
+ - `fix` - Bug fix
777
+ - `docs` - Documentation only changes
778
+ - `refactor` - Code change that neither fixes a bug nor adds a feature
779
+ - `chore` - Maintenance tasks (deps, configs)
780
+
781
+ **Subject line rules:**
782
+ - Use lowercase (except proper nouns)
783
+ - No period at the end
784
+ - Maximum 72 characters
785
+ - Use imperative mood ("add" not "added")
786
+
787
+ **Examples:**
788
+ ```
789
+ feat: add function-declaration-style rule
790
+ fix: allow relative imports in entry files
791
+ docs: update options descriptions
792
+ ```
793
+
794
+ **Multi-feature commits:**
795
+ ```
796
+ feat: add function-declaration-style rule and enhancements
797
+
798
+ New rule:
799
+ - function-declaration-style: auto-fixes to arrow expressions
800
+
801
+ Enhancements:
802
+ - function-naming-convention: add auto-fix
803
+ ```
804
+
805
+ ---
806
+
807
+ ### Versioning (SemVer)
808
+
809
+ Format: `MAJOR.MINOR.PATCH` (e.g., `1.2.8`)
810
+
811
+ | Change Type | Version | Examples |
812
+ |-------------|---------|----------|
813
+ | **PATCH** | `x.x.+1` | Bug fixes, typo corrections, doc updates |
814
+ | **MINOR** | `x.+1.0` | New rules, new features, new options |
815
+ | **MAJOR** | `+1.0.0` | Breaking changes, removed/renamed rules |
816
+
817
+ **Decision guide:**
818
+ - New rule → MINOR
819
+ - Auto-fix to existing rule → MINOR
820
+ - New option → MINOR
821
+ - Bug fix → PATCH
822
+ - Doc update only → PATCH
823
+ - Change default values → MAJOR (breaking)
824
+ - Rename/remove rule → MAJOR (breaking)
825
+
826
+ ---
827
+
828
+ ### When to Bump Version & Create Tag
829
+
830
+ **IMPORTANT:** Every commit requires a version bump and tag. Follow this workflow:
831
+
832
+ #### Commit Workflow (Always Bump Version)
833
+ After every meaningful change:
834
+ 1. Make changes and commit with appropriate message
835
+ 2. Bump version in `package.json`
836
+ 3. Update `CHANGELOG.md`:
837
+ - Add new version entry at the top
838
+ - Add comparison link at the bottom: `[X.Y.Z]: https://github.com/.../compare/vPREV...vX.Y.Z`
839
+ 4. Commit version bump with descriptive message (see below)
840
+ 5. Create annotated tag with descriptive message
841
+ 6. Push commits and tags
842
+
843
+ #### Version Bump Commit Messages
844
+
845
+ **IMPORTANT:** Do NOT use generic messages like `chore: bump version to X.Y.Z`. Instead, use descriptive messages that summarize what changes are in this version.
846
+
847
+ **Format:** `chore: release vX.Y.Z - brief description`
848
+
849
+ **Good examples:**
850
+ ```
851
+ chore: release v1.7.2 - fix double comma bug in enum/interface format
852
+ chore: release v1.7.1 - multiple rule fixes for destructuring and ternaries
853
+ chore: release v1.6.0 - add 3 new rules and enhance ternary formatting
854
+ ```
855
+
856
+ **Bad examples:**
857
+ ```
858
+ chore: bump version to 1.7.2
859
+ chore: version bump
860
+ chore: v1.7.2
861
+ ```
862
+
863
+ This makes `git log` readable and helps understand what each version contains without checking the CHANGELOG.
864
+
865
+ #### Version Bump Rules
866
+ | Change Type | Version Bump | Example | GitHub Release? |
867
+ |-------------|--------------|---------|-----------------|
868
+ | Bug fix | PATCH (+0.0.1) | 1.5.2 → 1.5.3 | No |
869
+ | Enhancement to existing rule | PATCH (+0.0.1) | 1.5.3 → 1.5.4 | No |
870
+ | New rule | MINOR (+0.1.0) | 1.5.4 → 1.6.0 | **Yes** |
871
+ | Breaking change | MAJOR (+1.0.0) | 1.6.0 → 2.0.0 | **Yes** |
872
+ | Docs only | PATCH (+0.0.1) | 1.5.2 → 1.5.3 | No |
873
+
874
+ #### MINOR/MAJOR Release Format (GitHub Releases)
875
+
876
+ When bumping MINOR or MAJOR version, the CHANGELOG entry must follow this format.
877
+
878
+ **IMPORTANT:** The release should contain ALL changes since the **previous RELEASE** (MINOR/MAJOR). The Version Range starts from the first version AFTER the previous release.
879
+
880
+ Example: If releasing v1.7.0 and the previous release was v1.6.0:
881
+ - Version Range: **v1.6.1 → v1.7.0** (starts AFTER v1.6.0)
882
+ - Include changes from: v1.6.1, v1.6.2, ... v1.6.6, AND v1.7.0
883
+
884
+ ```markdown
885
+ ## [X.Y.0] - YYYY-MM-DD
886
+
887
+ **Release Title (Brief Description of Main Features)**
888
+
889
+ **Version Range:** vAfterPreviousRelease → vCurrent
890
+
891
+ ### Added
892
+
893
+ **New Rules (N)**
894
+ - `rule-name` - Description 🔧
895
+
896
+ ### Enhanced
897
+
898
+ - **`rule-name`** - What was enhanced (consolidate all enhancements since last release)
899
+
900
+ ### Fixed
901
+
902
+ - **`rule-name`** - What was fixed (consolidate all fixes since last release)
903
+
904
+ ### Stats
905
+
906
+ - Total Rules: XX (was YY)
907
+ - Auto-fixable: ZZ rules 🔧
908
+ - Report-only: N rules
909
+
910
+ **Full Changelog:** [vAfterPreviousRelease...vCurrent](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/vAfterPreviousRelease...vCurrent)
911
+ ```
912
+
913
+ **Required elements for MINOR/MAJOR releases:**
914
+ 1. **Release title** in bold describing main changes
915
+ 2. **Version Range** showing first version AFTER previous release → current version
916
+ 3. **Consolidated changes** from all versions since last release
917
+ 4. **Stats** section with rule counts
918
+ 5. **Full Changelog** link at the end
919
+
920
+ #### Example Workflow
921
+ ```bash
922
+ # 1. Make changes and commit
923
+ git add .
924
+ git commit -m "fix: handle edge case in rule-name"
925
+
926
+ # 2. Bump version in package.json (1.5.2 → 1.5.3)
927
+ # 3. Update CHANGELOG.md with new entry
928
+
929
+ # 4. Commit version bump with descriptive message
930
+ git add package.json CHANGELOG.md
931
+ git commit -m "chore: release v1.5.3 - fix edge case in rule-name"
932
+
933
+ # 5. Create annotated tag with descriptive message
934
+ git tag -a v1.5.3 -m "v1.5.3 - Fix Edge Case in rule-name
935
+
936
+ - Fixed edge case handling in rule-name
937
+ - Improved error messages"
938
+
939
+ # 6. Push
940
+ git push origin main --tags
941
+ ```
942
+
943
+ ---
944
+
945
+ ### Release Steps
946
+
947
+ 1. **Update version in package.json**
948
+ 2. **Update CHANGELOG.md:**
949
+ - Add new version entry at the top
950
+ - Add comparison link at the bottom: `[X.Y.Z]: https://github.com/.../compare/vPREV...vX.Y.Z`
951
+ 3. **Commit version bump with descriptive message:**
952
+ ```bash
953
+ git commit -m "chore: release v1.2.9 - brief description of changes"
954
+ ```
955
+ 4. **Create annotated tag with descriptive message:**
956
+ ```bash
957
+ git tag -a v1.2.9 -m "v1.2.9 - Brief Description
958
+
959
+ - Feature description 1
960
+ - Feature description 2"
961
+ ```
962
+ 5. **Push (requires explicit approval):** `git push origin main --tags`
963
+ 6. **Publish (requires explicit approval):** `npm publish`
964
+
965
+ ---
966
+
967
+ ### GitHub Releases (Grouped Tags)
968
+
969
+ GitHub Releases group multiple version tags into a single release announcement. Create a release when a significant milestone is reached (new features, major enhancements).
970
+
971
+ **When to create a GitHub Release:**
972
+ - **All MINOR versions (x.Y.0)** - Every new MINOR version is a release
973
+ - **All MAJOR versions (X.0.0)** - Every new MAJOR version is a release
974
+ - Optionally after multiple PATCH versions accumulate significant changes
975
+
976
+ **Note:** All MINOR versions (e.g., v1.7.0, v1.8.0) and MAJOR versions (e.g., v2.0.0) are considered releases and must be added to the "Current releases" list. The Version Range for a release always starts from the first version AFTER the previous release (MINOR or MAJOR) up to the current version.
977
+
978
+ **Release format:**
979
+
980
+ ```markdown
981
+ ## Release Title
982
+ <Short, descriptive title summarizing the main changes>
983
+
984
+ ## Version Range
985
+ vX.X.X → vY.Y.Y
986
+
987
+ ---
988
+
989
+ ## What's New
990
+
991
+ <Brief intro paragraph mentioning key highlights and rule count change>
992
+
993
+ ### New Rules
994
+
995
+ | Rule | Description |
996
+ |------|-------------|
997
+ | `rule-name` | What it does |
998
+
999
+ ### Enhancements
1000
+
1001
+ | Rule | Enhancement |
1002
+ |------|-------------|
1003
+ | `rule-name` | What was improved |
1004
+
1005
+ ### New Features
1006
+
1007
+ - Feature 1 description
1008
+ - Feature 2 description
1009
+
1010
+ ### Bug Fixes
1011
+
1012
+ - Fix 1 description
1013
+ - Fix 2 description
1014
+
1015
+ ### Documentation
1016
+
1017
+ - Doc change 1
1018
+ - Doc change 2
1019
+
1020
+ ## Installation
1021
+
1022
+ \`\`\`bash
1023
+ npm install eslint-plugin-code-style@Y.Y.Y
1024
+ \`\`\`
1025
+
1026
+ ## Stats
1027
+
1028
+ - Total Rules: X (was Y)
1029
+ - All rules are auto-fixable with `eslint --fix`
1030
+
1031
+ **Full Changelog**: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/vX.X.X...vY.Y.Y
1032
+ ```
1033
+
1034
+ **Steps to create a GitHub Release:**
1035
+
1036
+ 1. Go to repository → Releases → "Draft a new release"
1037
+ 2. Choose the latest tag (e.g., `v1.3.0`)
1038
+ 3. Set release title (short, descriptive)
1039
+ 4. Paste the release description following the format above
1040
+ 5. Update `CHANGELOG.md` with the same information
1041
+ 6. Publish release
1042
+
1043
+ ### CHANGELOG.md
1044
+
1045
+ This project follows the [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) standard.
1046
+
1047
+ **IMPORTANT:**
1048
+ - The CHANGELOG must list **ALL version tags** (currently 82 tags)
1049
+ - Update the CHANGELOG with every new tag/release
1050
+ - Keep it in sync with changes as you work
1051
+ - **Releases must match GitHub Releases content exactly**
1052
+
1053
+ #### Two Types of Entries
1054
+
1055
+ **1. Releases** (published to GitHub Releases)
1056
+ - Have **Version Range** showing tags covered
1057
+ - Full detailed sections with sub-categories
1058
+ - Include **Full Changelog** link at the end
1059
+ - Content must match the GitHub Release description
1060
+ - **Current releases:** v1.15.0, v1.14.0, v1.13.0, v1.12.0, v1.11.0, v1.10.0, v1.9.0, v1.8.0, v1.7.0, v1.6.0, v1.5.0, v1.4.2, v1.3.0, v1.2.0, v1.1.0, v1.0.16, v1.0.14, v1.0.7, v1.0.6
1061
+
1062
+ **2. Tags/PATCH versions** (between releases)
1063
+ - Simpler entries with just the changes
1064
+ - **NO title** (bold description line after date)
1065
+ - **NO Version Range**
1066
+ - **NO Full Changelog link** in the entry body
1067
+ - **MUST add link reference** at bottom of CHANGELOG.md: `[X.Y.Z]: https://github.com/.../compare/vA.B.C...vX.Y.Z`
1068
+ - Just `### Fixed`, `### Enhanced`, or other section headers directly
1069
+
1070
+ #### When to Create a Release
1071
+
1072
+ Create a release when:
1073
+ - Adding new rules (MINOR version bump)
1074
+ - Significant feature additions
1075
+ - Major documentation overhauls
1076
+ - Grouping multiple related changes together
1077
+
1078
+ After creating a release:
1079
+ 1. Create the GitHub Release with full description
1080
+ 2. Copy the same content to CHANGELOG.md
1081
+ 3. Add **Full Changelog** link at the end
1082
+ 4. Ensure both match exactly
1083
+
1084
+ #### Release Format
1085
+
1086
+ ```markdown
1087
+ ## [1.4.2] - 2026-01-30
1088
+
1089
+ **New Rules, Enhanced Auto-Fix & Comprehensive Documentation**
1090
+
1091
+ **Version Range:** v1.3.1 → v1.4.2
1092
+
1093
+ ### Added
1094
+
1095
+ **New Rules (3)**
1096
+ - `rule-name` - Description 🔧
1097
+
1098
+ **Feature Category**
1099
+ - Feature description
1100
+
1101
+ ### Enhanced
1102
+
1103
+ - **`rule-name`** - What was improved
1104
+ - **`rule-name`** - Another improvement
1105
+
1106
+ ### Fixed
1107
+
1108
+ - **`rule-name`** - What was fixed
1109
+
1110
+ ### Documentation
1111
+
1112
+ - What docs were updated
1113
+
1114
+ ### Stats
1115
+
1116
+ - Total Rules: 64 (was 61)
1117
+ - Auto-fixable: 58 rules 🔧
1118
+ - Report-only: 6 rules
1119
+
1120
+ **Full Changelog:** [v1.3.1...v1.4.2](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.3.1...v1.4.2)
1121
+ ```
1122
+
1123
+ #### Tag Format (PATCH versions)
1124
+
1125
+ PATCH versions (x.y.+1) have a simpler format - NO title, NO version range, NO full changelog in entry:
1126
+
1127
+ ```markdown
1128
+ ## [1.11.2] - 2026-02-04
1129
+
1130
+ ### Fixed
1131
+
1132
+ - **`rule-name`** - What was fixed
1133
+ - **`another-rule`** - Another fix
1134
+
1135
+ ---
1136
+ ```
1137
+
1138
+ For version bumps with no changes:
1139
+ ```markdown
1140
+ ## [1.0.19] - 2026-01-11
1141
+
1142
+ - Version bump
1143
+
1144
+ ---
1145
+ ```
1146
+
1147
+ **IMPORTANT:** Even though PATCH entries don't have Full Changelog links in the body, you MUST still add the link reference at the bottom of CHANGELOG.md:
1148
+ ```markdown
1149
+ [1.11.2]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.1...v1.11.2
1150
+ [1.11.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.0...v1.11.1
1151
+ ```
1152
+
1153
+ #### Section Types
1154
+
1155
+ | Section | Use for |
1156
+ |---------|---------|
1157
+ | **Added** | New rules, features, configurations |
1158
+ | **Changed** | Breaking changes, behavior changes |
1159
+ | **Enhanced** | Improvements to existing functionality |
1160
+ | **Fixed** | Bug fixes |
1161
+ | **Deprecated** | Features to be removed in future |
1162
+ | **Removed** | Removed features |
1163
+ | **Security** | Security fixes |
1164
+ | **Documentation** | Doc-only changes |
1165
+ | **Stats** | Rule counts (include for releases) |
1166
+
1167
+ #### Comparison Links
1168
+
1169
+ At the bottom of CHANGELOG.md, maintain comparison links for **every version**:
1170
+
1171
+ ```markdown
1172
+ [1.4.2]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.4.1...v1.4.2
1173
+ [1.4.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.4.0...v1.4.1
1174
+ ```
1175
+
1176
+ #### When to Update
1177
+
1178
+ Update CHANGELOG.md when creating any new tag:
1179
+ - [ ] Add new section at top: `## [X.Y.Z] - YYYY-MM-DD`
1180
+ - [ ] For releases: add **Version Range**, full detailed sections, and **Full Changelog** link
1181
+ - [ ] For tags: add appropriate subsections
1182
+ - [ ] Add comparison link at bottom
1183
+ - [ ] Separate each version with `---`
1184
+
1185
+ **Tip:** Update the CHANGELOG as you make changes, not just at release time
1186
+
1187
+ #### Release Checklist
1188
+
1189
+ When creating a release:
1190
+ - [ ] Write full release description with all sections (Added, Enhanced, Fixed, Stats, etc.)
1191
+ - [ ] Create GitHub Release with the description and title
1192
+ - [ ] Copy exact same content to CHANGELOG.md
1193
+ - [ ] Add **Release Title** (bold text after version header)
1194
+ - [ ] Add **Version Range** showing first and last tag in release
1195
+ - [ ] Add **Full Changelog** link at the end: `**Full Changelog:** [vX.X.X...vY.Y.Y](compare-url)`
1196
+ - [ ] Update the "Current releases" list in this file (AGENTS.md)
1197
+ - [ ] Verify content matches between GitHub Release and CHANGELOG
1198
+
1199
+ #### Verifying CHANGELOG
1200
+
1201
+ To verify all tags are in CHANGELOG:
1202
+ ```bash
1203
+ # Count tags vs CHANGELOG entries
1204
+ echo "Tags: $(git tag | wc -l)"
1205
+ echo "CHANGELOG: $(grep -c '^## \[' CHANGELOG.md)"
1206
+
1207
+ # Check for missing tags
1208
+ git tag -l | sort -V > /tmp/tags.txt
1209
+ grep '^## \[' CHANGELOG.md | sed 's/.*\[\([^]]*\)\].*/v\1/' | sort -V > /tmp/changelog.txt
1210
+ diff /tmp/tags.txt /tmp/changelog.txt
1211
+ ```
1212
+
1213
+ ## Skills
1214
+
1215
+ 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.
1216
+
1217
+ | Skill | Description |
1218
+ |-------|-------------|
1219
+ | `audit-docs` | Verify documentation accuracy across all files |
1220
+ | `manage-rule` | Add, edit, or remove an ESLint rule with all required file updates |
1221
+ | `review-config` | Review a recommended ESLint configuration |
1222
+ | `test-rule` | Test an ESLint rule after creating or modifying it |
1223
+ | `validate-types` | Verify TypeScript definitions match rules in index.js |
1224
+
1225
+ See `.skills/*/skill.md` for detailed instructions.
1226
+
1227
+ ---
1228
+
1229
+ ## Workflows
1230
+
1231
+ Reusable workflows for common tasks. Any AI agent should follow these when performing the specified task.
1232
+
1233
+ ---
1234
+
1235
+ ### Workflow: Test Rule
1236
+
1237
+ Test an ESLint rule to verify it works correctly.
1238
+
1239
+ **When to use:** After creating or modifying a rule.
1240
+
1241
+ **Steps:**
1242
+
1243
+ 1. **Find the rule** in `index.js` and understand what it checks
1244
+ 2. **Identify test app** — Use `_tests_/react/` for JS rules or `_tests_/react-ts-tw/` for TS rules
1245
+ 3. **Create test cases** in the test app:
1246
+ - Add code that should PASS (no violations)
1247
+ - Add code that should FAIL (triggers violations)
1248
+ 4. **Run the linter:**
1249
+ ```bash
1250
+ cd _tests_/<config-name>
1251
+ npm run lint # Check for violations
1252
+ npm run lint:fix # Verify auto-fix works
1253
+ ```
1254
+ 5. **Verify results:**
1255
+ - Valid code produces no errors
1256
+ - Invalid code triggers the expected error message
1257
+ - Auto-fix transforms code correctly
1258
+
1259
+ ---
1260
+
1261
+ ### Workflow: Validate Types
1262
+
1263
+ Verify TypeScript definitions match the rules in `index.js`.
1264
+
1265
+ **When to use:** After adding new rules or before releases.
1266
+
1267
+ **Steps:**
1268
+
1269
+ 1. **Count rules in index.js:**
1270
+ ```bash
1271
+ grep -c "^const .* = {$" index.js
1272
+ ```
1273
+ Or count entries in the `rules` export object.
1274
+
1275
+ 2. **Check index.d.ts:**
1276
+ - Verify `RuleNames` type includes all rule names (alphabetically sorted)
1277
+ - Verify `PluginRules` interface includes all rules
1278
+
1279
+ 3. **Look for mismatches:**
1280
+ - Rules in `index.js` missing from `index.d.ts`?
1281
+ - Rules in `index.d.ts` that don't exist in `index.js`?
1282
+
1283
+ 4. **Report:**
1284
+ - Total rules: X
1285
+ - Types match: Yes/No
1286
+ - Missing types: [list]
1287
+ - Extra types: [list]
1288
+
1289
+ ---
1290
+
1291
+ ### Workflow: Review Config
1292
+
1293
+ Review a recommended ESLint configuration for consistency.
1294
+
1295
+ **When to use:** After adding rules or modifying configs.
1296
+
1297
+ **Arguments:** `<config-name>` (e.g., `react`, `react-ts-tw`)
1298
+
1299
+ **Steps:**
1300
+
1301
+ 1. **Check config file:** `recommended-configs/<config-name>/eslint.config.js`
1302
+ - Does it import the plugin correctly?
1303
+ - Are rules set to `"error"` (not `"off"`)?
1304
+ - Are rule options valid per the rule's schema?
1305
+
1306
+ 2. **Compare with test config:** `_tests_/<config-name>/eslint.config.js`
1307
+ - Should have the same rules enabled
1308
+ - Test config may have additional test-specific settings
1309
+
1310
+ 3. **Test the config:**
1311
+ ```bash
1312
+ cd _tests_/<config-name>
1313
+ npm run lint
1314
+ ```
1315
+
1316
+ 4. **Check README:** `recommended-configs/<config-name>/README.md`
1317
+ - Does it list all enabled rules?
1318
+ - Are rule counts accurate?
1319
+
1320
+ 5. **Report:**
1321
+ - Config valid: Yes/No
1322
+ - Rules enabled: X
1323
+ - Issues found: [list]
1324
+
1325
+ ---
1326
+
1327
+ ### Workflow: Audit Docs
1328
+
1329
+ Verify documentation accuracy across all files.
1330
+
1331
+ **When to use:** Before releases or after adding rules.
1332
+
1333
+ **Steps:**
1334
+
1335
+ 1. **Count actual rules:**
1336
+ ```bash
1337
+ grep -c "^const .* = {$" index.js
1338
+ ```
1339
+
1340
+ 2. **Check rule count references:**
1341
+ - `AGENTS.md`: "61 custom auto-fixable formatting rules"
1342
+ - `README.md`: Multiple mentions of rule count
1343
+ - `recommended-configs/*/README.md`: Any rule count mentions
1344
+
1345
+ 3. **Verify version consistency:**
1346
+ - `package.json` version matches latest tag
1347
+ - No outdated version references in docs
1348
+
1349
+ 4. **Check links:**
1350
+ - Config paths in README exist
1351
+ - Test app paths exist
1352
+ - Internal markdown links work
1353
+
1354
+ 5. **Report:**
1355
+ - Actual rule count: X
1356
+ - Documented counts match: Yes/No
1357
+ - Outdated references: [list]
1358
+ - Broken links: [list]