@eslint-react/kit 5.2.4-beta.2 → 5.2.4-beta.3

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.
Files changed (3) hide show
  1. package/README.md +1 -656
  2. package/dist/index.js +1 -1
  3. package/package.json +7 -7
package/README.md CHANGED
@@ -1,658 +1,3 @@
1
1
  # @eslint-react/kit
2
2
 
3
- ESLint React's toolkit for building custom React rules with JavaScript functions right inside your `eslint.config.ts`.
4
-
5
- ## Index
6
-
7
- - [Installation](#installation)
8
- - [Quick Start](#quick-start)
9
- - [API Reference](#api-reference)
10
- - [`eslintReactKit` (default export)](#eslintreactkit-default-export)
11
- - [`RuleFunction`](#rulefunction)
12
- - [`Builder`](#builder)
13
- - [`getConfig`](#getconfig)
14
- - [`getPlugin`](#getplugin)
15
- - [`merge`](#merge)
16
- - [`RuleToolkit` — the toolkit object](#ruletoolkit--the-toolkit-object)
17
- - [`collect`](#collect) — Semantic collectors
18
- - [`is`](#is) — Predicates
19
- - [`hint`](#hint) — Detection hint bit-flags
20
- - [`flag`](#flag) — Component characteristic flags
21
- - [`settings`](#settings) — Normalized ESLint React settings
22
- - [Examples](#examples)
23
- - [Simple: Ban `forwardRef`](#simple-ban-forwardref)
24
- - [Component: Destructure component props](#component-destructure-component-props)
25
- - [Hooks: Warn on custom hooks that don't call other hooks](#hooks-warn-on-custom-hooks-that-dont-call-other-hooks)
26
- - [Multiple Collectors: No component/hook factories](#multiple-collectors-no-componenthook-factories)
27
- - [Override Config: Using spread syntax with `getConfig`](#override-config-using-spread-syntax-with-getconfig)
28
- - [Advanced Config: Using `getPlugin` for custom plugin namespace](#advanced-config-using-getplugin-for-custom-plugin-namespace)
29
- - [More Examples](#more-examples)
30
-
31
- ## Installation
32
-
33
- ```sh
34
- npm install --save-dev @eslint-react/kit
35
- ```
36
-
37
- ## Quick Start
38
-
39
- ```ts
40
- import eslintReact from "@eslint-react/eslint-plugin";
41
- import eslintReactKit, { merge } from "@eslint-react/kit";
42
- import type { RuleFunction } from "@eslint-react/kit";
43
- import eslintJs from "@eslint/js";
44
- import { defineConfig } from "eslint/config";
45
- import tseslint from "typescript-eslint";
46
-
47
- /** Enforce function declarations for function components. */
48
- function functionComponentDefinition(): RuleFunction {
49
- return (context, { collect }) => {
50
- const { query, visitor } = collect.components(context);
51
- return merge(
52
- visitor,
53
- {
54
- "Program:exit"(program) {
55
- for (const { node } of query.all(program)) {
56
- if (node.type === "FunctionDeclaration") continue;
57
- context.report({
58
- node,
59
- message: "Function components must be defined with function declarations.",
60
- });
61
- }
62
- },
63
- },
64
- );
65
- };
66
- }
67
-
68
- export default defineConfig(
69
- {
70
- files: ["**/*.{ts,tsx}"],
71
- extends: [
72
- eslintJs.configs.recommended,
73
- tseslint.configs.recommended,
74
- eslintReact.configs["recommended-typescript"],
75
- eslintReactKit()
76
- .use(functionComponentDefinition)
77
- .getConfig(),
78
- ],
79
- },
80
- );
81
- ```
82
-
83
- The rule name is derived automatically from the function name (`functionComponentDefinition` → `function-component-definition`), and registered as `@eslint-react/kit/function-component-definition` at `"error"` severity.
84
-
85
- ## API Reference
86
-
87
- ### `eslintReactKit` (default export)
88
-
89
- ```ts
90
- import eslintReactKit from "@eslint-react/kit";
91
-
92
- eslintReactKit(): Builder
93
- ```
94
-
95
- Creates a `Builder` instance for registering custom rules via the chainable `.use()` API.
96
-
97
- ### `RuleFunction`
98
-
99
- ```ts
100
- import type { RuleFunction } from "@eslint-react/kit";
101
-
102
- type RuleFunction = (context: RuleContext, toolkit: RuleToolkit) => RuleListener;
103
- ```
104
-
105
- A function that receives the ESLint rule context and the structured `RuleToolkit` toolkit, and returns a `RuleListener` (AST visitor object).
106
-
107
- Rules are defined as **named functions** that return a `RuleFunction`. The function name is automatically converted to kebab-case and used as the rule name under the `@eslint-react/kit` plugin namespace.
108
-
109
- ```ts
110
- // Function name `noForwardRef` → rule name `no-forward-ref`
111
- // Registered as `@eslint-react/kit/no-forward-ref`
112
- function noForwardRef(): RuleFunction {
113
- return (context, { is }) => ({ ... });
114
- }
115
-
116
- // Functions that accept options work the same way
117
- function forbidElements({ forbidden }: ForbidElementsOptions): RuleFunction {
118
- return (context) => ({ ... });
119
- }
120
- ```
121
-
122
- #### Anonymous Rules
123
-
124
- When you use an **anonymous function** (arrow function without a name) with `.use()`, a random ULID is automatically generated as the rule name:
125
-
126
- ```ts
127
- // Anonymous rule → random ULID name like "01KNE2WSJ8011D2HXE3A6H717C"
128
- // Registered as `@eslint-react/kit/01KNE2WSJ8011D2HXE3A6H717C`
129
- eslintReactKit().use(() => (context) => ({
130
- JSXOpeningElement(node) {
131
- // Critical check that cannot be easily disabled
132
- },
133
- }));
134
- ```
135
-
136
- > **Note:** The rule names are ULIDs generated randomly on each ESLint run. The examples above illustrate the format — actual values will differ every time.
137
-
138
- Anonymous rules are ideal for checks that are **critical to code quality or security** and should never be bypassed via disable comments:
139
-
140
- ```ts
141
- // This critical security check cannot be easily disabled by developers
142
- eslintReactKit().use(() => (context, { is }) => ({
143
- CallExpression(node) {
144
- // Prevent dangerous API calls that could lead to XSS
145
- if (is.createElementCall(node) && isUnsafeArguments(node.arguments)) {
146
- context.report({
147
- node,
148
- message: "Potential XSS vulnerability detected. This issue must be fixed.",
149
- });
150
- }
151
- },
152
- }));
153
- ```
154
-
155
- **Note:** Since the rule name is random and changes on every ESLint run, developers cannot use standard rules configs or disable comments like:
156
-
157
- ```ts
158
- // This will NOT work - the rule name is random!
159
- { rules: { "@eslint-react/kit/01KNE2WSJ8011D2HXE3A6H717C": "off" } }
160
-
161
- // This will NOT work - the rule name is random!
162
- // eslint-disable-next-line @eslint-react/kit/01KNE2WSJ8011D2HXE3A6H717C
163
- ```
164
-
165
- To disable an anonymous rule, developers must modify the ESLint configuration file directly, which provides an audit trail for policy violations.
166
-
167
- ### `Builder`
168
-
169
- ```ts
170
- interface Builder {
171
- use<F extends (...args: any[]) => RuleFunction>(factory: F, ...args: Parameters<F>): Builder;
172
- getConfig(): Linter.Config;
173
- getPlugin(): ESLint.Plugin;
174
- }
175
- ```
176
-
177
- A chainable builder for registering custom rules.
178
-
179
- | Method | Description |
180
- | ----------- | -------------------------------------------------------------------------------------------------------------------------- |
181
- | `use` | Registers a rule factory. The rule name is `kebabCase(factory.name)`. Options type is inferred from the factory signature. |
182
- | `getConfig` | Returns a `Linter.Config` with all registered rules enabled at `"error"` severity. |
183
- | `getPlugin` | Returns an `ESLint.Plugin` containing the registered rules and plugin metadata. |
184
-
185
- #### `getConfig`
186
-
187
- Returns a flat `Linter.Config` object with all registered rules set to `"error"`. This is a convenience wrapper that calls `getPlugin()` internally and adds the plugin plus rule entries to the config.
188
-
189
- ```ts
190
- eslintReactKit()
191
- .use(noForwardRef) // no-arg factory
192
- .use(version, "19") // factory with inferred options
193
- .getConfig();
194
- ```
195
-
196
- #### `getPlugin`
197
-
198
- Returns an `ESLint.Plugin` object containing the registered rules and plugin metadata (`name` and `version`). Use this when you need finer-grained control over how the plugin is integrated into your ESLint configuration — for example, when you want to choose the plugin namespace, set per-rule severities, or compose the plugin with other configs manually.
199
-
200
- ```ts
201
- const kit = eslintReactKit()
202
- .use(noForwardRef)
203
- .use(version, "19");
204
-
205
- // Retrieve the raw plugin object
206
- const plugin = kit.getPlugin();
207
-
208
- // Use it in a custom flat config with your own namespace and severity
209
- export default [
210
- {
211
- files: ["**/*.{ts,tsx}"],
212
- plugins: {
213
- react: plugin,
214
- },
215
- rules: {
216
- "react/version": "error",
217
- "react/no-forward-ref": "error",
218
- },
219
- },
220
- ];
221
- ```
222
-
223
- ### `merge`
224
-
225
- ```ts
226
- import { merge } from "@eslint-react/kit";
227
-
228
- merge(...listeners: RuleListener[]): RuleListener
229
- ```
230
-
231
- Merges multiple `RuleListener` (visitor) objects into a single listener. When two or more listeners define the same visitor key, the handlers are chained and execute in order.
232
-
233
- This is essential for combining a collector's `visitor` with your own inspection logic.
234
-
235
- ### `RuleToolkit` — the toolkit object
236
-
237
- The second argument passed to the `RuleFunction` function is a structured `RuleToolkit` object:
238
-
239
- ```
240
- kit
241
- ├── collect -> Semantic collectors (components, hooks)
242
- ├── is -> All predicates (component, hook, React API, import source)
243
- ├── hint -> Detection hint bit-flags
244
- ├── flag -> Component characteristic bit-flags
245
- ├── settings -> Normalized ESLint React settings
246
- ```
247
-
248
- ---
249
-
250
- #### `collect`
251
-
252
- Collector factories create a `{ query, visitor }` pair. The `visitor` must be merged into your rule listener via `merge()`. After traversal completes, `query.all(program)` yields all detected semantic nodes.
253
-
254
- | Method | Returns | Description |
255
- | ------------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------- |
256
- | `components(context, options?)` | `CollectorWithContext<FunctionComponentSemanticNode>` | Detects function components. Options: `{ hint?: bigint, collectDisplayName?: boolean }` |
257
- | `hooks(context)` | `CollectorWithContext<HookSemanticNode>` | Detects custom hook definitions. |
258
-
259
- **`CollectorWithContext`** extends `Collector` with contextual queries:
260
-
261
- | Query | Description |
262
- | -------------------- | ----------------------------------------- |
263
- | `query.all(program)` | All collected semantic nodes in the file. |
264
-
265
- ---
266
-
267
- #### `is`
268
-
269
- All predicates live under `kit.is` — organized into four sub-sections.
270
-
271
- ##### Component
272
-
273
- | Predicate | Signature | Description |
274
- | -------------------------- | ------------------------- | --------------------------------------------------------------------------- |
275
- | `componentDecl` | `(node, hint) -> boolean` | Whether a function node is a component. (context pre-bound) |
276
- | `componentName` | `(name) -> boolean` | Strict PascalCase component name check. |
277
- | `componentNameLoose` | `(name) -> boolean` | Loose component name check. |
278
- | `componentWrapperCall` | `(node) -> boolean` | Whether a node is a `memo(…)` or `forwardRef(…)` call. (context pre-bound) |
279
- | `componentWrapperCallback` | `(node) -> boolean` | Whether a function is the callback passed to a wrapper. (context pre-bound) |
280
-
281
- ##### Hook
282
-
283
- General hook predicates:
284
-
285
- | Predicate | Signature | Description |
286
- | -------------------------- | ------------------------------------- | ------------------------------------------------------------ |
287
- | `hookDecl` | `(node) -> boolean` | Whether a function node is a hook (by name). |
288
- | `hookCall` | `(node) -> boolean` | Whether a node is a hook call. |
289
- | `hookName` | `(name) -> boolean` | Whether a string matches the `use[A-Z]` convention. |
290
- | `useEffectLikeCall` | `(node, additionalHooks?) -> boolean` | Whether a node is a `useEffect`/`useLayoutEffect`-like call. |
291
- | `useStateLikeCall` | `(node, additionalHooks?) -> boolean` | Whether a node is a `useState`-like call. |
292
- | `useEffectSetupCallback` | `(node) -> boolean` | Whether a node is a useEffect setup function. |
293
- | `useEffectCleanupCallback` | `(node) -> boolean` | Whether a node is a useEffect cleanup function. |
294
-
295
- Specific hook call predicates (context pre-bound):
296
-
297
- | Predicate | Description |
298
- | -------------------------- | ------------------------------------------------ |
299
- | `useActionStateCall` | Whether a node is a `useActionState` call. |
300
- | `useCallbackCall` | Whether a node is a `useCallback` call. |
301
- | `useContextCall` | Whether a node is a `useContext` call. |
302
- | `useDebugValueCall` | Whether a node is a `useDebugValue` call. |
303
- | `useDeferredValueCall` | Whether a node is a `useDeferredValue` call. |
304
- | `useEffectCall` | Whether a node is a `useEffect` call. |
305
- | `useFormStatusCall` | Whether a node is a `useFormStatus` call. |
306
- | `useIdCall` | Whether a node is a `useId` call. |
307
- | `useImperativeHandleCall` | Whether a node is a `useImperativeHandle` call. |
308
- | `useInsertionEffectCall` | Whether a node is a `useInsertionEffect` call. |
309
- | `useLayoutEffectCall` | Whether a node is a `useLayoutEffect` call. |
310
- | `useMemoCall` | Whether a node is a `useMemo` call. |
311
- | `useOptimisticCall` | Whether a node is a `useOptimistic` call. |
312
- | `useReducerCall` | Whether a node is a `useReducer` call. |
313
- | `useRefCall` | Whether a node is a `useRef` call. |
314
- | `useStateCall` | Whether a node is a `useState` call. |
315
- | `useSyncExternalStoreCall` | Whether a node is a `useSyncExternalStore` call. |
316
- | `useTransitionCall` | Whether a node is a `useTransition` call. |
317
-
318
- ##### React API
319
-
320
- Factory functions (context pre-bound):
321
-
322
- | Predicate | Signature | Description |
323
- | --------- | -------------------------------- | ---------------------------------------------------------------------------- |
324
- | `API` | `(apiName) -> (node) -> boolean` | Factory: creates a predicate for a React API identifier. (context pre-bound) |
325
- | `APICall` | `(apiName) -> (node) -> boolean` | Factory: creates a predicate for a React API call. (context pre-bound) |
326
-
327
- Pre-built call predicates (context pre-bound):
328
-
329
- - `captureOwnerStackCall`
330
- - `childrenCountCall`
331
- - `childrenForEachCall`
332
- - `childrenMapCall`
333
- - `childrenOnlyCall`
334
- - `childrenToArrayCall`
335
- - `cloneElementCall`
336
- - `createContextCall`
337
- - `createElementCall`
338
- - `createRefCall`
339
- - `forwardRefCall`
340
- - `lazyCall`
341
- - `memoCall`
342
- - `useCall`
343
-
344
- All React API predicates and factories have `context` pre-bound — no need to pass the rule context manually:
345
-
346
- ```ts
347
- // Direct check
348
- is.memoCall(node);
349
-
350
- // Useful in filter/find
351
- nodes.filter(is.memoCall);
352
-
353
- // Factory for any API name
354
- const isCreateRefCall = is.APICall("createRef");
355
- isCreateRefCall(node);
356
- ```
357
-
358
- ##### Import source
359
-
360
- | Predicate | Signature | Description |
361
- | -------------------- | ----------------------------------------- | ---------------------------------------------------- |
362
- | `APIFromReact` | `(name, scope, importSource?) -> boolean` | Whether a variable comes from a React import. |
363
- | `APIFromReactNative` | `(name, scope, importSource?) -> boolean` | Whether a variable comes from a React Native import. |
364
-
365
- ---
366
-
367
- #### `hint`
368
-
369
- Bit-flags that control what the component collector considers a "component". Combine with bitwise OR (`|`) and remove with bitwise AND-NOT (`& ~`).
370
-
371
- ```ts
372
- // The default hint used when none is specified
373
- hint.component.Default;
374
-
375
- // All available flags
376
- hint.component.DoNotIncludeFunctionDefinedAsObjectMethod;
377
- hint.component.DoNotIncludeFunctionDefinedAsClassMethod;
378
- hint.component.DoNotIncludeFunctionDefinedAsArrayMapCallback;
379
- hint.component.DoNotIncludeFunctionDefinedAsArbitraryCallExpressionCallback;
380
- // … and more (inherits all JsxDetectionHint flags)
381
- ```
382
-
383
- **Customization example:**
384
-
385
- ```ts
386
- const { query, visitor } = collect.components(context, {
387
- // Also treat object methods as components (remove the exclusion flag)
388
- hint: hint.component.Default & ~hint.component.DoNotIncludeFunctionDefinedAsObjectMethod,
389
- });
390
- ```
391
-
392
- ---
393
-
394
- #### `flag`
395
-
396
- Bit-flags indicating component characteristics. Check with bitwise AND (`&`).
397
-
398
- ```ts
399
- flag.component.None; // 0n — no flags
400
- flag.component.Memo; // wrapped in React.memo
401
- flag.component.ForwardRef; // wrapped in React.forwardRef
402
- ```
403
-
404
- **Usage:**
405
-
406
- ```ts
407
- for (const component of query.all(program)) {
408
- if (component.flag & flag.component.Memo) {
409
- // This component is memoized
410
- }
411
- }
412
- ```
413
-
414
- #### `settings`
415
-
416
- Exposes the normalized `react-x` settings from the ESLint shared configuration (`context.settings["react-x"]`). This lets your custom rules read and react to the same project-level settings used by the built-in rules.
417
-
418
- | Property | Type | Default | Description |
419
- | ----------------------- | ------------------------------------------------------- | ----------- | --------------------------------------------------------- |
420
- | `version` | `string` | auto-detect | Resolved React version (e.g. `"19.2.4"`). |
421
- | `importSource` | `string` | `"react"` | The module React is imported from (e.g. `"@pika/react"`). |
422
- | `compilationMode` | `"infer" \| "annotation" \| "syntax" \| "all" \| "off"` | `"off"` | The React Compiler compilation mode the project uses. |
423
- | `polymorphicPropName` | `string \| null` | `"as"` | Prop name used for polymorphic components. |
424
- | `additionalStateHooks` | `RegExpLike` | — | Pattern matching custom hooks treated as state hooks. |
425
- | `additionalEffectHooks` | `RegExpLike` | — | Pattern matching custom hooks treated as effect hooks. |
426
-
427
- `RegExpLike` is an object with a `test(s: string) => boolean` method (same interface as `RegExp`).
428
-
429
- **Usage:**
430
-
431
- ```ts
432
- import type { RuleFunction } from "@eslint-react/kit";
433
-
434
- function version(major = "19"): RuleFunction {
435
- return (context, { settings }) => ({
436
- Program(program) {
437
- if (!settings.version.startsWith(`${major}.`)) {
438
- context.report({
439
- node: program,
440
- message: `This project requires React ${major}, but detected version ${settings.version}.`,
441
- });
442
- }
443
- },
444
- });
445
- }
446
- ```
447
-
448
- ---
449
-
450
- ## Examples
451
-
452
- ### Simple: Ban `forwardRef`
453
-
454
- This is a simplified kit reimplementation of the built-in [`react-x/no-forwardRef`](https://eslint-react.xyz/docs/rules/no-forward-ref) rule.
455
-
456
- ```ts
457
- import type { RuleFunction } from "@eslint-react/kit";
458
-
459
- function noForwardRef(): RuleFunction {
460
- return (context, { is }) => ({
461
- CallExpression(node) {
462
- if (is.forwardRefCall(node)) {
463
- context.report({ node, message: "forwardRef is deprecated in React 19. Pass ref as a prop instead." });
464
- }
465
- },
466
- });
467
- }
468
-
469
- // Usage
470
- eslintReactKit()
471
- .use(noForwardRef)
472
- .getConfig();
473
- ```
474
-
475
- ### Component: Destructure component props
476
-
477
- This is a simplified kit reimplementation of the built-in [`react-x/prefer-destructuring-assignment`](https://eslint-react.xyz/docs/rules/prefer-destructuring-assignment) rule.
478
-
479
- ```ts
480
- import type { RuleFunction } from "@eslint-react/kit";
481
- import { merge } from "@eslint-react/kit";
482
-
483
- function destructureComponentProps(): RuleFunction {
484
- return (context, { collect }) => {
485
- const { query, visitor } = collect.components(context);
486
-
487
- return merge(visitor, {
488
- "Program:exit"(program) {
489
- for (const { node } of query.all(program)) {
490
- const [props] = node.params;
491
- if (props == null) continue;
492
- if (props.type !== "Identifier") continue;
493
- const propName = props.name;
494
- const propVariable = context.sourceCode.getScope(node).variables.find((v) => v.name === propName);
495
- const propReferences = propVariable?.references ?? [];
496
- for (const ref of propReferences) {
497
- const { parent } = ref.identifier;
498
- if (parent.type !== "MemberExpression") continue;
499
- context.report({
500
- message: "Use destructuring assignment for component props.",
501
- node: parent,
502
- });
503
- }
504
- }
505
- },
506
- });
507
- };
508
- }
509
-
510
- // Usage
511
- eslintReactKit()
512
- .use(destructureComponentProps)
513
- .getConfig();
514
- ```
515
-
516
- ### Hooks: Warn on custom hooks that don't call other hooks
517
-
518
- This is a simplified kit reimplementation of the built-in [`react-x/no-unnecessary-use-prefix`](https://eslint-react.xyz/docs/rules/no-unnecessary-use-prefix) rule.
519
-
520
- ```ts
521
- import type { RuleFunction } from "@eslint-react/kit";
522
- import { merge } from "@eslint-react/kit";
523
-
524
- function noUnnecessaryUsePrefix(): RuleFunction {
525
- return (context, { collect }) => {
526
- const { query, visitor } = collect.hooks(context);
527
-
528
- return merge(visitor, {
529
- "Program:exit"(program) {
530
- for (const { node, hookCalls } of query.all(program)) {
531
- if (hookCalls.length === 0) {
532
- context.report({
533
- node,
534
- message: "A custom hook should use at least one hook, otherwise it's just a regular function.",
535
- });
536
- }
537
- }
538
- },
539
- });
540
- };
541
- }
542
-
543
- // Usage
544
- eslintReactKit()
545
- .use(noUnnecessaryUsePrefix)
546
- .getConfig();
547
- ```
548
-
549
- ### Multiple Collectors: No component/hook factories
550
-
551
- Disallow defining components or hooks inside other functions (factory pattern).
552
- This is a simplified kit reimplementation of the built-in [`react-x/component-hook-factories`](https://eslint-react.xyz/docs/rules/component-hook-factories) rule.
553
-
554
- ```ts
555
- import type { RuleFunction } from "@eslint-react/kit";
556
- import { merge } from "@eslint-react/kit";
557
- import type { TSESTree } from "@typescript-eslint/types";
558
-
559
- function componentHookFactories(): RuleFunction {
560
- function findParent({ parent }: TSESTree.Node, test: (n: TSESTree.Node) => boolean): TSESTree.Node | null {
561
- if (parent == null) return null;
562
- if (test(parent)) return parent;
563
- if (parent.type === "Program") return null;
564
- return findParent(parent, test);
565
- }
566
-
567
- function isFunction({ type }: TSESTree.Node) {
568
- return type === "FunctionDeclaration" || type === "FunctionExpression" || type === "ArrowFunctionExpression";
569
- }
570
- return (context, { collect }) => {
571
- const fc = collect.components(context);
572
- const hk = collect.hooks(context);
573
- return merge(
574
- fc.visitor,
575
- hk.visitor,
576
- {
577
- "Program:exit"(program) {
578
- const comps = fc.query.all(program);
579
- const hooks = hk.query.all(program);
580
- for (const { name, node, kind } of [...comps, ...hooks]) {
581
- if (name == null) continue;
582
- if (findParent(node, isFunction) == null) continue;
583
- context.report({
584
- node,
585
- message: `Don't define ${kind} "${name}" inside a function. Move it to the module level.`,
586
- });
587
- }
588
- },
589
- },
590
- );
591
- };
592
- }
593
-
594
- // Usage
595
- eslintReactKit()
596
- .use(componentHookFactories)
597
- .getConfig();
598
- ```
599
-
600
- ### Override Config: Using spread syntax with `getConfig`
601
-
602
- `getConfig()` returns a plain config object. You can spread it into a new object to override or supplement its properties — for example, to scope the config to specific files or add extra settings alongside your kit rules.
603
-
604
- ```ts
605
- import eslintReactKit from "@eslint-react/kit";
606
- import type { RuleFunction } from "@eslint-react/kit";
607
-
608
- // Spread the config into a new object to add or override properties like `files`:
609
- export default [
610
- {
611
- ...eslintReactKit()
612
- .use(noForwardRef)
613
- .use(version, "19")
614
- .getConfig(),
615
- // Override `name` so it shows your own label in config inspector tools
616
- name: "react-custom-rules",
617
- // Override `files` to scope the kit rules to specific source files
618
- files: ["src/**/*.ts", "src/**/*.tsx"],
619
- },
620
- ];
621
- ```
622
-
623
- This pattern is especially useful when composing kit configs alongside other ESLint configs (e.g. `typescript-eslint`, `eslint-plugin-react-hooks`) via `defineConfig` — you can nest the spread object inside `extends` arrays and attach shared properties like `files` or `languageOptions` at the same level.
624
-
625
- ### Advanced Config: Using `getPlugin` for custom plugin namespace
626
-
627
- Use `getPlugin()` when you want full control over the plugin namespace and rule severities instead of the all-in-one `getConfig()`.
628
-
629
- ```ts
630
- import eslintReactKit from "@eslint-react/kit";
631
- import type { RuleFunction } from "@eslint-react/kit";
632
-
633
- const kit = eslintReactKit()
634
- .use(noForwardRef)
635
- .use(version, "19");
636
-
637
- // Instead of kit.getConfig(), use kit.getPlugin() for full control:
638
- const plugin = kit.getPlugin();
639
-
640
- export default [
641
- {
642
- files: ["**/*.{ts,tsx}"],
643
- plugins: {
644
- // Choose your own namespace
645
- "react-custom-rules": plugin,
646
- },
647
- rules: {
648
- // Set individual severities
649
- "react-custom-rules/no-forward-ref": "error",
650
- "react-custom-rules/version": "error",
651
- },
652
- },
653
- ];
654
- ```
655
-
656
- ## More Examples
657
-
658
- Please check the [Rule Recipes](https://www.eslint-react.xyz/docs/recipes) in the documentation site.
3
+ For full documentation, see [https://beta.eslint-react.xyz/docs/packages/kit](https://beta.eslint-react.xyz/docs/packages/kit).
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { ESLintUtils } from "@typescript-eslint/utils";
6
6
 
7
7
  //#region package.json
8
8
  var name = "@eslint-react/kit";
9
- var version = "5.2.4-beta.2";
9
+ var version = "5.2.4-beta.3";
10
10
 
11
11
  //#endregion
12
12
  //#region ../eslint/dist/index.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-react/kit",
3
- "version": "5.2.4-beta.2",
3
+ "version": "5.2.4-beta.3",
4
4
  "description": "ESLint React's utility module for building custom React rules with JavaScript functions.",
5
5
  "keywords": [
6
6
  "react",
@@ -38,16 +38,16 @@
38
38
  "dependencies": {
39
39
  "@typescript-eslint/utils": "^8.58.2",
40
40
  "string-ts": "^2.3.1",
41
- "@eslint-react/core": "5.2.4-beta.2",
42
- "@eslint-react/shared": "5.2.4-beta.2"
41
+ "@eslint-react/core": "5.2.4-beta.3",
42
+ "@eslint-react/shared": "5.2.4-beta.3"
43
43
  },
44
44
  "devDependencies": {
45
45
  "eslint": "^10.2.0",
46
46
  "tsdown": "^0.21.9",
47
- "@eslint-react/ast": "5.2.4-beta.2",
48
- "@local/eff": "3.0.0-beta.72",
49
- "@eslint-react/eslint": "5.2.4-beta.2",
50
- "@local/configs": "0.0.0"
47
+ "@eslint-react/ast": "5.2.4-beta.3",
48
+ "@eslint-react/eslint": "5.2.4-beta.3",
49
+ "@local/configs": "0.0.0",
50
+ "@local/eff": "3.0.0-beta.72"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "eslint": "^10.2.0",