@eslint-react/core 1.52.10-next.0 → 1.52.10-next.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/dist/index.d.mts +218 -176
- package/dist/index.d.ts +218 -176
- package/dist/index.js +978 -823
- package/dist/index.mjs +966 -808
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,983 +1,1138 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
enumerable: true,
|
|
23
|
-
get: function () { return e[k]; }
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
n.default = e;
|
|
29
|
-
return Object.freeze(n);
|
|
30
|
-
}
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
31
22
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
//#endregion
|
|
24
|
+
const __eslint_react_ast = __toESM(require("@eslint-react/ast"));
|
|
25
|
+
const __eslint_react_eff = __toESM(require("@eslint-react/eff"));
|
|
26
|
+
const __eslint_react_kit = __toESM(require("@eslint-react/kit"));
|
|
27
|
+
const __eslint_react_shared = __toESM(require("@eslint-react/shared"));
|
|
28
|
+
const __typescript_eslint_types = __toESM(require("@typescript-eslint/types"));
|
|
29
|
+
const __eslint_react_var = __toESM(require("@eslint-react/var"));
|
|
30
|
+
const ts_pattern = __toESM(require("ts-pattern"));
|
|
31
|
+
const birecord = __toESM(require("birecord"));
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
//#region src/utils/get-instance-id.ts
|
|
34
|
+
/** @internal */
|
|
37
35
|
function getInstanceId(node, prev) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
case (node.type === types.AST_NODE_TYPES.BlockStatement || node.type === types.AST_NODE_TYPES.Program || node.parent === node):
|
|
46
|
-
return eff.unit;
|
|
47
|
-
default:
|
|
48
|
-
return getInstanceId(node.parent, node);
|
|
49
|
-
}
|
|
36
|
+
switch (true) {
|
|
37
|
+
case node.type === __typescript_eslint_types.AST_NODE_TYPES.VariableDeclarator && node.init === prev: return node.id;
|
|
38
|
+
case node.type === __typescript_eslint_types.AST_NODE_TYPES.AssignmentExpression && node.right === prev: return node.left;
|
|
39
|
+
case node.type === __typescript_eslint_types.AST_NODE_TYPES.PropertyDefinition && node.value === prev: return node.key;
|
|
40
|
+
case node.type === __typescript_eslint_types.AST_NODE_TYPES.BlockStatement || node.type === __typescript_eslint_types.AST_NODE_TYPES.Program || node.parent === node: return __eslint_react_eff.unit;
|
|
41
|
+
default: return getInstanceId(node.parent, node);
|
|
42
|
+
}
|
|
50
43
|
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/utils/is-from-react.ts
|
|
47
|
+
/**
|
|
48
|
+
* Get the arguments of a require expression
|
|
49
|
+
* @param node The node to match
|
|
50
|
+
* @returns The require expression arguments or undefined if the node is not a require expression
|
|
51
|
+
*/
|
|
51
52
|
function getRequireExpressionArguments(node) {
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
return (0, ts_pattern.match)(node).with({
|
|
54
|
+
type: __typescript_eslint_types.AST_NODE_TYPES.CallExpression,
|
|
55
|
+
arguments: ts_pattern.P.select(),
|
|
56
|
+
callee: {
|
|
57
|
+
type: __typescript_eslint_types.AST_NODE_TYPES.Identifier,
|
|
58
|
+
name: "require"
|
|
59
|
+
}
|
|
60
|
+
}, __eslint_react_eff.identity).with({
|
|
61
|
+
type: __typescript_eslint_types.AST_NODE_TYPES.MemberExpression,
|
|
62
|
+
object: ts_pattern.P.select()
|
|
63
|
+
}, getRequireExpressionArguments).otherwise(() => null);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Check if an identifier name is initialized from react
|
|
67
|
+
* @param name The top-level identifier's name
|
|
68
|
+
* @param importSource The import source to check against
|
|
69
|
+
* @param initialScope Initial scope to search for the identifier
|
|
70
|
+
* @returns Whether the identifier name is initialized from react
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
54
73
|
function isInitializedFromReact(name, importSource, initialScope) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (arg0 == null || !AST9__namespace.isLiteral(arg0, "string")) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
return arg0.value === importSource || arg0.value.startsWith(`${importSource}/`);
|
|
73
|
-
}
|
|
74
|
-
return parent?.type === types.AST_NODE_TYPES.ImportDeclaration && parent.source.value === importSource;
|
|
74
|
+
if (name.toLowerCase() === "react") return true;
|
|
75
|
+
const latestDef = __eslint_react_var.findVariable(name, initialScope)?.defs.at(-1);
|
|
76
|
+
if (latestDef == null) return false;
|
|
77
|
+
const { node, parent } = latestDef;
|
|
78
|
+
if (node.type === __typescript_eslint_types.AST_NODE_TYPES.VariableDeclarator && node.init != null) {
|
|
79
|
+
const { init } = node;
|
|
80
|
+
if (init.type === __typescript_eslint_types.AST_NODE_TYPES.MemberExpression && init.object.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier) return isInitializedFromReact(init.object.name, importSource, initialScope);
|
|
81
|
+
if (init.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier) return isInitializedFromReact(init.name, importSource, initialScope);
|
|
82
|
+
const args = getRequireExpressionArguments(init);
|
|
83
|
+
const arg0 = args?.[0];
|
|
84
|
+
if (arg0 == null || !__eslint_react_ast.isLiteral(arg0, "string")) return false;
|
|
85
|
+
return arg0.value === importSource || arg0.value.startsWith(`${importSource}/`);
|
|
86
|
+
}
|
|
87
|
+
return parent?.type === __typescript_eslint_types.AST_NODE_TYPES.ImportDeclaration && parent.source.value === importSource;
|
|
75
88
|
}
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/utils/is-instance-id-equal.ts
|
|
92
|
+
/** @internal */
|
|
76
93
|
function isInstanceIdEqual(context, a, b) {
|
|
77
|
-
|
|
78
|
-
context.sourceCode.getScope(a),
|
|
79
|
-
context.sourceCode.getScope(b)
|
|
80
|
-
]);
|
|
94
|
+
return __eslint_react_ast.isNodeEqual(a, b) || __eslint_react_var.isNodeValueEqual(a, b, [context.sourceCode.getScope(a), context.sourceCode.getScope(b)]);
|
|
81
95
|
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/utils/is-react-api.ts
|
|
82
99
|
function isReactAPI(api) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
const func = (context, node) => {
|
|
101
|
+
if (node == null) return false;
|
|
102
|
+
const getText = (n) => context.sourceCode.getText(n);
|
|
103
|
+
const name = __eslint_react_ast.toString(node, getText);
|
|
104
|
+
if (name === api) return true;
|
|
105
|
+
if (name.substring(name.indexOf(".") + 1) === api) return true;
|
|
106
|
+
return false;
|
|
107
|
+
};
|
|
108
|
+
return (0, __eslint_react_eff.dual)(2, func);
|
|
92
109
|
}
|
|
93
110
|
function isReactAPICall(api) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
111
|
+
const func = (context, node) => {
|
|
112
|
+
if (node == null) return false;
|
|
113
|
+
if (node.type !== __typescript_eslint_types.AST_NODE_TYPES.CallExpression) return false;
|
|
114
|
+
return isReactAPI(api)(context, node.callee);
|
|
115
|
+
};
|
|
116
|
+
return (0, __eslint_react_eff.dual)(2, func);
|
|
117
|
+
}
|
|
118
|
+
const isCaptureOwnerStack = isReactAPI("captureOwnerStack");
|
|
119
|
+
const isChildrenCount = isReactAPI("Children.count");
|
|
120
|
+
const isChildrenForEach = isReactAPI("Children.forEach");
|
|
121
|
+
const isChildrenMap = isReactAPI("Children.map");
|
|
122
|
+
const isChildrenOnly = isReactAPI("Children.only");
|
|
123
|
+
const isChildrenToArray = isReactAPI("Children.toArray");
|
|
124
|
+
const isCloneElement = isReactAPI("cloneElement");
|
|
125
|
+
const isCreateContext = isReactAPI("createContext");
|
|
126
|
+
const isCreateElement = isReactAPI("createElement");
|
|
127
|
+
const isCreateRef = isReactAPI("createRef");
|
|
128
|
+
const isForwardRef = isReactAPI("forwardRef");
|
|
129
|
+
const isMemo = isReactAPI("memo");
|
|
130
|
+
const isLazy = isReactAPI("lazy");
|
|
131
|
+
const isCaptureOwnerStackCall = isReactAPICall("captureOwnerStack");
|
|
132
|
+
const isChildrenCountCall = isReactAPICall("Children.count");
|
|
133
|
+
const isChildrenForEachCall = isReactAPICall("Children.forEach");
|
|
134
|
+
const isChildrenMapCall = isReactAPICall("Children.map");
|
|
135
|
+
const isChildrenOnlyCall = isReactAPICall("Children.only");
|
|
136
|
+
const isChildrenToArrayCall = isReactAPICall("Children.toArray");
|
|
137
|
+
const isCloneElementCall = isReactAPICall("cloneElement");
|
|
138
|
+
const isCreateContextCall = isReactAPICall("createContext");
|
|
139
|
+
const isCreateElementCall = isReactAPICall("createElement");
|
|
140
|
+
const isCreateRefCall = isReactAPICall("createRef");
|
|
141
|
+
const isForwardRefCall = isReactAPICall("forwardRef");
|
|
142
|
+
const isMemoCall = isReactAPICall("memo");
|
|
143
|
+
const isLazyCall = isReactAPICall("lazy");
|
|
127
144
|
|
|
128
|
-
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region src/hook/hook-name.ts
|
|
147
|
+
/**
|
|
148
|
+
* Catch all identifiers that begin with "use" followed by an uppercase Latin
|
|
149
|
+
* character to exclude identifiers like "user".
|
|
150
|
+
* @param name The name of the identifier to check.
|
|
151
|
+
* @see https://github.com/facebook/react/blob/1d6c8168db1d82713202e842df3167787ffa00ed/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts#L16
|
|
152
|
+
*/
|
|
129
153
|
function isReactHookName(name) {
|
|
130
|
-
|
|
154
|
+
return name === "use" || /^use[A-Z0-9]/.test(name);
|
|
131
155
|
}
|
|
132
156
|
|
|
133
|
-
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/hook/hook-is.ts
|
|
134
159
|
function isReactHook(node) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
160
|
+
if (node == null) return false;
|
|
161
|
+
const id = __eslint_react_ast.getFunctionId(node);
|
|
162
|
+
return id?.name != null && isReactHookName(id.name);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Check if the given node is a React Hook call by its name.
|
|
166
|
+
* @param node The node to check.
|
|
167
|
+
* @returns `true` if the node is a React Hook call, `false` otherwise.
|
|
168
|
+
*/
|
|
139
169
|
function isReactHookCall(node) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return isReactHookName(node.callee.name);
|
|
146
|
-
}
|
|
147
|
-
if (node.callee.type === types.AST_NODE_TYPES.MemberExpression) {
|
|
148
|
-
return node.callee.property.type === types.AST_NODE_TYPES.Identifier && isReactHookName(node.callee.property.name);
|
|
149
|
-
}
|
|
150
|
-
return false;
|
|
170
|
+
if (node == null) return false;
|
|
171
|
+
if (node.type !== __typescript_eslint_types.AST_NODE_TYPES.CallExpression) return false;
|
|
172
|
+
if (node.callee.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier) return isReactHookName(node.callee.name);
|
|
173
|
+
if (node.callee.type === __typescript_eslint_types.AST_NODE_TYPES.MemberExpression) return node.callee.property.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && isReactHookName(node.callee.property.name);
|
|
174
|
+
return false;
|
|
151
175
|
}
|
|
152
176
|
function isReactHookCallWithName(context, node) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
case (node.callee.type === types.AST_NODE_TYPES.MemberExpression && node.callee.property.type === types.AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object):
|
|
164
|
-
return skipImportCheck || isInitializedFromReact(node.callee.object.name, importSource, initialScope);
|
|
165
|
-
default:
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
};
|
|
177
|
+
if (node == null || node.type !== __typescript_eslint_types.AST_NODE_TYPES.CallExpression) return __eslint_react_eff.constFalse;
|
|
178
|
+
const { importSource = __eslint_react_shared.DEFAULT_ESLINT_REACT_SETTINGS.importSource, skipImportCheck = true } = (0, __eslint_react_shared.coerceSettings)(context.settings);
|
|
179
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
180
|
+
return (name) => {
|
|
181
|
+
switch (true) {
|
|
182
|
+
case node.callee.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.callee.name === name: return skipImportCheck || isInitializedFromReact(name, importSource, initialScope);
|
|
183
|
+
case node.callee.type === __typescript_eslint_types.AST_NODE_TYPES.MemberExpression && node.callee.property.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object: return skipImportCheck || isInitializedFromReact(node.callee.object.name, importSource, initialScope);
|
|
184
|
+
default: return false;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
169
187
|
}
|
|
170
188
|
function isReactHookCallWithNameLoose(node) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
};
|
|
189
|
+
if (node == null || node.type !== __typescript_eslint_types.AST_NODE_TYPES.CallExpression) return __eslint_react_eff.constFalse;
|
|
190
|
+
return (name) => {
|
|
191
|
+
switch (node.callee.type) {
|
|
192
|
+
case __typescript_eslint_types.AST_NODE_TYPES.Identifier: return node.callee.name === name;
|
|
193
|
+
case __typescript_eslint_types.AST_NODE_TYPES.MemberExpression: return node.callee.property.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.callee.property.name === name;
|
|
194
|
+
default: return false;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
182
197
|
}
|
|
183
198
|
function isReactHookCallWithNameAlias(context, name, alias = []) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
case (node.callee.type === types.AST_NODE_TYPES.MemberExpression && node.callee.property.type === types.AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object):
|
|
194
|
-
return skipImportCheck || isInitializedFromReact(node.callee.object.name, importSource, initialScope);
|
|
195
|
-
default:
|
|
196
|
-
return alias.some(isReactHookCallWithNameLoose(node));
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
+
const { importSource = __eslint_react_shared.DEFAULT_ESLINT_REACT_SETTINGS.importSource, skipImportCheck = true } = (0, __eslint_react_shared.coerceSettings)(context.settings);
|
|
200
|
+
return (node) => {
|
|
201
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
202
|
+
switch (true) {
|
|
203
|
+
case node.callee.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.callee.name === name: return skipImportCheck || isInitializedFromReact(name, importSource, initialScope);
|
|
204
|
+
case node.callee.type === __typescript_eslint_types.AST_NODE_TYPES.MemberExpression && node.callee.property.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object: return skipImportCheck || isInitializedFromReact(node.callee.object.name, importSource, initialScope);
|
|
205
|
+
default: return alias.some(isReactHookCallWithNameLoose(node));
|
|
206
|
+
}
|
|
207
|
+
};
|
|
199
208
|
}
|
|
200
209
|
function isUseEffectCallLoose(node) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
var isUseReducerCall = eff.flip(isReactHookCallWithName)("useReducer");
|
|
229
|
-
var isUseRefCall = eff.flip(isReactHookCallWithName)("useRef");
|
|
230
|
-
var isUseStateCall = eff.flip(isReactHookCallWithName)("useState");
|
|
231
|
-
var isUseSyncExternalStoreCall = eff.flip(isReactHookCallWithName)("useSyncExternalStore");
|
|
232
|
-
var isUseTransitionCall = eff.flip(isReactHookCallWithName)("useTransition");
|
|
210
|
+
if (node == null) return false;
|
|
211
|
+
if (node.type !== __typescript_eslint_types.AST_NODE_TYPES.CallExpression) return false;
|
|
212
|
+
switch (node.callee.type) {
|
|
213
|
+
case __typescript_eslint_types.AST_NODE_TYPES.Identifier: return /^use\w*Effect$/u.test(node.callee.name);
|
|
214
|
+
case __typescript_eslint_types.AST_NODE_TYPES.MemberExpression: return node.callee.property.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && /^use\w*Effect$/u.test(node.callee.property.name);
|
|
215
|
+
default: return false;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const isUseCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("use");
|
|
219
|
+
const isUseActionStateCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useActionState");
|
|
220
|
+
const isUseCallbackCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useCallback");
|
|
221
|
+
const isUseContextCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useContext");
|
|
222
|
+
const isUseDebugValueCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useDebugValue");
|
|
223
|
+
const isUseDeferredValueCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useDeferredValue");
|
|
224
|
+
const isUseEffectCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useEffect");
|
|
225
|
+
const isUseFormStatusCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useFormStatus");
|
|
226
|
+
const isUseIdCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useId");
|
|
227
|
+
const isUseImperativeHandleCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useImperativeHandle");
|
|
228
|
+
const isUseInsertionEffectCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useInsertionEffect");
|
|
229
|
+
const isUseLayoutEffectCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useLayoutEffect");
|
|
230
|
+
const isUseMemoCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useMemo");
|
|
231
|
+
const isUseOptimisticCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useOptimistic");
|
|
232
|
+
const isUseReducerCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useReducer");
|
|
233
|
+
const isUseRefCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useRef");
|
|
234
|
+
const isUseStateCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useState");
|
|
235
|
+
const isUseSyncExternalStoreCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useSyncExternalStore");
|
|
236
|
+
const isUseTransitionCall = (0, __eslint_react_eff.flip)(isReactHookCallWithName)("useTransition");
|
|
233
237
|
|
|
234
|
-
|
|
238
|
+
//#endregion
|
|
239
|
+
//#region src/hook/hook-collector.ts
|
|
235
240
|
function useHookCollector() {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
241
|
+
const hooks = /* @__PURE__ */ new Map();
|
|
242
|
+
const functionEntries = [];
|
|
243
|
+
const onFunctionEnter = (node) => {
|
|
244
|
+
const id = __eslint_react_ast.getFunctionId(node);
|
|
245
|
+
const key = (0, __eslint_react_shared.getId)();
|
|
246
|
+
const name = id?.name;
|
|
247
|
+
if (name != null && isReactHookName(name)) {
|
|
248
|
+
functionEntries.push({
|
|
249
|
+
key,
|
|
250
|
+
node,
|
|
251
|
+
isHook: true
|
|
252
|
+
});
|
|
253
|
+
hooks.set(key, {
|
|
254
|
+
id,
|
|
255
|
+
key,
|
|
256
|
+
kind: "function",
|
|
257
|
+
name,
|
|
258
|
+
node,
|
|
259
|
+
flag: 0n,
|
|
260
|
+
hint: 0n,
|
|
261
|
+
hookCalls: []
|
|
262
|
+
});
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
functionEntries.push({
|
|
266
|
+
key,
|
|
267
|
+
node,
|
|
268
|
+
isHook: false
|
|
269
|
+
});
|
|
270
|
+
};
|
|
271
|
+
const onFunctionExit = () => {
|
|
272
|
+
functionEntries.pop();
|
|
273
|
+
};
|
|
274
|
+
const ctx = { getAllHooks(node) {
|
|
275
|
+
return hooks;
|
|
276
|
+
} };
|
|
277
|
+
const listeners = {
|
|
278
|
+
":function[type]": onFunctionEnter,
|
|
279
|
+
":function[type]:exit": onFunctionExit,
|
|
280
|
+
"CallExpression[type]"(node) {
|
|
281
|
+
if (!isReactHookCall(node)) return;
|
|
282
|
+
const fEntry = functionEntries.at(-1);
|
|
283
|
+
if (fEntry?.key == null) return;
|
|
284
|
+
const hook = hooks.get(fEntry.key);
|
|
285
|
+
if (hook == null) return;
|
|
286
|
+
hook.hookCalls.push(node);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
return {
|
|
290
|
+
ctx,
|
|
291
|
+
listeners
|
|
292
|
+
};
|
|
286
293
|
}
|
|
294
|
+
|
|
295
|
+
//#endregion
|
|
296
|
+
//#region src/hook/hook-hierarchy.ts
|
|
287
297
|
function isFunctionOfUseEffectSetup(node) {
|
|
288
|
-
|
|
289
|
-
|
|
298
|
+
if (node == null) return false;
|
|
299
|
+
return node.parent?.type === __typescript_eslint_types.AST_NODE_TYPES.CallExpression && node.parent.callee !== node && node.parent.callee.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.parent.arguments.at(0) === node && isUseEffectCallLoose(node.parent);
|
|
290
300
|
}
|
|
291
301
|
function isFunctionOfUseEffectCleanup(node) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
302
|
+
if (node == null) return false;
|
|
303
|
+
const pReturn = __eslint_react_ast.findParentNode(node, __eslint_react_ast.is(__typescript_eslint_types.AST_NODE_TYPES.ReturnStatement));
|
|
304
|
+
const pFunction = __eslint_react_ast.findParentNode(node, __eslint_react_ast.isFunction);
|
|
305
|
+
const pFunctionOfReturn = __eslint_react_ast.findParentNode(pReturn, __eslint_react_ast.isFunction);
|
|
306
|
+
if (pFunction !== pFunctionOfReturn) return false;
|
|
307
|
+
return isFunctionOfUseEffectSetup(pFunction);
|
|
298
308
|
}
|
|
309
|
+
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/jsx/jsx-stringify.ts
|
|
312
|
+
/**
|
|
313
|
+
* Get the stringified representation of a JSX node
|
|
314
|
+
* @param node The JSX node
|
|
315
|
+
* @returns The stringified representation
|
|
316
|
+
*/
|
|
299
317
|
function stringifyJsx(node) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
return `<${stringifyJsx(node.name)}>`;
|
|
311
|
-
case types.AST_NODE_TYPES.JSXClosingElement:
|
|
312
|
-
return `</${stringifyJsx(node.name)}>`;
|
|
313
|
-
case types.AST_NODE_TYPES.JSXOpeningFragment:
|
|
314
|
-
return "<>";
|
|
315
|
-
case types.AST_NODE_TYPES.JSXClosingFragment:
|
|
316
|
-
return "</>";
|
|
317
|
-
}
|
|
318
|
+
switch (node.type) {
|
|
319
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXIdentifier: return node.name;
|
|
320
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXNamespacedName: return `${node.namespace.name}:${node.name.name}`;
|
|
321
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXMemberExpression: return `${stringifyJsx(node.object)}.${stringifyJsx(node.property)}`;
|
|
322
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXText: return node.value;
|
|
323
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXOpeningElement: return `<${stringifyJsx(node.name)}>`;
|
|
324
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXClosingElement: return `</${stringifyJsx(node.name)}>`;
|
|
325
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXOpeningFragment: return "<>";
|
|
326
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXClosingFragment: return "</>";
|
|
327
|
+
}
|
|
318
328
|
}
|
|
319
329
|
|
|
320
|
-
|
|
330
|
+
//#endregion
|
|
331
|
+
//#region src/jsx/jsx-attribute-name.ts
|
|
332
|
+
/**
|
|
333
|
+
* Get the stringified name of a JSX attribute
|
|
334
|
+
* @param context The ESLint rule context
|
|
335
|
+
* @param node The JSX attribute node
|
|
336
|
+
* @returns The name of the attribute
|
|
337
|
+
*/
|
|
321
338
|
function getAttributeName(context, node) {
|
|
322
|
-
|
|
339
|
+
return stringifyJsx(node.name);
|
|
323
340
|
}
|
|
324
341
|
|
|
325
|
-
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/jsx/jsx-attribute.ts
|
|
344
|
+
/**
|
|
345
|
+
* Get the JSX attribute node with the given name
|
|
346
|
+
* @param context The ESLint rule context
|
|
347
|
+
* @param name The name of the attribute
|
|
348
|
+
* @param attributes The attributes to search
|
|
349
|
+
* @param initialScope The initial scope to use for variable resolution
|
|
350
|
+
* @returns The JSX attribute node or undefined
|
|
351
|
+
*/
|
|
326
352
|
function getAttribute(context, name, attributes, initialScope) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
case types.AST_NODE_TYPES.ObjectExpression:
|
|
342
|
-
return VAR3__namespace.findPropertyInProperties(name, attr.argument.properties, initialScope) != null;
|
|
343
|
-
}
|
|
344
|
-
return false;
|
|
345
|
-
});
|
|
353
|
+
return attributes.findLast((attr) => {
|
|
354
|
+
if (attr.type === __typescript_eslint_types.AST_NODE_TYPES.JSXAttribute) return getAttributeName(context, attr) === name;
|
|
355
|
+
if (initialScope == null) return false;
|
|
356
|
+
switch (attr.argument.type) {
|
|
357
|
+
case __typescript_eslint_types.AST_NODE_TYPES.Identifier: {
|
|
358
|
+
const variable = __eslint_react_var.findVariable(attr.argument.name, initialScope);
|
|
359
|
+
const variableNode = __eslint_react_var.getVariableInitNode(variable, 0);
|
|
360
|
+
if (variableNode?.type === __typescript_eslint_types.AST_NODE_TYPES.ObjectExpression) return __eslint_react_var.findPropertyInProperties(name, variableNode.properties, initialScope) != null;
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
case __typescript_eslint_types.AST_NODE_TYPES.ObjectExpression: return __eslint_react_var.findPropertyInProperties(name, attr.argument.properties, initialScope) != null;
|
|
364
|
+
}
|
|
365
|
+
return false;
|
|
366
|
+
});
|
|
346
367
|
}
|
|
368
|
+
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/jsx/jsx-attribute-value.ts
|
|
371
|
+
/**
|
|
372
|
+
* Get a StaticValue of the attribute value
|
|
373
|
+
* @param context The rule context
|
|
374
|
+
* @param node The JSX attribute node
|
|
375
|
+
* @param name The name of the attribute
|
|
376
|
+
* @returns The StaticValue of the attribute value
|
|
377
|
+
*/
|
|
347
378
|
function getAttributeValue(context, node, name) {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
379
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
380
|
+
switch (node.type) {
|
|
381
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXAttribute:
|
|
382
|
+
if (node.value?.type === __typescript_eslint_types.AST_NODE_TYPES.Literal) return {
|
|
383
|
+
kind: "some",
|
|
384
|
+
node: node.value,
|
|
385
|
+
initialScope,
|
|
386
|
+
value: node.value.value
|
|
387
|
+
};
|
|
388
|
+
if (node.value?.type === __typescript_eslint_types.AST_NODE_TYPES.JSXExpressionContainer) return __eslint_react_var.toStaticValue({
|
|
389
|
+
kind: "lazy",
|
|
390
|
+
node: node.value.expression,
|
|
391
|
+
initialScope
|
|
392
|
+
});
|
|
393
|
+
return {
|
|
394
|
+
kind: "none",
|
|
395
|
+
node,
|
|
396
|
+
initialScope
|
|
397
|
+
};
|
|
398
|
+
case __typescript_eslint_types.AST_NODE_TYPES.JSXSpreadAttribute: {
|
|
399
|
+
const staticValue = __eslint_react_var.toStaticValue({
|
|
400
|
+
kind: "lazy",
|
|
401
|
+
node: node.argument,
|
|
402
|
+
initialScope
|
|
403
|
+
});
|
|
404
|
+
if (staticValue.kind === "none") return staticValue;
|
|
405
|
+
return (0, ts_pattern.match)(staticValue.value).with({ [name]: ts_pattern.P.select(ts_pattern.P.any) }, (value) => ({
|
|
406
|
+
kind: "some",
|
|
407
|
+
node: node.argument,
|
|
408
|
+
initialScope,
|
|
409
|
+
value
|
|
410
|
+
})).otherwise(() => ({
|
|
411
|
+
kind: "none",
|
|
412
|
+
node,
|
|
413
|
+
initialScope
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
416
|
+
default: return {
|
|
417
|
+
kind: "none",
|
|
418
|
+
node,
|
|
419
|
+
initialScope
|
|
420
|
+
};
|
|
421
|
+
}
|
|
386
422
|
}
|
|
387
423
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/jsx/jsx-detection-hint.ts
|
|
426
|
+
const JSXDetectionHint = {
|
|
427
|
+
None: 0n,
|
|
428
|
+
SkipUndefined: 1n << 0n,
|
|
429
|
+
SkipNullLiteral: 1n << 1n,
|
|
430
|
+
SkipBooleanLiteral: 1n << 2n,
|
|
431
|
+
SkipStringLiteral: 1n << 3n,
|
|
432
|
+
SkipNumberLiteral: 1n << 4n,
|
|
433
|
+
SkipBigIntLiteral: 1n << 5n,
|
|
434
|
+
SkipEmptyArray: 1n << 6n,
|
|
435
|
+
SkipCreateElement: 1n << 7n,
|
|
436
|
+
StrictArray: 1n << 8n,
|
|
437
|
+
StrictLogical: 1n << 9n,
|
|
438
|
+
StrictConditional: 1n << 10n
|
|
402
439
|
};
|
|
403
|
-
|
|
440
|
+
const DEFAULT_JSX_DETECTION_HINT = 0n | JSXDetectionHint.SkipUndefined | JSXDetectionHint.SkipBooleanLiteral;
|
|
404
441
|
|
|
405
|
-
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/jsx/jsx-detection.ts
|
|
444
|
+
/**
|
|
445
|
+
* Check if a node is a `JSXText` or a `Literal` node
|
|
446
|
+
* @param node The AST node to check
|
|
447
|
+
* @returns `true` if the node is a `JSXText` or a `Literal` node
|
|
448
|
+
*/
|
|
406
449
|
function isJsxText(node) {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
450
|
+
if (node == null) return false;
|
|
451
|
+
return node.type === __typescript_eslint_types.AST_NODE_TYPES.JSXText || node.type === __typescript_eslint_types.AST_NODE_TYPES.Literal;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Heuristic decision to determine if a node is a JSX-like node.
|
|
455
|
+
* @param code The sourceCode object
|
|
456
|
+
* @param code.getScope The function to get the scope of a node
|
|
457
|
+
* @param node The AST node to check
|
|
458
|
+
* @param hint The `JSXDetectionHint` to use
|
|
459
|
+
* @returns boolean
|
|
460
|
+
*/
|
|
410
461
|
function isJsxLike(code, node, hint = DEFAULT_JSX_DETECTION_HINT) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
case types.AST_NODE_TYPES.SequenceExpression: {
|
|
469
|
-
const exp = node.expressions.at(-1);
|
|
470
|
-
return isJsxLike(code, exp, hint);
|
|
471
|
-
}
|
|
472
|
-
case types.AST_NODE_TYPES.CallExpression: {
|
|
473
|
-
if (hint & JSXDetectionHint.SkipCreateElement) {
|
|
474
|
-
return false;
|
|
475
|
-
}
|
|
476
|
-
switch (node.callee.type) {
|
|
477
|
-
case types.AST_NODE_TYPES.Identifier:
|
|
478
|
-
return node.callee.name === "createElement";
|
|
479
|
-
case types.AST_NODE_TYPES.MemberExpression:
|
|
480
|
-
return node.callee.property.type === types.AST_NODE_TYPES.Identifier && node.callee.property.name === "createElement";
|
|
481
|
-
}
|
|
482
|
-
return false;
|
|
483
|
-
}
|
|
484
|
-
case types.AST_NODE_TYPES.Identifier: {
|
|
485
|
-
const { name } = node;
|
|
486
|
-
if (name === "undefined") {
|
|
487
|
-
return !(hint & JSXDetectionHint.SkipUndefined);
|
|
488
|
-
}
|
|
489
|
-
if (AST9__namespace.isJSXTagNameExpression(node)) {
|
|
490
|
-
return true;
|
|
491
|
-
}
|
|
492
|
-
const variable = VAR3__namespace.findVariable(name, code.getScope(node));
|
|
493
|
-
const variableNode = variable && VAR3__namespace.getVariableInitNode(variable, 0);
|
|
494
|
-
return !!variableNode && isJsxLike(code, variableNode, hint);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
return false;
|
|
462
|
+
if (node == null) return false;
|
|
463
|
+
if (__eslint_react_ast.isJSX(node)) return true;
|
|
464
|
+
switch (node.type) {
|
|
465
|
+
case __typescript_eslint_types.AST_NODE_TYPES.Literal:
|
|
466
|
+
switch (typeof node.value) {
|
|
467
|
+
case "boolean": return !(hint & JSXDetectionHint.SkipBooleanLiteral);
|
|
468
|
+
case "string": return !(hint & JSXDetectionHint.SkipStringLiteral);
|
|
469
|
+
case "number": return !(hint & JSXDetectionHint.SkipNumberLiteral);
|
|
470
|
+
case "bigint": return !(hint & JSXDetectionHint.SkipBigIntLiteral);
|
|
471
|
+
}
|
|
472
|
+
if (node.value == null) return !(hint & JSXDetectionHint.SkipNullLiteral);
|
|
473
|
+
return false;
|
|
474
|
+
case __typescript_eslint_types.AST_NODE_TYPES.TemplateLiteral: return !(hint & JSXDetectionHint.SkipStringLiteral);
|
|
475
|
+
case __typescript_eslint_types.AST_NODE_TYPES.ArrayExpression:
|
|
476
|
+
if (node.elements.length === 0) return !(hint & JSXDetectionHint.SkipEmptyArray);
|
|
477
|
+
if (hint & JSXDetectionHint.StrictArray) return node.elements.every((n) => isJsxLike(code, n, hint));
|
|
478
|
+
return node.elements.some((n) => isJsxLike(code, n, hint));
|
|
479
|
+
case __typescript_eslint_types.AST_NODE_TYPES.LogicalExpression:
|
|
480
|
+
if (hint & JSXDetectionHint.StrictLogical) return isJsxLike(code, node.left, hint) && isJsxLike(code, node.right, hint);
|
|
481
|
+
return isJsxLike(code, node.left, hint) || isJsxLike(code, node.right, hint);
|
|
482
|
+
case __typescript_eslint_types.AST_NODE_TYPES.ConditionalExpression: {
|
|
483
|
+
function leftHasJSX(node$1) {
|
|
484
|
+
if (Array.isArray(node$1.consequent)) {
|
|
485
|
+
if (node$1.consequent.length === 0) return !(hint & JSXDetectionHint.SkipEmptyArray);
|
|
486
|
+
if (hint & JSXDetectionHint.StrictArray) return node$1.consequent.every((n) => isJsxLike(code, n, hint));
|
|
487
|
+
return node$1.consequent.some((n) => isJsxLike(code, n, hint));
|
|
488
|
+
}
|
|
489
|
+
return isJsxLike(code, node$1.consequent, hint);
|
|
490
|
+
}
|
|
491
|
+
function rightHasJSX(node$1) {
|
|
492
|
+
return isJsxLike(code, node$1.alternate, hint);
|
|
493
|
+
}
|
|
494
|
+
if (hint & JSXDetectionHint.StrictConditional) return leftHasJSX(node) && rightHasJSX(node);
|
|
495
|
+
return leftHasJSX(node) || rightHasJSX(node);
|
|
496
|
+
}
|
|
497
|
+
case __typescript_eslint_types.AST_NODE_TYPES.SequenceExpression: {
|
|
498
|
+
const exp = node.expressions.at(-1);
|
|
499
|
+
return isJsxLike(code, exp, hint);
|
|
500
|
+
}
|
|
501
|
+
case __typescript_eslint_types.AST_NODE_TYPES.CallExpression:
|
|
502
|
+
if (hint & JSXDetectionHint.SkipCreateElement) return false;
|
|
503
|
+
switch (node.callee.type) {
|
|
504
|
+
case __typescript_eslint_types.AST_NODE_TYPES.Identifier: return node.callee.name === "createElement";
|
|
505
|
+
case __typescript_eslint_types.AST_NODE_TYPES.MemberExpression: return node.callee.property.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.callee.property.name === "createElement";
|
|
506
|
+
}
|
|
507
|
+
return false;
|
|
508
|
+
case __typescript_eslint_types.AST_NODE_TYPES.Identifier: {
|
|
509
|
+
const { name } = node;
|
|
510
|
+
if (name === "undefined") return !(hint & JSXDetectionHint.SkipUndefined);
|
|
511
|
+
if (__eslint_react_ast.isJSXTagNameExpression(node)) return true;
|
|
512
|
+
const variable = __eslint_react_var.findVariable(name, code.getScope(node));
|
|
513
|
+
const variableNode = variable && __eslint_react_var.getVariableInitNode(variable, 0);
|
|
514
|
+
return !!variableNode && isJsxLike(code, variableNode, hint);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return false;
|
|
498
518
|
}
|
|
519
|
+
|
|
520
|
+
//#endregion
|
|
521
|
+
//#region src/jsx/jsx-element-type.ts
|
|
522
|
+
/**
|
|
523
|
+
* Get the stringified type of a JSX element
|
|
524
|
+
* @param context The ESLint rule context
|
|
525
|
+
* @param node The JSX element node
|
|
526
|
+
* @returns The type of the element
|
|
527
|
+
*/
|
|
499
528
|
function getElementType(context, node) {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
503
|
-
return stringifyJsx(node.openingElement.name);
|
|
529
|
+
if (node.type === __typescript_eslint_types.AST_NODE_TYPES.JSXFragment) return "";
|
|
530
|
+
return stringifyJsx(node.openingElement.name);
|
|
504
531
|
}
|
|
505
532
|
|
|
506
|
-
|
|
533
|
+
//#endregion
|
|
534
|
+
//#region src/jsx/jsx-has.ts
|
|
507
535
|
function hasAttribute(context, name, attributes, initialScope) {
|
|
508
|
-
|
|
536
|
+
return getAttribute(context, name, attributes, initialScope) != null;
|
|
509
537
|
}
|
|
510
538
|
function hasAnyAttribute(context, names, attributes, initialScope) {
|
|
511
|
-
|
|
539
|
+
return names.some((n) => hasAttribute(context, n, attributes, initialScope));
|
|
512
540
|
}
|
|
513
541
|
function hasEveryAttribute(context, names, attributes, initialScope) {
|
|
514
|
-
|
|
542
|
+
return names.every((n) => hasAttribute(context, n, attributes, initialScope));
|
|
515
543
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
544
|
+
|
|
545
|
+
//#endregion
|
|
546
|
+
//#region src/jsx/jsx-hierarchy.ts
|
|
547
|
+
/**
|
|
548
|
+
* Find the parent JSX attribute node of a node
|
|
549
|
+
* @param node The node to find the parent attribute of
|
|
550
|
+
* @param test The test to apply to the parent attribute
|
|
551
|
+
* @returns The parent attribute node or undefined
|
|
552
|
+
*/
|
|
553
|
+
function findParentAttribute(node, test = __eslint_react_eff.constTrue) {
|
|
554
|
+
const guard = (node$1) => {
|
|
555
|
+
return node$1.type === __typescript_eslint_types.AST_NODE_TYPES.JSXAttribute && test(node$1);
|
|
556
|
+
};
|
|
557
|
+
return __eslint_react_ast.findParentNode(node, guard);
|
|
521
558
|
}
|
|
559
|
+
|
|
560
|
+
//#endregion
|
|
561
|
+
//#region src/jsx/jsx-is.ts
|
|
522
562
|
function isHostElement(context, node) {
|
|
523
|
-
|
|
563
|
+
return node.type === __typescript_eslint_types.AST_NODE_TYPES.JSXElement && node.openingElement.name.type === __typescript_eslint_types.AST_NODE_TYPES.JSXIdentifier && /^[a-z]/u.test(node.openingElement.name.name);
|
|
524
564
|
}
|
|
525
565
|
function isKeyedElement(context, node, initialScope) {
|
|
526
|
-
|
|
566
|
+
return node.type === __typescript_eslint_types.AST_NODE_TYPES.JSXElement && hasAttribute(context, "key", node.openingElement.attributes, initialScope);
|
|
527
567
|
}
|
|
528
568
|
function isFragmentElement(context, node, allowJSXFragment = false) {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
569
|
+
if (node == null) return false;
|
|
570
|
+
if (node.type !== __typescript_eslint_types.AST_NODE_TYPES.JSXElement && node.type !== __typescript_eslint_types.AST_NODE_TYPES.JSXFragment) return false;
|
|
571
|
+
if (node.type === __typescript_eslint_types.AST_NODE_TYPES.JSXFragment) return allowJSXFragment;
|
|
572
|
+
return getElementType(context, node).split(".").at(-1) === "Fragment";
|
|
533
573
|
}
|
|
534
574
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
SkipForwardRef: 1n << 65n,
|
|
549
|
-
/**
|
|
550
|
-
* Skip function component defined as array map argument
|
|
551
|
-
*/
|
|
552
|
-
SkipArrayMapArgument: 1n << 66n,
|
|
553
|
-
/**
|
|
554
|
-
* Skip function component defined on object method
|
|
555
|
-
*/
|
|
556
|
-
SkipObjectMethod: 1n << 67n,
|
|
557
|
-
/**
|
|
558
|
-
* Skip function component defined on class method
|
|
559
|
-
*/
|
|
560
|
-
SkipClassMethod: 1n << 68n,
|
|
561
|
-
/**
|
|
562
|
-
* Skip function component defined on class property
|
|
563
|
-
*/
|
|
564
|
-
SkipClassProperty: 1n << 69n
|
|
575
|
+
//#endregion
|
|
576
|
+
//#region src/component/component-detection-hint.ts
|
|
577
|
+
/**
|
|
578
|
+
* Hints for component collector
|
|
579
|
+
*/
|
|
580
|
+
const ComponentDetectionHint = {
|
|
581
|
+
...JSXDetectionHint,
|
|
582
|
+
SkipMemo: 1n << 64n,
|
|
583
|
+
SkipForwardRef: 1n << 65n,
|
|
584
|
+
SkipArrayMapArgument: 1n << 66n,
|
|
585
|
+
SkipObjectMethod: 1n << 67n,
|
|
586
|
+
SkipClassMethod: 1n << 68n,
|
|
587
|
+
SkipClassProperty: 1n << 69n
|
|
565
588
|
};
|
|
566
|
-
|
|
589
|
+
/**
|
|
590
|
+
* Default component detection hint
|
|
591
|
+
*/
|
|
592
|
+
const DEFAULT_COMPONENT_DETECTION_HINT = 0n | ComponentDetectionHint.SkipBooleanLiteral | ComponentDetectionHint.SkipEmptyArray | ComponentDetectionHint.SkipArrayMapArgument | ComponentDetectionHint.SkipNumberLiteral | ComponentDetectionHint.SkipStringLiteral | ComponentDetectionHint.SkipUndefined | ComponentDetectionHint.StrictArray | ComponentDetectionHint.StrictConditional | ComponentDetectionHint.StrictLogical;
|
|
593
|
+
|
|
594
|
+
//#endregion
|
|
595
|
+
//#region src/component/component-is.ts
|
|
596
|
+
/**
|
|
597
|
+
* Check if a node is a React class component
|
|
598
|
+
* @param node The AST node to check
|
|
599
|
+
* @returns `true` if the node is a class component, `false` otherwise
|
|
600
|
+
*/
|
|
567
601
|
function isClassComponent(node) {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
602
|
+
if ("superClass" in node && node.superClass != null) {
|
|
603
|
+
const re = /^(?:Pure)?Component$/u;
|
|
604
|
+
switch (true) {
|
|
605
|
+
case node.superClass.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier: return re.test(node.superClass.name);
|
|
606
|
+
case node.superClass.type === __typescript_eslint_types.AST_NODE_TYPES.MemberExpression && node.superClass.property.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier: return re.test(node.superClass.property.name);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Check if a node is a React PureComponent
|
|
613
|
+
* @param node The AST node to check
|
|
614
|
+
* @returns `true` if the node is a pure component, `false` otherwise
|
|
615
|
+
*/
|
|
579
616
|
function isPureComponent(node) {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
}
|
|
589
|
-
return false;
|
|
617
|
+
if ("superClass" in node && node.superClass != null) {
|
|
618
|
+
const re = /^PureComponent$/u;
|
|
619
|
+
switch (true) {
|
|
620
|
+
case node.superClass.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier: return re.test(node.superClass.name);
|
|
621
|
+
case node.superClass.type === __typescript_eslint_types.AST_NODE_TYPES.MemberExpression && node.superClass.property.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier: return re.test(node.superClass.property.name);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return false;
|
|
590
625
|
}
|
|
626
|
+
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region src/component/component-lifecycle.ts
|
|
591
629
|
function isComponentDidCatch(node) {
|
|
592
|
-
|
|
630
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "componentDidCatch";
|
|
593
631
|
}
|
|
594
632
|
function isComponentDidMount(node) {
|
|
595
|
-
|
|
633
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "componentDidMount";
|
|
596
634
|
}
|
|
597
635
|
function isComponentDidUpdate(node) {
|
|
598
|
-
|
|
636
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "componentDidUpdate";
|
|
599
637
|
}
|
|
600
638
|
function isComponentWillMount(node) {
|
|
601
|
-
|
|
639
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "componentWillMount";
|
|
602
640
|
}
|
|
603
641
|
function isComponentWillReceiveProps(node) {
|
|
604
|
-
|
|
642
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "componentWillReceiveProps";
|
|
605
643
|
}
|
|
606
644
|
function isComponentWillUnmount(node) {
|
|
607
|
-
|
|
645
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "componentWillUnmount";
|
|
608
646
|
}
|
|
609
647
|
function isComponentWillUpdate(node) {
|
|
610
|
-
|
|
648
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "componentWillUpdate";
|
|
611
649
|
}
|
|
612
650
|
function isGetChildContext(node) {
|
|
613
|
-
|
|
651
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "getChildContext";
|
|
614
652
|
}
|
|
615
653
|
function isGetDefaultProps(node) {
|
|
616
|
-
|
|
654
|
+
return __eslint_react_ast.isMethodOrProperty(node) && node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "getDefaultProps";
|
|
617
655
|
}
|
|
618
656
|
function isGetInitialState(node) {
|
|
619
|
-
|
|
657
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "getInitialState";
|
|
620
658
|
}
|
|
621
659
|
function isGetSnapshotBeforeUpdate(node) {
|
|
622
|
-
|
|
660
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "getSnapshotBeforeUpdate";
|
|
623
661
|
}
|
|
624
662
|
function isShouldComponentUpdate(node) {
|
|
625
|
-
|
|
663
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "shouldComponentUpdate";
|
|
626
664
|
}
|
|
627
665
|
function isUnsafeComponentWillMount(node) {
|
|
628
|
-
|
|
666
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "UNSAFE_componentWillMount";
|
|
629
667
|
}
|
|
630
668
|
function isUnsafeComponentWillReceiveProps(node) {
|
|
631
|
-
|
|
669
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "UNSAFE_componentWillReceiveProps";
|
|
632
670
|
}
|
|
633
671
|
function isUnsafeComponentWillUpdate(node) {
|
|
634
|
-
|
|
672
|
+
return __eslint_react_ast.isMethodOrProperty(node) && !node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "UNSAFE_componentWillUpdate";
|
|
635
673
|
}
|
|
636
674
|
function isGetDerivedStateFromProps(node) {
|
|
637
|
-
|
|
675
|
+
return __eslint_react_ast.isMethodOrProperty(node) && node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "getDerivedStateFromProps";
|
|
638
676
|
}
|
|
639
677
|
function isGetDerivedStateFromError(node) {
|
|
640
|
-
|
|
678
|
+
return __eslint_react_ast.isMethodOrProperty(node) && node.static && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "getDerivedStateFromError";
|
|
641
679
|
}
|
|
680
|
+
|
|
681
|
+
//#endregion
|
|
682
|
+
//#region src/component/component-render.ts
|
|
683
|
+
/**
|
|
684
|
+
* Check whether given node is a render function of a class component
|
|
685
|
+
* @example
|
|
686
|
+
* ```tsx
|
|
687
|
+
* class Component extends React.Component {
|
|
688
|
+
* render() {
|
|
689
|
+
* return <div />;
|
|
690
|
+
* }
|
|
691
|
+
* }
|
|
692
|
+
* ```
|
|
693
|
+
* @param node The AST node to check
|
|
694
|
+
* @returns `true` if node is a render function, `false` if not
|
|
695
|
+
*/
|
|
642
696
|
function isRenderLike(node) {
|
|
643
|
-
|
|
644
|
-
}
|
|
697
|
+
return __eslint_react_ast.isMethodOrProperty(node) && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name === "render" && node.parent.parent.type === __typescript_eslint_types.AST_NODE_TYPES.ClassDeclaration;
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Check whether given node is a function of a render function of a class component
|
|
701
|
+
* @example
|
|
702
|
+
* ```tsx
|
|
703
|
+
* class Component extends React.Component {
|
|
704
|
+
* render = () => <div />;
|
|
705
|
+
* ```
|
|
706
|
+
* @param node The AST node to check
|
|
707
|
+
* @returns `true` if node is a render function, `false` if not
|
|
708
|
+
*/
|
|
645
709
|
function isFunctionOfRender(node) {
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
}
|
|
649
|
-
return isClassComponent(node.parent.parent.parent);
|
|
710
|
+
if (!isRenderLike(node.parent)) return false;
|
|
711
|
+
return isClassComponent(node.parent.parent.parent);
|
|
650
712
|
}
|
|
713
|
+
|
|
714
|
+
//#endregion
|
|
715
|
+
//#region src/component/component-render-method.ts
|
|
716
|
+
/**
|
|
717
|
+
* Check whether given node is a render method of a class component
|
|
718
|
+
* @example
|
|
719
|
+
* ```tsx
|
|
720
|
+
* class Component extends React.Component {
|
|
721
|
+
* renderHeader = () => <div />;
|
|
722
|
+
* renderFooter = () => <div />;
|
|
723
|
+
* }
|
|
724
|
+
* ```
|
|
725
|
+
* @param node The AST node to check
|
|
726
|
+
* @returns `true` if node is a render function, `false` if not
|
|
727
|
+
*/
|
|
651
728
|
function isRenderMethodLike(node) {
|
|
652
|
-
|
|
729
|
+
return __eslint_react_ast.isMethodOrProperty(node) && node.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node.key.name.startsWith("render") && node.parent.parent.type === __typescript_eslint_types.AST_NODE_TYPES.ClassDeclaration;
|
|
653
730
|
}
|
|
654
731
|
|
|
655
|
-
|
|
732
|
+
//#endregion
|
|
733
|
+
//#region src/component/component-hierarchy.ts
|
|
734
|
+
/**
|
|
735
|
+
* Determines whether inside `createElement`'s children.
|
|
736
|
+
* @param context The rule context
|
|
737
|
+
* @param node The AST node to check
|
|
738
|
+
* @returns `true` if the node is inside createElement's children
|
|
739
|
+
*/
|
|
656
740
|
function isChildrenOfCreateElement(context, node) {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
741
|
+
const parent = node.parent;
|
|
742
|
+
if (parent == null || parent.type !== __typescript_eslint_types.AST_NODE_TYPES.CallExpression) return false;
|
|
743
|
+
if (!isCreateElementCall(context, parent)) return false;
|
|
744
|
+
return parent.arguments.slice(2).some((arg) => arg === node);
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Check whether given node is declared inside class component's render block
|
|
748
|
+
* ```tsx
|
|
749
|
+
* class Component extends React.Component {
|
|
750
|
+
* render() {
|
|
751
|
+
* class NestedClassComponent extends React.Component {
|
|
752
|
+
* render() { return <div />; }
|
|
753
|
+
* }
|
|
754
|
+
* const nestedFunctionComponent = () => <div />;
|
|
755
|
+
* }
|
|
756
|
+
* }
|
|
757
|
+
* ```
|
|
758
|
+
* @param node The AST node being checked
|
|
759
|
+
* @returns `true` if node is inside class component's render block, `false` if not
|
|
760
|
+
*/
|
|
662
761
|
function isInsideRenderMethod(node) {
|
|
663
|
-
|
|
762
|
+
return __eslint_react_ast.findParentNode(node, (n) => isRenderLike(n) && isClassComponent(n.parent.parent)) != null;
|
|
664
763
|
}
|
|
665
764
|
function isFunctionOfComponentDidMount(node) {
|
|
666
|
-
|
|
765
|
+
return __eslint_react_ast.isFunction(node) && isComponentDidMount(node.parent) && node.parent.value === node;
|
|
667
766
|
}
|
|
668
767
|
function isFunctionOfComponentWillUnmount(node) {
|
|
669
|
-
|
|
670
|
-
}
|
|
768
|
+
return __eslint_react_ast.isFunction(node) && isComponentWillUnmount(node.parent) && node.parent.value === node;
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Check whether given node is a function of a render method of a class component
|
|
772
|
+
* @example
|
|
773
|
+
* ```tsx
|
|
774
|
+
* class Component extends React.Component {
|
|
775
|
+
* renderHeader = () => <div />;
|
|
776
|
+
* renderFooter = () => <div />;
|
|
777
|
+
* }
|
|
778
|
+
* ```
|
|
779
|
+
* @param node The AST node to check
|
|
780
|
+
* @returns `true` if node is a render function, `false` if not
|
|
781
|
+
*/
|
|
671
782
|
function isFunctionOfRenderMethod(node) {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
}
|
|
675
|
-
return isClassComponent(node.parent.parent.parent);
|
|
783
|
+
if (!isRenderMethodLike(node.parent)) return false;
|
|
784
|
+
return isClassComponent(node.parent.parent.parent);
|
|
676
785
|
}
|
|
677
786
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
787
|
+
//#endregion
|
|
788
|
+
//#region src/component/component-definition.ts
|
|
789
|
+
const isFunctionOfClassMethod = (0, ts_pattern.isMatching)({
|
|
790
|
+
type: ts_pattern.P.union(__typescript_eslint_types.AST_NODE_TYPES.ArrowFunctionExpression, __typescript_eslint_types.AST_NODE_TYPES.FunctionExpression),
|
|
791
|
+
parent: __typescript_eslint_types.AST_NODE_TYPES.MethodDefinition
|
|
682
792
|
});
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
793
|
+
const isFunctionOfClassProperty = (0, ts_pattern.isMatching)({
|
|
794
|
+
type: ts_pattern.P.union(__typescript_eslint_types.AST_NODE_TYPES.ArrowFunctionExpression, __typescript_eslint_types.AST_NODE_TYPES.FunctionExpression),
|
|
795
|
+
parent: __typescript_eslint_types.AST_NODE_TYPES.Property
|
|
686
796
|
});
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
}
|
|
694
|
-
}
|
|
797
|
+
const isFunctionOfObjectMethod = (0, ts_pattern.isMatching)({
|
|
798
|
+
type: ts_pattern.P.union(__typescript_eslint_types.AST_NODE_TYPES.ArrowFunctionExpression, __typescript_eslint_types.AST_NODE_TYPES.FunctionExpression),
|
|
799
|
+
parent: {
|
|
800
|
+
type: __typescript_eslint_types.AST_NODE_TYPES.Property,
|
|
801
|
+
parent: { type: __typescript_eslint_types.AST_NODE_TYPES.ObjectExpression }
|
|
802
|
+
}
|
|
695
803
|
});
|
|
696
804
|
function isValidComponentDefinition(context, node, hint) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
return false;
|
|
711
|
-
}
|
|
712
|
-
const significantParent = AST9__namespace.findParentNode(
|
|
713
|
-
node,
|
|
714
|
-
AST9__namespace.isOneOf([
|
|
715
|
-
types.AST_NODE_TYPES.JSXExpressionContainer,
|
|
716
|
-
types.AST_NODE_TYPES.ArrowFunctionExpression,
|
|
717
|
-
types.AST_NODE_TYPES.FunctionExpression,
|
|
718
|
-
types.AST_NODE_TYPES.Property,
|
|
719
|
-
types.AST_NODE_TYPES.ClassBody
|
|
720
|
-
])
|
|
721
|
-
);
|
|
722
|
-
return significantParent == null || significantParent.type !== types.AST_NODE_TYPES.JSXExpressionContainer;
|
|
805
|
+
if (isChildrenOfCreateElement(context, node) || isFunctionOfRenderMethod(node)) return false;
|
|
806
|
+
if (hint & ComponentDetectionHint.SkipObjectMethod && isFunctionOfObjectMethod(node.parent)) return false;
|
|
807
|
+
if (hint & ComponentDetectionHint.SkipClassMethod && isFunctionOfClassMethod(node.parent)) return false;
|
|
808
|
+
if (hint & ComponentDetectionHint.SkipClassProperty && isFunctionOfClassProperty(node.parent)) return false;
|
|
809
|
+
if (hint & ComponentDetectionHint.SkipArrayMapArgument && __eslint_react_ast.isArrayMapCall(node.parent)) return false;
|
|
810
|
+
const significantParent = __eslint_react_ast.findParentNode(node, __eslint_react_ast.isOneOf([
|
|
811
|
+
__typescript_eslint_types.AST_NODE_TYPES.JSXExpressionContainer,
|
|
812
|
+
__typescript_eslint_types.AST_NODE_TYPES.ArrowFunctionExpression,
|
|
813
|
+
__typescript_eslint_types.AST_NODE_TYPES.FunctionExpression,
|
|
814
|
+
__typescript_eslint_types.AST_NODE_TYPES.Property,
|
|
815
|
+
__typescript_eslint_types.AST_NODE_TYPES.ClassBody
|
|
816
|
+
]));
|
|
817
|
+
return significantParent == null || significantParent.type !== __typescript_eslint_types.AST_NODE_TYPES.JSXExpressionContainer;
|
|
723
818
|
}
|
|
819
|
+
|
|
820
|
+
//#endregion
|
|
821
|
+
//#region src/component/component-wrapper.ts
|
|
822
|
+
/**
|
|
823
|
+
* Check if the node is a call expression for a component wrapper
|
|
824
|
+
* @param context The ESLint rule context
|
|
825
|
+
* @param node The node to check
|
|
826
|
+
* @returns `true` if the node is a call expression for a component wrapper
|
|
827
|
+
*/
|
|
724
828
|
function isComponentWrapperCall(context, node) {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
}
|
|
829
|
+
if (node.type !== __typescript_eslint_types.AST_NODE_TYPES.CallExpression) return false;
|
|
830
|
+
return isMemoCall(context, node) || isForwardRefCall(context, node);
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Check if the node is a call expression for a component wrapper loosely
|
|
834
|
+
* @param context The ESLint rule context
|
|
835
|
+
* @param node The node to check
|
|
836
|
+
* @returns `true` if the node is a call expression for a component wrapper loosely
|
|
837
|
+
*/
|
|
728
838
|
function isComponentWrapperCallLoose(context, node) {
|
|
729
|
-
|
|
730
|
-
|
|
839
|
+
if (node.type !== __typescript_eslint_types.AST_NODE_TYPES.CallExpression) return false;
|
|
840
|
+
return isComponentWrapperCall(context, node) || isUseCallbackCall(context, node);
|
|
731
841
|
}
|
|
732
842
|
|
|
733
|
-
|
|
843
|
+
//#endregion
|
|
844
|
+
//#region src/component/component-id.ts
|
|
734
845
|
function getFunctionComponentId(context, node) {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
return parent.parent.id;
|
|
742
|
-
}
|
|
743
|
-
if (parent.type === types.AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === types.AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent.parent) && parent.parent.parent.type === types.AST_NODE_TYPES.VariableDeclarator && parent.parent.parent.id.type === types.AST_NODE_TYPES.Identifier) {
|
|
744
|
-
return parent.parent.parent.id;
|
|
745
|
-
}
|
|
746
|
-
return eff.unit;
|
|
846
|
+
const functionId = __eslint_react_ast.getFunctionId(node);
|
|
847
|
+
if (functionId != null) return functionId;
|
|
848
|
+
const { parent } = node;
|
|
849
|
+
if (parent.type === __typescript_eslint_types.AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === __typescript_eslint_types.AST_NODE_TYPES.VariableDeclarator && parent.parent.id.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier) return parent.parent.id;
|
|
850
|
+
if (parent.type === __typescript_eslint_types.AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === __typescript_eslint_types.AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent.parent) && parent.parent.parent.type === __typescript_eslint_types.AST_NODE_TYPES.VariableDeclarator && parent.parent.parent.id.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier) return parent.parent.parent.id;
|
|
851
|
+
return __eslint_react_eff.unit;
|
|
747
852
|
}
|
|
748
853
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
854
|
+
//#endregion
|
|
855
|
+
//#region src/component/component-flag.ts
|
|
856
|
+
const ComponentFlag = {
|
|
857
|
+
None: 0n,
|
|
858
|
+
PureComponent: 1n << 0n,
|
|
859
|
+
CreateElement: 1n << 1n,
|
|
860
|
+
Memo: 1n << 2n,
|
|
861
|
+
ForwardRef: 1n << 3n,
|
|
862
|
+
Async: 1n << 4n
|
|
757
863
|
};
|
|
758
864
|
|
|
759
|
-
|
|
865
|
+
//#endregion
|
|
866
|
+
//#region src/component/component-init-path.ts
|
|
760
867
|
function getComponentFlagFromInitPath(initPath) {
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if (initPath != null && AST9__namespace.hasCallInFunctionInitPath("forwardRef", initPath)) {
|
|
766
|
-
flag |= ComponentFlag.ForwardRef;
|
|
767
|
-
}
|
|
768
|
-
return flag;
|
|
868
|
+
let flag = ComponentFlag.None;
|
|
869
|
+
if (initPath != null && __eslint_react_ast.hasCallInFunctionInitPath("memo", initPath)) flag |= ComponentFlag.Memo;
|
|
870
|
+
if (initPath != null && __eslint_react_ast.hasCallInFunctionInitPath("forwardRef", initPath)) flag |= ComponentFlag.ForwardRef;
|
|
871
|
+
return flag;
|
|
769
872
|
}
|
|
873
|
+
|
|
874
|
+
//#endregion
|
|
875
|
+
//#region src/component/component-name.ts
|
|
770
876
|
function isComponentName(name) {
|
|
771
|
-
|
|
877
|
+
return __eslint_react_kit.RegExp.COMPONENT_NAME.test(name);
|
|
772
878
|
}
|
|
773
879
|
function isComponentNameLoose(name) {
|
|
774
|
-
|
|
880
|
+
return __eslint_react_kit.RegExp.COMPONENT_NAME_LOOSE.test(name);
|
|
775
881
|
}
|
|
776
882
|
function getComponentNameFromId(id) {
|
|
777
|
-
|
|
778
|
-
|
|
883
|
+
if (id == null) return __eslint_react_eff.unit;
|
|
884
|
+
return Array.isArray(id) ? id.map((n) => n.name).join(".") : id.name;
|
|
779
885
|
}
|
|
780
886
|
function hasNoneOrLooseComponentName(context, fn) {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
887
|
+
const id = getFunctionComponentId(context, fn);
|
|
888
|
+
if (id == null) return true;
|
|
889
|
+
const name = Array.isArray(id) ? id.at(-1)?.name : id.name;
|
|
890
|
+
return name != null && isComponentNameLoose(name);
|
|
785
891
|
}
|
|
786
892
|
|
|
787
|
-
|
|
893
|
+
//#endregion
|
|
894
|
+
//#region src/component/component-collector.ts
|
|
895
|
+
/**
|
|
896
|
+
* Get a ctx and listeners for the rule to collect function components
|
|
897
|
+
* @param context The ESLint rule context
|
|
898
|
+
* @param options The options to use
|
|
899
|
+
* @returns The component collector
|
|
900
|
+
*/
|
|
788
901
|
function useComponentCollector(context, options = {}) {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
return { ctx, listeners };
|
|
902
|
+
const { collectDisplayName = false, collectHookCalls = false, hint = DEFAULT_COMPONENT_DETECTION_HINT } = options;
|
|
903
|
+
const components = /* @__PURE__ */ new Map();
|
|
904
|
+
const functionEntries = [];
|
|
905
|
+
const getCurrentEntry = () => functionEntries.at(-1);
|
|
906
|
+
const onFunctionEnter = (node) => {
|
|
907
|
+
const key = (0, __eslint_react_shared.getId)();
|
|
908
|
+
functionEntries.push({
|
|
909
|
+
key,
|
|
910
|
+
node,
|
|
911
|
+
hookCalls: [],
|
|
912
|
+
isComponent: false
|
|
913
|
+
});
|
|
914
|
+
};
|
|
915
|
+
const onFunctionExit = () => {
|
|
916
|
+
const entry = functionEntries.at(-1);
|
|
917
|
+
if (entry == null) return;
|
|
918
|
+
if (!entry.isComponent) return functionEntries.pop();
|
|
919
|
+
const rets = __eslint_react_ast.getNestedReturnStatements(entry.node.body);
|
|
920
|
+
for (let i = rets.length - 1; i >= 0; i--) {
|
|
921
|
+
const ret = rets[i];
|
|
922
|
+
if (ret == null) continue;
|
|
923
|
+
const shouldDrop = context.sourceCode.getScope(ret).block === entry.node && ret.argument != null && !isJsxLike(context.sourceCode, ret.argument, hint);
|
|
924
|
+
if (shouldDrop) {
|
|
925
|
+
components.delete(entry.key);
|
|
926
|
+
break;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
return functionEntries.pop();
|
|
930
|
+
};
|
|
931
|
+
const ctx = {
|
|
932
|
+
getAllComponents(node) {
|
|
933
|
+
return components;
|
|
934
|
+
},
|
|
935
|
+
getCurrentEntries() {
|
|
936
|
+
return [...functionEntries];
|
|
937
|
+
},
|
|
938
|
+
getCurrentEntry
|
|
939
|
+
};
|
|
940
|
+
const listeners = {
|
|
941
|
+
":function[type]": onFunctionEnter,
|
|
942
|
+
":function[type]:exit": onFunctionExit,
|
|
943
|
+
"ArrowFunctionExpression[body.type!='BlockStatement']"() {
|
|
944
|
+
const entry = getCurrentEntry();
|
|
945
|
+
if (entry == null) return;
|
|
946
|
+
const { body } = entry.node;
|
|
947
|
+
const isComponent = hasNoneOrLooseComponentName(context, entry.node) && isJsxLike(context.sourceCode, body, hint) && isValidComponentDefinition(context, entry.node, hint);
|
|
948
|
+
if (!isComponent) return;
|
|
949
|
+
const initPath = __eslint_react_ast.getFunctionInitPath(entry.node);
|
|
950
|
+
const id = getFunctionComponentId(context, entry.node);
|
|
951
|
+
const name = getComponentNameFromId(id);
|
|
952
|
+
const key = (0, __eslint_react_shared.getId)();
|
|
953
|
+
components.set(key, {
|
|
954
|
+
id,
|
|
955
|
+
key,
|
|
956
|
+
kind: "function",
|
|
957
|
+
name,
|
|
958
|
+
node: entry.node,
|
|
959
|
+
displayName: __eslint_react_eff.unit,
|
|
960
|
+
flag: getComponentFlagFromInitPath(initPath),
|
|
961
|
+
hint,
|
|
962
|
+
hookCalls: entry.hookCalls,
|
|
963
|
+
initPath
|
|
964
|
+
});
|
|
965
|
+
},
|
|
966
|
+
...collectDisplayName ? { [__eslint_react_kit.Selector.DISPLAY_NAME_ASSIGNMENT_EXPRESSION](node) {
|
|
967
|
+
const { left, right } = node;
|
|
968
|
+
if (left.type !== __typescript_eslint_types.AST_NODE_TYPES.MemberExpression) return;
|
|
969
|
+
const componentName = left.object.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier ? left.object.name : __eslint_react_eff.unit;
|
|
970
|
+
const component = [...components.values()].findLast(({ name }) => name != null && name === componentName);
|
|
971
|
+
if (component == null) return;
|
|
972
|
+
component.displayName = right;
|
|
973
|
+
} } : {},
|
|
974
|
+
...collectHookCalls ? { "CallExpression[type]:exit"(node) {
|
|
975
|
+
if (!isReactHookCall(node)) return;
|
|
976
|
+
const entry = getCurrentEntry();
|
|
977
|
+
if (entry == null) return;
|
|
978
|
+
entry.hookCalls.push(node);
|
|
979
|
+
} } : {},
|
|
980
|
+
"ReturnStatement[type]"(node) {
|
|
981
|
+
const entry = getCurrentEntry();
|
|
982
|
+
if (entry == null) return;
|
|
983
|
+
const isComponent = hasNoneOrLooseComponentName(context, entry.node) && isJsxLike(context.sourceCode, node.argument, hint) && isValidComponentDefinition(context, entry.node, hint);
|
|
984
|
+
if (!isComponent) return;
|
|
985
|
+
entry.isComponent = true;
|
|
986
|
+
const initPath = __eslint_react_ast.getFunctionInitPath(entry.node);
|
|
987
|
+
const id = getFunctionComponentId(context, entry.node);
|
|
988
|
+
const name = getComponentNameFromId(id);
|
|
989
|
+
components.set(entry.key, {
|
|
990
|
+
id,
|
|
991
|
+
key: entry.key,
|
|
992
|
+
kind: "function",
|
|
993
|
+
name,
|
|
994
|
+
node: entry.node,
|
|
995
|
+
displayName: __eslint_react_eff.unit,
|
|
996
|
+
flag: getComponentFlagFromInitPath(initPath),
|
|
997
|
+
hint,
|
|
998
|
+
hookCalls: entry.hookCalls,
|
|
999
|
+
initPath
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
};
|
|
1003
|
+
return {
|
|
1004
|
+
ctx,
|
|
1005
|
+
listeners
|
|
1006
|
+
};
|
|
895
1007
|
}
|
|
1008
|
+
|
|
1009
|
+
//#endregion
|
|
1010
|
+
//#region src/component/component-collector-legacy.ts
|
|
1011
|
+
/**
|
|
1012
|
+
* Get a ctx and listeners object for the rule to collect class components
|
|
1013
|
+
* @returns The context and listeners for the rule
|
|
1014
|
+
*/
|
|
896
1015
|
function useComponentCollectorLegacy() {
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
}
|
|
934
|
-
var ComponentPhaseRelevance = birecord__default.default({
|
|
935
|
-
mount: "unmount",
|
|
936
|
-
setup: "cleanup"
|
|
1016
|
+
const components = /* @__PURE__ */ new Map();
|
|
1017
|
+
const ctx = { getAllComponents(node) {
|
|
1018
|
+
return components;
|
|
1019
|
+
} };
|
|
1020
|
+
const collect = (node) => {
|
|
1021
|
+
if (!isClassComponent(node)) return;
|
|
1022
|
+
const id = __eslint_react_ast.getClassId(node);
|
|
1023
|
+
const key = (0, __eslint_react_shared.getId)();
|
|
1024
|
+
const flag = isPureComponent(node) ? ComponentFlag.PureComponent : ComponentFlag.None;
|
|
1025
|
+
components.set(key, {
|
|
1026
|
+
id,
|
|
1027
|
+
key,
|
|
1028
|
+
kind: "class",
|
|
1029
|
+
name: id?.name,
|
|
1030
|
+
node,
|
|
1031
|
+
displayName: __eslint_react_eff.unit,
|
|
1032
|
+
flag,
|
|
1033
|
+
hint: 0n,
|
|
1034
|
+
methods: []
|
|
1035
|
+
});
|
|
1036
|
+
};
|
|
1037
|
+
const listeners = {
|
|
1038
|
+
"ClassDeclaration[type]": collect,
|
|
1039
|
+
"ClassExpression[type]": collect
|
|
1040
|
+
};
|
|
1041
|
+
return {
|
|
1042
|
+
ctx,
|
|
1043
|
+
listeners
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
//#endregion
|
|
1048
|
+
//#region src/component/component-phase.ts
|
|
1049
|
+
const ComponentPhaseRelevance = (0, birecord.default)({
|
|
1050
|
+
mount: "unmount",
|
|
1051
|
+
setup: "cleanup"
|
|
937
1052
|
});
|
|
938
|
-
|
|
1053
|
+
const isInversePhase = (0, __eslint_react_eff.dual)(2, (a, b) => ComponentPhaseRelevance.get(a) === b);
|
|
1054
|
+
|
|
1055
|
+
//#endregion
|
|
1056
|
+
//#region src/component/component-render-prop.ts
|
|
1057
|
+
/**
|
|
1058
|
+
* Unsafe check whether given node is a render function
|
|
1059
|
+
* ```tsx
|
|
1060
|
+
* const renderRow = () => <div />
|
|
1061
|
+
* ` ^^^^^^^^^^^^`
|
|
1062
|
+
* _ = <Component renderRow={() => <div />} />
|
|
1063
|
+
* ` ^^^^^^^^^^^^^ `
|
|
1064
|
+
* ```
|
|
1065
|
+
* @param context The rule context
|
|
1066
|
+
* @param node The AST node to check
|
|
1067
|
+
* @returns `true` if node is a render function, `false` if not
|
|
1068
|
+
*/
|
|
939
1069
|
function isRenderFunctionLoose(context, node) {
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1070
|
+
const { body, parent } = node;
|
|
1071
|
+
if (__eslint_react_ast.getFunctionId(node)?.name.startsWith("render")) return parent.type === __typescript_eslint_types.AST_NODE_TYPES.JSXExpressionContainer && parent.parent.type === __typescript_eslint_types.AST_NODE_TYPES.JSXAttribute && parent.parent.name.type === __typescript_eslint_types.AST_NODE_TYPES.JSXIdentifier && parent.parent.name.name.startsWith("render");
|
|
1072
|
+
return isJsxLike(context.sourceCode, body, JSXDetectionHint.SkipNullLiteral | JSXDetectionHint.SkipUndefined | JSXDetectionHint.StrictLogical | JSXDetectionHint.StrictConditional);
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Unsafe check whether given JSXAttribute is a render prop
|
|
1076
|
+
* ```tsx
|
|
1077
|
+
* _ = <Component renderRow={() => <div />} />
|
|
1078
|
+
* ` ^^^^^^^^^^^^^^^^^^^^^^^^^ `
|
|
1079
|
+
* ```
|
|
1080
|
+
* @param context The rule context
|
|
1081
|
+
* @param node The AST node to check
|
|
1082
|
+
* @returns `true` if node is a render prop, `false` if not
|
|
1083
|
+
*/
|
|
950
1084
|
function isRenderPropLoose(context, node) {
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1085
|
+
if (node.name.type !== __typescript_eslint_types.AST_NODE_TYPES.JSXIdentifier) return false;
|
|
1086
|
+
return node.name.name.startsWith("render") && node.value?.type === __typescript_eslint_types.AST_NODE_TYPES.JSXExpressionContainer && __eslint_react_ast.isFunction(node.value.expression) && isRenderFunctionLoose(context, node.value.expression);
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Unsafe check whether given node is declared directly inside a render property
|
|
1090
|
+
* ```tsx
|
|
1091
|
+
* const rows = { render: () => <div /> }
|
|
1092
|
+
* ` ^^^^^^^^^^^^^ `
|
|
1093
|
+
* _ = <Component rows={ [{ render: () => <div /> }] } />
|
|
1094
|
+
* ` ^^^^^^^^^^^^^ `
|
|
1095
|
+
* ```
|
|
1096
|
+
* @internal
|
|
1097
|
+
* @param node The AST node to check
|
|
1098
|
+
* @returns `true` if component is declared inside a render property, `false` if not
|
|
1099
|
+
*/
|
|
956
1100
|
function isDirectValueOfRenderPropertyLoose(node) {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
}
|
|
1101
|
+
const matching = (node$1) => {
|
|
1102
|
+
return node$1.type === __typescript_eslint_types.AST_NODE_TYPES.Property && node$1.key.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && node$1.key.name.startsWith("render");
|
|
1103
|
+
};
|
|
1104
|
+
return matching(node) || node.parent != null && matching(node.parent);
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Unsafe check whether given node is declared inside a render prop
|
|
1108
|
+
* ```tsx
|
|
1109
|
+
* _ = <Component renderRow={"node"} />
|
|
1110
|
+
* ` ^^^^^^ `
|
|
1111
|
+
* _ = <Component rows={ [{ render: "node" }] } />
|
|
1112
|
+
* ` ^^^^^^ `
|
|
1113
|
+
* ```
|
|
1114
|
+
* @param node The AST node to check
|
|
1115
|
+
* @returns `true` if component is declared inside a render prop, `false` if not
|
|
1116
|
+
*/
|
|
962
1117
|
function isDeclaredInRenderPropLoose(node) {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
if (parent?.type !== types.AST_NODE_TYPES.JSXAttribute) {
|
|
968
|
-
return false;
|
|
969
|
-
}
|
|
970
|
-
return parent.name.type === types.AST_NODE_TYPES.JSXIdentifier && parent.name.name.startsWith("render");
|
|
1118
|
+
if (isDirectValueOfRenderPropertyLoose(node)) return true;
|
|
1119
|
+
const parent = __eslint_react_ast.findParentNode(node, __eslint_react_ast.is(__typescript_eslint_types.AST_NODE_TYPES.JSXExpressionContainer))?.parent;
|
|
1120
|
+
if (parent?.type !== __typescript_eslint_types.AST_NODE_TYPES.JSXAttribute) return false;
|
|
1121
|
+
return parent.name.type === __typescript_eslint_types.AST_NODE_TYPES.JSXIdentifier && parent.name.name.startsWith("render");
|
|
971
1122
|
}
|
|
1123
|
+
|
|
1124
|
+
//#endregion
|
|
1125
|
+
//#region src/component/component-state.ts
|
|
972
1126
|
function isThisSetState(node) {
|
|
973
|
-
|
|
974
|
-
|
|
1127
|
+
const { callee } = node;
|
|
1128
|
+
return callee.type === __typescript_eslint_types.AST_NODE_TYPES.MemberExpression && __eslint_react_ast.isThisExpression(callee.object) && callee.property.type === __typescript_eslint_types.AST_NODE_TYPES.Identifier && callee.property.name === "setState";
|
|
975
1129
|
}
|
|
976
1130
|
function isAssignmentToThisState(node) {
|
|
977
|
-
|
|
978
|
-
|
|
1131
|
+
const { left } = node;
|
|
1132
|
+
return left.type === __typescript_eslint_types.AST_NODE_TYPES.MemberExpression && __eslint_react_ast.isThisExpression(left.object) && __eslint_react_ast.getPropertyName(left.property) === "state";
|
|
979
1133
|
}
|
|
980
1134
|
|
|
1135
|
+
//#endregion
|
|
981
1136
|
exports.ComponentDetectionHint = ComponentDetectionHint;
|
|
982
1137
|
exports.ComponentFlag = ComponentFlag;
|
|
983
1138
|
exports.ComponentPhaseRelevance = ComponentPhaseRelevance;
|
|
@@ -1102,4 +1257,4 @@ exports.isValidComponentDefinition = isValidComponentDefinition;
|
|
|
1102
1257
|
exports.stringifyJsx = stringifyJsx;
|
|
1103
1258
|
exports.useComponentCollector = useComponentCollector;
|
|
1104
1259
|
exports.useComponentCollectorLegacy = useComponentCollectorLegacy;
|
|
1105
|
-
exports.useHookCollector = useHookCollector;
|
|
1260
|
+
exports.useHookCollector = useHookCollector;
|