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