@eslint-react/kit 5.0.1-next.1 → 5.0.2-beta.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/README.md +63 -55
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -13,12 +13,12 @@ ESLint React's toolkit for building custom React rules with JavasSript functions
|
|
|
13
13
|
- [`getConfig`](#getconfig)
|
|
14
14
|
- [`getPlugin`](#getplugin)
|
|
15
15
|
- [`merge`](#merge)
|
|
16
|
-
- [`
|
|
17
|
-
- [`
|
|
18
|
-
- [`
|
|
19
|
-
- [`
|
|
20
|
-
- [`
|
|
21
|
-
- [`
|
|
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
22
|
- [Examples](#examples)
|
|
23
23
|
- [Simple: Ban `forwardRef`](#simple-ban-forwardref)
|
|
24
24
|
- [Component: Destructure component props](#component-destructure-component-props)
|
|
@@ -99,10 +99,10 @@ Creates a `Builder` instance for registering custom rules via the chainable `.us
|
|
|
99
99
|
```ts
|
|
100
100
|
import type { RuleFunction } from "@eslint-react/kit";
|
|
101
101
|
|
|
102
|
-
type RuleFunction = (
|
|
102
|
+
type RuleFunction = (context: RuleContext, toolkit: RuleToolkit) => RuleListener;
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
A function that receives the ESLint rule context and the structured `
|
|
105
|
+
A function that receives the ESLint rule context and the structured `RuleToolkit` toolkit, and returns a `RuleListener` (AST visitor object).
|
|
106
106
|
|
|
107
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
108
|
|
|
@@ -126,7 +126,7 @@ When you use an **anonymous function** (arrow function without a name) with `.us
|
|
|
126
126
|
```ts
|
|
127
127
|
// Anonymous rule → random ULID name like "01KNE2WSJ8011D2HXE3A6H717C"
|
|
128
128
|
// Registered as `@eslint-react/kit/01KNE2WSJ8011D2HXE3A6H717C`
|
|
129
|
-
|
|
129
|
+
eslintReactKit().use(() => (context) => ({
|
|
130
130
|
JSXOpeningElement(node) {
|
|
131
131
|
// Critical check that cannot be easily disabled
|
|
132
132
|
},
|
|
@@ -150,7 +150,7 @@ Anonymous rules are ideal for checks that are **critical to code quality or secu
|
|
|
150
150
|
eslintReactKit().use(() => (context, { is }) => ({
|
|
151
151
|
CallExpression(node) {
|
|
152
152
|
// Prevent dangerous API calls that could lead to XSS
|
|
153
|
-
if (is.
|
|
153
|
+
if (is.createElementCall(node) && isUnsafeArguments(node.arguments)) {
|
|
154
154
|
context.report({
|
|
155
155
|
node,
|
|
156
156
|
message: "Potential XSS vulnerability detected. This issue must be fixed.",
|
|
@@ -164,30 +164,14 @@ eslintReactKit().use(() => (context, { is }) => ({
|
|
|
164
164
|
|
|
165
165
|
```ts
|
|
166
166
|
// This will NOT work - the rule name is random!
|
|
167
|
-
{ rules: { "01KNE2WSJ8011D2HXE3A6H717C": "off" } }
|
|
167
|
+
{ rules: { "@eslint-react/kit/01KNE2WSJ8011D2HXE3A6H717C": "off" } }
|
|
168
168
|
|
|
169
169
|
// This will NOT work - the rule name is random!
|
|
170
|
-
// eslint-disable-next-line 01KNE2WSJ8011D2HXE3A6H717C
|
|
170
|
+
// eslint-disable-next-line @eslint-react/kit/01KNE2WSJ8011D2HXE3A6H717C
|
|
171
171
|
```
|
|
172
172
|
|
|
173
173
|
To disable an anonymous rule, developers must modify the ESLint configuration file directly, which provides an audit trail for policy violations.
|
|
174
174
|
|
|
175
|
-
##### Debugging Anonymous Rules
|
|
176
|
-
|
|
177
|
-
For debugging purposes, you can [set a `displayName`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/displayName#setting_a_displayname) on an anonymous function. The display name will be used as a label in various places. This helps identify the rule, while the actual registered rule name remains a random ULID:
|
|
178
|
-
|
|
179
|
-
```ts
|
|
180
|
-
import { defineRule } from "@eslint-react/kit";
|
|
181
|
-
|
|
182
|
-
const myRule = defineRule(() => (context) => ({}));
|
|
183
|
-
|
|
184
|
-
myRule.displayName = "my-rule";
|
|
185
|
-
|
|
186
|
-
eslintReactKit().use(myRule);
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
> **Note:** This feature is currently under development and may not be available in the current release.
|
|
190
|
-
|
|
191
175
|
### `Builder`
|
|
192
176
|
|
|
193
177
|
```ts
|
|
@@ -223,8 +207,8 @@ Returns an `ESLint.Plugin` object containing the registered rules and plugin met
|
|
|
223
207
|
|
|
224
208
|
```ts
|
|
225
209
|
const kit = eslintReactKit()
|
|
226
|
-
.use(noForwardRef)
|
|
227
|
-
.use(version, "19")
|
|
210
|
+
.use(noForwardRef)
|
|
211
|
+
.use(version, "19");
|
|
228
212
|
|
|
229
213
|
// Retrieve the raw plugin object
|
|
230
214
|
const plugin = kit.getPlugin();
|
|
@@ -256,9 +240,9 @@ Merges multiple `RuleListener` (visitor) objects into a single listener. When tw
|
|
|
256
240
|
|
|
257
241
|
This is essential for combining a collector's `visitor` with your own inspection logic.
|
|
258
242
|
|
|
259
|
-
###
|
|
243
|
+
### `RuleToolkit` — the toolkit object
|
|
260
244
|
|
|
261
|
-
The second argument passed to the `RuleFunction` function is a structured `
|
|
245
|
+
The second argument passed to the `RuleFunction` function is a structured `RuleToolkit` object:
|
|
262
246
|
|
|
263
247
|
```
|
|
264
248
|
kit
|
|
@@ -271,7 +255,7 @@ kit
|
|
|
271
255
|
|
|
272
256
|
---
|
|
273
257
|
|
|
274
|
-
#### `
|
|
258
|
+
#### `collect`
|
|
275
259
|
|
|
276
260
|
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.
|
|
277
261
|
|
|
@@ -288,20 +272,19 @@ Collector factories create a `{ query, visitor }` pair. The `visitor` must be me
|
|
|
288
272
|
|
|
289
273
|
---
|
|
290
274
|
|
|
291
|
-
#### `
|
|
275
|
+
#### `is`
|
|
292
276
|
|
|
293
277
|
All predicates live under `kit.is` — organized into four sub-sections.
|
|
294
278
|
|
|
295
279
|
##### Component
|
|
296
280
|
|
|
297
|
-
| Predicate
|
|
298
|
-
|
|
|
299
|
-
| `
|
|
300
|
-
| `componentName`
|
|
301
|
-
| `componentNameLoose`
|
|
302
|
-
| `componentWrapperCall`
|
|
303
|
-
| `
|
|
304
|
-
| `componentWrapperCallback` | `(node) -> boolean` | Whether a function is the callback passed to a wrapper. (context pre-bound) |
|
|
281
|
+
| Predicate | Signature | Description |
|
|
282
|
+
| -------------------------- | ------------------------- | --------------------------------------------------------------------------- |
|
|
283
|
+
| `componentDecl` | `(node, hint) -> boolean` | Whether a function node is a component. (context pre-bound) |
|
|
284
|
+
| `componentName` | `(name) -> boolean` | Strict PascalCase component name check. |
|
|
285
|
+
| `componentNameLoose` | `(name) -> boolean` | Loose component name check. |
|
|
286
|
+
| `componentWrapperCall` | `(node) -> boolean` | Whether a node is a `memo(…)` or `forwardRef(…)` call. (context pre-bound) |
|
|
287
|
+
| `componentWrapperCallback` | `(node) -> boolean` | Whether a function is the callback passed to a wrapper. (context pre-bound) |
|
|
305
288
|
|
|
306
289
|
##### Hook
|
|
307
290
|
|
|
@@ -309,7 +292,7 @@ General hook predicates:
|
|
|
309
292
|
|
|
310
293
|
| Predicate | Signature | Description |
|
|
311
294
|
| -------------------------- | ------------------------------------- | ------------------------------------------------------------ |
|
|
312
|
-
| `
|
|
295
|
+
| `hookDecl` | `(node) -> boolean` | Whether a function node is a hook (by name). |
|
|
313
296
|
| `hookCall` | `(node) -> boolean` | Whether a node is a hook call. |
|
|
314
297
|
| `hookName` | `(name) -> boolean` | Whether a string matches the `use[A-Z]` convention. |
|
|
315
298
|
| `useEffectLikeCall` | `(node, additionalHooks?) -> boolean` | Whether a node is a `useEffect`/`useLayoutEffect`-like call. |
|
|
@@ -317,6 +300,29 @@ General hook predicates:
|
|
|
317
300
|
| `useEffectSetupCallback` | `(node) -> boolean` | Whether a node is a useEffect setup function. |
|
|
318
301
|
| `useEffectCleanupCallback` | `(node) -> boolean` | Whether a node is a useEffect cleanup function. |
|
|
319
302
|
|
|
303
|
+
Specific hook call predicates (context pre-bound):
|
|
304
|
+
|
|
305
|
+
| Predicate | Description |
|
|
306
|
+
| -------------------------- | ------------------------------------------------ |
|
|
307
|
+
| `useActionStateCall` | Whether a node is a `useActionState` call. |
|
|
308
|
+
| `useCallbackCall` | Whether a node is a `useCallback` call. |
|
|
309
|
+
| `useContextCall` | Whether a node is a `useContext` call. |
|
|
310
|
+
| `useDebugValueCall` | Whether a node is a `useDebugValue` call. |
|
|
311
|
+
| `useDeferredValueCall` | Whether a node is a `useDeferredValue` call. |
|
|
312
|
+
| `useEffectCall` | Whether a node is a `useEffect` call. |
|
|
313
|
+
| `useFormStatusCall` | Whether a node is a `useFormStatus` call. |
|
|
314
|
+
| `useIdCall` | Whether a node is a `useId` call. |
|
|
315
|
+
| `useImperativeHandleCall` | Whether a node is a `useImperativeHandle` call. |
|
|
316
|
+
| `useInsertionEffectCall` | Whether a node is a `useInsertionEffect` call. |
|
|
317
|
+
| `useLayoutEffectCall` | Whether a node is a `useLayoutEffect` call. |
|
|
318
|
+
| `useMemoCall` | Whether a node is a `useMemo` call. |
|
|
319
|
+
| `useOptimisticCall` | Whether a node is a `useOptimistic` call. |
|
|
320
|
+
| `useReducerCall` | Whether a node is a `useReducer` call. |
|
|
321
|
+
| `useRefCall` | Whether a node is a `useRef` call. |
|
|
322
|
+
| `useStateCall` | Whether a node is a `useState` call. |
|
|
323
|
+
| `useSyncExternalStoreCall` | Whether a node is a `useSyncExternalStore` call. |
|
|
324
|
+
| `useTransitionCall` | Whether a node is a `useTransition` call. |
|
|
325
|
+
|
|
320
326
|
##### React API
|
|
321
327
|
|
|
322
328
|
Factory functions (context pre-bound):
|
|
@@ -337,9 +343,11 @@ Pre-built call predicates (context pre-bound):
|
|
|
337
343
|
- `cloneElementCall`
|
|
338
344
|
- `createContextCall`
|
|
339
345
|
- `createElementCall`
|
|
346
|
+
- `createRefCall`
|
|
340
347
|
- `forwardRefCall`
|
|
341
|
-
- `memoCall`
|
|
342
348
|
- `lazyCall`
|
|
349
|
+
- `memoCall`
|
|
350
|
+
- `useCall`
|
|
343
351
|
|
|
344
352
|
All React API predicates and factories have `context` pre-bound — no need to pass the rule context manually:
|
|
345
353
|
|
|
@@ -351,7 +359,7 @@ is.memoCall(node);
|
|
|
351
359
|
nodes.filter(is.memoCall);
|
|
352
360
|
|
|
353
361
|
// Factory for any API name
|
|
354
|
-
const isCreateRefCall = is.
|
|
362
|
+
const isCreateRefCall = is.APICall("createRef");
|
|
355
363
|
isCreateRefCall(node);
|
|
356
364
|
```
|
|
357
365
|
|
|
@@ -364,7 +372,7 @@ isCreateRefCall(node);
|
|
|
364
372
|
|
|
365
373
|
---
|
|
366
374
|
|
|
367
|
-
#### `
|
|
375
|
+
#### `hint`
|
|
368
376
|
|
|
369
377
|
Bit-flags that control what the component collector considers a "component". Combine with bitwise OR (`|`) and remove with bitwise AND-NOT (`& ~`).
|
|
370
378
|
|
|
@@ -391,7 +399,7 @@ const { query, visitor } = collect.components(context, {
|
|
|
391
399
|
|
|
392
400
|
---
|
|
393
401
|
|
|
394
|
-
#### `
|
|
402
|
+
#### `flag`
|
|
395
403
|
|
|
396
404
|
Bit-flags indicating component characteristics. Check with bitwise AND (`&`).
|
|
397
405
|
|
|
@@ -411,7 +419,7 @@ for (const component of query.all(program)) {
|
|
|
411
419
|
}
|
|
412
420
|
```
|
|
413
421
|
|
|
414
|
-
#### `
|
|
422
|
+
#### `settings`
|
|
415
423
|
|
|
416
424
|
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
425
|
|
|
@@ -451,7 +459,7 @@ function version(major = "19"): RuleFunction {
|
|
|
451
459
|
|
|
452
460
|
### Simple: Ban `forwardRef`
|
|
453
461
|
|
|
454
|
-
This is a simplified kit reimplementation of the built-in [`react-x/no-forwardRef`](https://
|
|
462
|
+
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
463
|
|
|
456
464
|
```ts
|
|
457
465
|
import type { RuleFunction } from "@eslint-react/kit";
|
|
@@ -474,7 +482,7 @@ eslintReactKit()
|
|
|
474
482
|
|
|
475
483
|
### Component: Destructure component props
|
|
476
484
|
|
|
477
|
-
This is a simplified kit reimplementation of the built-in [`react-x/prefer-destructuring-assignment`](https://
|
|
485
|
+
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
486
|
|
|
479
487
|
```ts
|
|
480
488
|
import type { RuleFunction } from "@eslint-react/kit";
|
|
@@ -515,7 +523,7 @@ eslintReactKit()
|
|
|
515
523
|
|
|
516
524
|
### Hooks: Warn on custom hooks that don't call other hooks
|
|
517
525
|
|
|
518
|
-
This is a simplified kit reimplementation of the built-in [`react-x/no-unnecessary-use-prefix`](https://
|
|
526
|
+
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
527
|
|
|
520
528
|
```ts
|
|
521
529
|
import type { RuleFunction } from "@eslint-react/kit";
|
|
@@ -549,7 +557,7 @@ eslintReactKit()
|
|
|
549
557
|
### Multiple Collectors: No component/hook factories
|
|
550
558
|
|
|
551
559
|
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://
|
|
560
|
+
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
561
|
|
|
554
562
|
```ts
|
|
555
563
|
import type { RuleFunction } from "@eslint-react/kit";
|
|
@@ -609,7 +617,7 @@ import type { RuleFunction } from "@eslint-react/kit";
|
|
|
609
617
|
export default [
|
|
610
618
|
{
|
|
611
619
|
...eslintReactKit()
|
|
612
|
-
.use(noForwardRef)
|
|
620
|
+
.use(noForwardRef)
|
|
613
621
|
.use(version, "19")
|
|
614
622
|
.getConfig(),
|
|
615
623
|
// Override `name` so it shows your own label in config inspector tools
|
|
@@ -631,8 +639,8 @@ import eslintReactKit from "@eslint-react/kit";
|
|
|
631
639
|
import type { RuleFunction } from "@eslint-react/kit";
|
|
632
640
|
|
|
633
641
|
const kit = eslintReactKit()
|
|
634
|
-
.use(noForwardRef)
|
|
635
|
-
.use(version, "19")
|
|
642
|
+
.use(noForwardRef)
|
|
643
|
+
.use(version, "19");
|
|
636
644
|
|
|
637
645
|
// Instead of kit.getConfig(), use kit.getPlugin() for full control:
|
|
638
646
|
const plugin = kit.getPlugin();
|
package/dist/index.d.ts
CHANGED
|
@@ -2435,4 +2435,4 @@ declare module "@typescript-eslint/utils/ts-eslint" {
|
|
|
2435
2435
|
}
|
|
2436
2436
|
}
|
|
2437
2437
|
//#endregion
|
|
2438
|
-
export { Builder, Collector, CollectorWithContext, type RuleFix, type RuleFixer, RuleFunction, type RuleListener, build as default, merge };
|
|
2438
|
+
export { Builder, Collector, CollectorWithContext, type RuleFix, type RuleFixer, RuleFunction, type RuleListener, RuleToolkit, build as default, merge };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/kit",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2-beta.0",
|
|
4
4
|
"description": "ESLint React's utility module for building custom React rules with JavasSript functions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"@typescript-eslint/utils": "^8.58.0",
|
|
40
40
|
"string-ts": "^2.3.1",
|
|
41
41
|
"ulid": "^3.0.2",
|
|
42
|
-
"@eslint-react/ast": "5.0.
|
|
43
|
-
"@eslint-react/core": "5.0.
|
|
44
|
-
"@eslint-react/shared": "5.0.
|
|
42
|
+
"@eslint-react/ast": "5.0.2-beta.0",
|
|
43
|
+
"@eslint-react/core": "5.0.2-beta.0",
|
|
44
|
+
"@eslint-react/shared": "5.0.2-beta.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"eslint": "^10.2.0",
|