@eslint-react/core 2.0.0-next.146 → 2.0.0-next.148

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