@eslint-react/kit 4.0.1-beta.0 → 4.0.1-beta.1
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 +22 -8
- package/dist/index.d.ts +11 -11
- package/dist/index.js +56 -64
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ ESLint React's toolkit for building custom React lint rules right inside your `e
|
|
|
9
9
|
- [API Reference](#api-reference)
|
|
10
10
|
- [`eslintReactKit` (default export)](#eslintreactkit-default-export)
|
|
11
11
|
- [`RuleDefinition`](#ruledefinition)
|
|
12
|
-
- [`
|
|
12
|
+
- [`Builder`](#builder)
|
|
13
13
|
- [`merge`](#merge)
|
|
14
14
|
- [`Kit` — the toolkit object](#kit--the-toolkit-object)
|
|
15
15
|
- [`kit.collect`](#kitcollect) — Semantic collectors
|
|
@@ -85,10 +85,10 @@ The rule name is derived automatically from the function name (`functionComponen
|
|
|
85
85
|
```ts
|
|
86
86
|
import eslintReactKit from "@eslint-react/kit";
|
|
87
87
|
|
|
88
|
-
eslintReactKit():
|
|
88
|
+
eslintReactKit(): Builder
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
Creates a `
|
|
91
|
+
Creates a `Builder` instance for registering custom rules via the chainable `.use()` API.
|
|
92
92
|
|
|
93
93
|
### `RuleDefinition`
|
|
94
94
|
|
|
@@ -115,11 +115,11 @@ function forbidElements({ forbidden }: ForbidElementsOptions): RuleDefinition {
|
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
### `
|
|
118
|
+
### `Builder`
|
|
119
119
|
|
|
120
120
|
```ts
|
|
121
|
-
interface
|
|
122
|
-
use<F extends (...args: any[]) => RuleDefinition>(factory: F, ...args: Parameters<F>):
|
|
121
|
+
interface Builder {
|
|
122
|
+
use<F extends (...args: any[]) => RuleDefinition>(factory: F, ...args: Parameters<F>): Builder;
|
|
123
123
|
getConfig(): Linter.Config;
|
|
124
124
|
}
|
|
125
125
|
```
|
|
@@ -317,6 +317,8 @@ Exposes the normalized `react-x` settings from the ESLint shared configuration (
|
|
|
317
317
|
**Usage:**
|
|
318
318
|
|
|
319
319
|
```ts
|
|
320
|
+
import type { RuleDefinition } from "@eslint-react/kit";
|
|
321
|
+
|
|
320
322
|
function requireReact19(): RuleDefinition {
|
|
321
323
|
return (context, { settings }) => ({
|
|
322
324
|
Program(program) {
|
|
@@ -340,6 +342,8 @@ function requireReact19(): RuleDefinition {
|
|
|
340
342
|
This is a simplified kit reimplementation of the built-in [`react-x/no-forwardRef`](https://beta.eslint-react.xyz/docs/rules/no-forward-ref) rule.
|
|
341
343
|
|
|
342
344
|
```ts
|
|
345
|
+
import type { RuleDefinition } from "@eslint-react/kit";
|
|
346
|
+
|
|
343
347
|
function noForwardRef(): RuleDefinition {
|
|
344
348
|
return (context, { is }) => ({
|
|
345
349
|
CallExpression(node) {
|
|
@@ -361,6 +365,9 @@ eslintReactKit()
|
|
|
361
365
|
This is a simplified kit reimplementation of the built-in [`react-x/prefer-destructuring-assignment`](https://beta.eslint-react.xyz/docs/rules/prefer-destructuring-assignment) rule.
|
|
362
366
|
|
|
363
367
|
```ts
|
|
368
|
+
import type { RuleDefinition } from "@eslint-react/kit";
|
|
369
|
+
import { merge } from "@eslint-react/kit";
|
|
370
|
+
|
|
364
371
|
function destructureComponentProps(): RuleDefinition {
|
|
365
372
|
return (context, { collect }) => {
|
|
366
373
|
const { query, visitor } = collect.components(context);
|
|
@@ -370,13 +377,13 @@ function destructureComponentProps(): RuleDefinition {
|
|
|
370
377
|
for (const { node } of query.all(program)) {
|
|
371
378
|
const [props] = node.params;
|
|
372
379
|
if (props == null) continue;
|
|
373
|
-
if (props.type !==
|
|
380
|
+
if (props.type !== "Identifier") continue;
|
|
374
381
|
const propName = props.name;
|
|
375
382
|
const propVariable = context.sourceCode.getScope(node).variables.find((v) => v.name === propName);
|
|
376
383
|
const propReferences = propVariable?.references ?? [];
|
|
377
384
|
for (const ref of propReferences) {
|
|
378
385
|
const { parent } = ref.identifier;
|
|
379
|
-
if (parent.type !==
|
|
386
|
+
if (parent.type !== "MemberExpression") continue;
|
|
380
387
|
context.report({
|
|
381
388
|
message: "Use destructuring assignment for component props.",
|
|
382
389
|
node: parent,
|
|
@@ -399,6 +406,9 @@ eslintReactKit()
|
|
|
399
406
|
This is a simplified kit reimplementation of the built-in [`react-x/no-unnecessary-use-prefix`](https://beta.eslint-react.xyz/docs/rules/no-unnecessary-use-prefix) rule.
|
|
400
407
|
|
|
401
408
|
```ts
|
|
409
|
+
import type { RuleDefinition } from "@eslint-react/kit";
|
|
410
|
+
import { merge } from "@eslint-react/kit";
|
|
411
|
+
|
|
402
412
|
function noUnnecessaryUsePrefix(): RuleDefinition {
|
|
403
413
|
return (context, { collect }) => {
|
|
404
414
|
const { query, visitor } = collect.hooks(context);
|
|
@@ -430,6 +440,10 @@ Disallow defining components or hooks inside other functions (factory pattern).
|
|
|
430
440
|
This is a simplified kit reimplementation of the built-in [`react-x/component-hook-factories`](https://beta.eslint-react.xyz/docs/rules/component-hook-factories) rule.
|
|
431
441
|
|
|
432
442
|
```ts
|
|
443
|
+
import type { RuleDefinition } from "@eslint-react/kit";
|
|
444
|
+
import { merge } from "@eslint-react/kit";
|
|
445
|
+
import type { TSESTree } from "@typescript-eslint/utils";
|
|
446
|
+
|
|
433
447
|
function findParent({ parent }: TSESTree.Node, test: (n: TSESTree.Node) => boolean): TSESTree.Node | null {
|
|
434
448
|
if (parent == null) return null;
|
|
435
449
|
if (test(parent)) return parent;
|
package/dist/index.d.ts
CHANGED
|
@@ -17,20 +17,13 @@ interface CollectorWithContext<T> extends Collector<T> {
|
|
|
17
17
|
all(program: TSESTree.Program): T[];
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
-
type RuleDefinition = (ctx: RuleContext, kit: RuleToolkit) => RuleListener;
|
|
21
|
-
interface KitBuilder {
|
|
22
|
-
getConfig(args?: {
|
|
23
|
-
files?: string[];
|
|
24
|
-
}): Linter.Config;
|
|
25
|
-
use<F extends (...args: any[]) => RuleDefinition>(factory: F, ...args: Parameters<F>): KitBuilder;
|
|
26
|
-
}
|
|
27
20
|
interface RuleToolkit {
|
|
28
21
|
collect: {
|
|
29
|
-
components(
|
|
22
|
+
components(context: RuleContext, options?: {
|
|
30
23
|
collectDisplayName?: boolean;
|
|
31
24
|
hint?: bigint;
|
|
32
25
|
}): CollectorWithContext<core.FunctionComponentSemanticNode>;
|
|
33
|
-
hooks(
|
|
26
|
+
hooks(context: RuleContext): CollectorWithContext<core.HookSemanticNode>;
|
|
34
27
|
};
|
|
35
28
|
flag: {
|
|
36
29
|
component: typeof core.ComponentFlag;
|
|
@@ -106,7 +99,14 @@ interface RuleToolkit {
|
|
|
106
99
|
};
|
|
107
100
|
settings: ESLintReactSettingsNormalized;
|
|
108
101
|
}
|
|
109
|
-
|
|
102
|
+
type RuleDefinition = (context: RuleContext, toolkit: RuleToolkit) => RuleListener;
|
|
103
|
+
interface Builder {
|
|
104
|
+
getConfig(args?: {
|
|
105
|
+
files?: string[];
|
|
106
|
+
}): Linter.Config;
|
|
107
|
+
use<F extends (...args: any[]) => RuleDefinition>(factory: F, ...args: Parameters<F>): Builder;
|
|
108
|
+
}
|
|
109
|
+
declare function eslintReactKit(): Builder;
|
|
110
110
|
declare module "@typescript-eslint/utils/ts-eslint" {
|
|
111
111
|
interface RuleContext<MessageIds extends string = string, Options extends readonly unknown[] = readonly unknown[]> {
|
|
112
112
|
report(descriptor: {
|
|
@@ -124,4 +124,4 @@ declare module "@typescript-eslint/utils/ts-eslint" {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
//#endregion
|
|
127
|
-
export { Collector, CollectorWithContext,
|
|
127
|
+
export { Builder, Collector, CollectorWithContext, RuleDefinition, type RuleFix, type RuleFixer, type RuleListener, eslintReactKit as default, merge };
|
package/dist/index.js
CHANGED
|
@@ -4,15 +4,15 @@ import { kebabCase } from "string-ts";
|
|
|
4
4
|
|
|
5
5
|
//#region package.json
|
|
6
6
|
var name = "@eslint-react/kit";
|
|
7
|
-
var version = "4.0.1-beta.
|
|
7
|
+
var version = "4.0.1-beta.1";
|
|
8
8
|
|
|
9
9
|
//#endregion
|
|
10
10
|
//#region src/index.ts
|
|
11
|
-
function
|
|
11
|
+
function makeRuleToolkit(context) {
|
|
12
12
|
return {
|
|
13
13
|
collect: {
|
|
14
|
-
components(
|
|
15
|
-
const { api, visitor } = core.getComponentCollector(
|
|
14
|
+
components(context, options) {
|
|
15
|
+
const { api, visitor } = core.getComponentCollector(context, options);
|
|
16
16
|
return {
|
|
17
17
|
query: { all(program) {
|
|
18
18
|
return api.getAllComponents(program);
|
|
@@ -20,8 +20,8 @@ function createKit(ctx) {
|
|
|
20
20
|
visitor
|
|
21
21
|
};
|
|
22
22
|
},
|
|
23
|
-
hooks(
|
|
24
|
-
const { api, visitor } = core.getHookCollector(
|
|
23
|
+
hooks(context) {
|
|
24
|
+
const { api, visitor } = core.getHookCollector(context);
|
|
25
25
|
return {
|
|
26
26
|
query: { all(program) {
|
|
27
27
|
return api.getAllHooks(program);
|
|
@@ -36,45 +36,45 @@ function createKit(ctx) {
|
|
|
36
36
|
Default: core.DEFAULT_COMPONENT_DETECTION_HINT
|
|
37
37
|
} },
|
|
38
38
|
is: {
|
|
39
|
-
captureOwnerStack: core.isCaptureOwnerStack(
|
|
40
|
-
captureOwnerStackCall: core.isCaptureOwnerStackCall(
|
|
41
|
-
childrenCount: core.isChildrenCount(
|
|
42
|
-
childrenCountCall: core.isChildrenCountCall(
|
|
43
|
-
childrenForEach: core.isChildrenForEach(
|
|
44
|
-
childrenForEachCall: core.isChildrenForEachCall(
|
|
45
|
-
childrenMap: core.isChildrenMap(
|
|
46
|
-
childrenMapCall: core.isChildrenMapCall(
|
|
47
|
-
childrenOnly: core.isChildrenOnly(
|
|
48
|
-
childrenOnlyCall: core.isChildrenOnlyCall(
|
|
49
|
-
childrenToArray: core.isChildrenToArray(
|
|
50
|
-
childrenToArrayCall: core.isChildrenToArrayCall(
|
|
51
|
-
cloneElement: core.isCloneElement(
|
|
52
|
-
cloneElementCall: core.isCloneElementCall(
|
|
53
|
-
componentDefinition: (node, hint) => core.isComponentDefinition(
|
|
39
|
+
captureOwnerStack: core.isCaptureOwnerStack(context),
|
|
40
|
+
captureOwnerStackCall: core.isCaptureOwnerStackCall(context),
|
|
41
|
+
childrenCount: core.isChildrenCount(context),
|
|
42
|
+
childrenCountCall: core.isChildrenCountCall(context),
|
|
43
|
+
childrenForEach: core.isChildrenForEach(context),
|
|
44
|
+
childrenForEachCall: core.isChildrenForEachCall(context),
|
|
45
|
+
childrenMap: core.isChildrenMap(context),
|
|
46
|
+
childrenMapCall: core.isChildrenMapCall(context),
|
|
47
|
+
childrenOnly: core.isChildrenOnly(context),
|
|
48
|
+
childrenOnlyCall: core.isChildrenOnlyCall(context),
|
|
49
|
+
childrenToArray: core.isChildrenToArray(context),
|
|
50
|
+
childrenToArrayCall: core.isChildrenToArrayCall(context),
|
|
51
|
+
cloneElement: core.isCloneElement(context),
|
|
52
|
+
cloneElementCall: core.isCloneElementCall(context),
|
|
53
|
+
componentDefinition: (node, hint) => core.isComponentDefinition(context, node, hint),
|
|
54
54
|
componentName: core.isComponentName,
|
|
55
55
|
componentNameLoose: core.isComponentNameLoose,
|
|
56
|
-
componentWrapperCall: (node) => core.isComponentWrapperCall(
|
|
57
|
-
componentWrapperCallback: (node) => core.isComponentWrapperCallback(
|
|
58
|
-
componentWrapperCallLoose: (node) => core.isComponentWrapperCallLoose(
|
|
59
|
-
createContext: core.isCreateContext(
|
|
60
|
-
createContextCall: core.isCreateContextCall(
|
|
61
|
-
createElement: core.isCreateElement(
|
|
62
|
-
createElementCall: core.isCreateElementCall(
|
|
63
|
-
createRef: core.isCreateRef(
|
|
64
|
-
createRefCall: core.isCreateRefCall(
|
|
65
|
-
forwardRef: core.isForwardRef(
|
|
66
|
-
forwardRefCall: core.isForwardRefCall(
|
|
56
|
+
componentWrapperCall: (node) => core.isComponentWrapperCall(context, node),
|
|
57
|
+
componentWrapperCallback: (node) => core.isComponentWrapperCallback(context, node),
|
|
58
|
+
componentWrapperCallLoose: (node) => core.isComponentWrapperCallLoose(context, node),
|
|
59
|
+
createContext: core.isCreateContext(context),
|
|
60
|
+
createContextCall: core.isCreateContextCall(context),
|
|
61
|
+
createElement: core.isCreateElement(context),
|
|
62
|
+
createElementCall: core.isCreateElementCall(context),
|
|
63
|
+
createRef: core.isCreateRef(context),
|
|
64
|
+
createRefCall: core.isCreateRefCall(context),
|
|
65
|
+
forwardRef: core.isForwardRef(context),
|
|
66
|
+
forwardRefCall: core.isForwardRefCall(context),
|
|
67
67
|
hook: core.isHook,
|
|
68
68
|
hookCall: core.isHookCall,
|
|
69
69
|
hookName: core.isHookName,
|
|
70
70
|
initializedFromReact: core.isInitializedFromReact,
|
|
71
71
|
initializedFromReactNative: core.isInitializedFromReactNative,
|
|
72
|
-
lazy: core.isLazy(
|
|
73
|
-
lazyCall: core.isLazyCall(
|
|
74
|
-
memo: core.isMemo(
|
|
75
|
-
memoCall: core.isMemoCall(
|
|
76
|
-
reactAPI: (api) => core.isReactAPI(api)(
|
|
77
|
-
reactAPICall: (api) => core.isReactAPICall(api)(
|
|
72
|
+
lazy: core.isLazy(context),
|
|
73
|
+
lazyCall: core.isLazyCall(context),
|
|
74
|
+
memo: core.isMemo(context),
|
|
75
|
+
memoCall: core.isMemoCall(context),
|
|
76
|
+
reactAPI: (api) => core.isReactAPI(api)(context),
|
|
77
|
+
reactAPICall: (api) => core.isReactAPICall(api)(context),
|
|
78
78
|
useActionStateCall: core.isUseActionStateCall,
|
|
79
79
|
useCall: core.isUseCall,
|
|
80
80
|
useCallbackCall: core.isUseCallbackCall,
|
|
@@ -99,45 +99,37 @@ function createKit(ctx) {
|
|
|
99
99
|
useSyncExternalStoreCall: core.isUseSyncExternalStoreCall,
|
|
100
100
|
useTransitionCall: core.isUseTransitionCall
|
|
101
101
|
},
|
|
102
|
-
settings: getSettingsFromContext(
|
|
102
|
+
settings: getSettingsFromContext(context)
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
105
|
function eslintReactKit() {
|
|
106
106
|
const idGen = new IdGenerator();
|
|
107
|
-
const
|
|
107
|
+
const plugin = {
|
|
108
|
+
meta: {
|
|
109
|
+
name,
|
|
110
|
+
version
|
|
111
|
+
},
|
|
112
|
+
rules: {}
|
|
113
|
+
};
|
|
108
114
|
const builder = {
|
|
109
115
|
getConfig({ files = ["**/*.ts", "**/*.tsx"] } = {}) {
|
|
110
116
|
return {
|
|
111
117
|
files,
|
|
112
|
-
plugins: { [name]:
|
|
113
|
-
|
|
114
|
-
name,
|
|
115
|
-
version
|
|
116
|
-
},
|
|
117
|
-
rules: rules.reduce((acc, { name, make }) => {
|
|
118
|
-
Reflect.set(acc, name, {
|
|
119
|
-
meta: {
|
|
120
|
-
fixable: "code",
|
|
121
|
-
hasSuggestions: true
|
|
122
|
-
},
|
|
123
|
-
create(ctx) {
|
|
124
|
-
return make(ctx, createKit(ctx));
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
return acc;
|
|
128
|
-
}, {})
|
|
129
|
-
} },
|
|
130
|
-
rules: rules.reduce((acc, { name: name$1 }) => {
|
|
118
|
+
plugins: { [name]: plugin },
|
|
119
|
+
rules: Object.keys(plugin.rules).reduce((acc, name$1) => {
|
|
131
120
|
acc[`${name}/${name$1}`] = "error";
|
|
132
121
|
return acc;
|
|
133
122
|
}, {})
|
|
134
123
|
};
|
|
135
124
|
},
|
|
136
|
-
use(
|
|
137
|
-
const name = kebabCase(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
125
|
+
use(make, ...args) {
|
|
126
|
+
const name = kebabCase(make.name === "" ? idGen.next() : make.name);
|
|
127
|
+
Reflect.set(plugin.rules, name, {
|
|
128
|
+
meta: {
|
|
129
|
+
fixable: "code",
|
|
130
|
+
hasSuggestions: true
|
|
131
|
+
},
|
|
132
|
+
create: (context) => make(...args)(context, makeRuleToolkit(context))
|
|
141
133
|
});
|
|
142
134
|
return builder;
|
|
143
135
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/kit",
|
|
3
|
-
"version": "4.0.1-beta.
|
|
3
|
+
"version": "4.0.1-beta.1",
|
|
4
4
|
"description": "ESLint React's utility module for building custom rules.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@typescript-eslint/utils": "^8.57.2",
|
|
40
40
|
"string-ts": "^2.3.1",
|
|
41
|
-
"@eslint-react/
|
|
42
|
-
"@eslint-react/
|
|
43
|
-
"@eslint-react/
|
|
41
|
+
"@eslint-react/ast": "4.0.1-beta.1",
|
|
42
|
+
"@eslint-react/core": "4.0.1-beta.1",
|
|
43
|
+
"@eslint-react/shared": "4.0.1-beta.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"eslint": "^10.1.0",
|