@eslint-react/core 5.24.1 → 5.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,11 +7,6 @@ import { P, isMatching, match } from "ts-pattern";
7
7
  import ts from "typescript";
8
8
 
9
9
  //#region src/api.ts
10
- /**
11
- * Check if the node is a React API identifier or member expression.
12
- * @param api The React API name to check against (ex: "useState", "React.memo").
13
- * @returns A predicate function to check if a node matches the API.
14
- */
15
10
  function isAPI(api) {
16
11
  const func = (context, node) => {
17
12
  if (node == null) return false;
@@ -25,11 +20,6 @@ function isAPI(api) {
25
20
  }
26
21
  return dual;
27
22
  }
28
- /**
29
- * Check if the node is a call expression to a specific React API.
30
- * @param api The React API name to check against.
31
- * @returns A predicate function to check if a node is a call to the API.
32
- */
33
23
  function isAPICall(api) {
34
24
  const func = (context, node) => {
35
25
  if (node == null) return false;
@@ -41,157 +31,181 @@ function isAPICall(api) {
41
31
  }
42
32
  return dual;
43
33
  }
44
- /** Check if the node is a React `captureOwnerStack` API identifier or member expression. */
45
34
  const isCaptureOwnerStack = isAPI("captureOwnerStack");
46
- /** Check if the node is a React `Children.count` API identifier or member expression. */
47
35
  const isChildrenCount = isAPI("Children.count");
48
- /** Check if the node is a React `Children.forEach` API identifier or member expression. */
49
36
  const isChildrenForEach = isAPI("Children.forEach");
50
- /** Check if the node is a React `Children.map` API identifier or member expression. */
51
37
  const isChildrenMap = isAPI("Children.map");
52
- /** Check if the node is a React `Children.only` API identifier or member expression. */
53
38
  const isChildrenOnly = isAPI("Children.only");
54
- /** Check if the node is a React `Children.toArray` API identifier or member expression. */
55
39
  const isChildrenToArray = isAPI("Children.toArray");
56
- /** Check if the node is a React `cloneElement` API identifier or member expression. */
57
40
  const isCloneElement = isAPI("cloneElement");
58
- /** Check if the node is a React `createContext` API identifier or member expression. */
59
41
  const isCreateContext = isAPI("createContext");
60
- /** Check if the node is a React `createElement` API identifier or member expression. */
61
42
  const isCreateElement = isAPI("createElement");
62
- /** Check if the node is a React `createRef` API identifier or member expression. */
63
43
  const isCreateRef = isAPI("createRef");
64
- /** Check if the node is a React `forwardRef` API identifier or member expression. */
65
44
  const isForwardRef = isAPI("forwardRef");
66
- /** Check if the node is a React `memo` API identifier or member expression. */
67
45
  const isMemo = isAPI("memo");
68
- /** Check if the node is a React `lazy` API identifier or member expression. */
69
46
  const isLazy = isAPI("lazy");
70
- /** Check if the node is a call expression to the React `captureOwnerStack` API. */
71
47
  const isCaptureOwnerStackCall = isAPICall("captureOwnerStack");
72
- /** Check if the node is a call expression to the React `Children.count` API. */
73
48
  const isChildrenCountCall = isAPICall("Children.count");
74
- /** Check if the node is a call expression to the React `Children.forEach` API. */
75
49
  const isChildrenForEachCall = isAPICall("Children.forEach");
76
- /** Check if the node is a call expression to the React `Children.map` API. */
77
50
  const isChildrenMapCall = isAPICall("Children.map");
78
- /** Check if the node is a call expression to the React `Children.only` API. */
79
51
  const isChildrenOnlyCall = isAPICall("Children.only");
80
- /** Check if the node is a call expression to the React `Children.toArray` API. */
81
52
  const isChildrenToArrayCall = isAPICall("Children.toArray");
82
- /** Check if the node is a call expression to the React `cloneElement` API. */
83
53
  const isCloneElementCall = isAPICall("cloneElement");
84
- /** Check if the node is a call expression to the React `createContext` API. */
85
54
  const isCreateContextCall = isAPICall("createContext");
86
- /** Check if the node is a call expression to the React `createElement` API. */
87
55
  const isCreateElementCall = isAPICall("createElement");
88
- /** Check if the node is a call expression to the React `createRef` API. */
89
56
  const isCreateRefCall = isAPICall("createRef");
90
- /** Check if the node is a call expression to the React `forwardRef` API. */
91
57
  const isForwardRefCall = isAPICall("forwardRef");
92
- /** Check if the node is a call expression to the React `memo` API. */
93
58
  const isMemoCall = isAPICall("memo");
94
- /** Check if the node is a call expression to the React `lazy` API. */
95
59
  const isLazyCall = isAPICall("lazy");
96
- /** Check if the node is a React `use` API identifier or member expression. */
97
60
  const isUse = isAPI("use");
98
- /** Check if the node is a React `useActionState` API identifier or member expression. */
99
61
  const isUseActionState = isAPI("useActionState");
100
- /** Check if the node is a React `useCallback` API identifier or member expression. */
101
62
  const isUseCallback = isAPI("useCallback");
102
- /** Check if the node is a React `useContext` API identifier or member expression. */
103
63
  const isUseContext = isAPI("useContext");
104
- /** Check if the node is a React `useDebugValue` API identifier or member expression. */
105
64
  const isUseDebugValue = isAPI("useDebugValue");
106
- /** Check if the node is a React `useDeferredValue` API identifier or member expression. */
107
65
  const isUseDeferredValue = isAPI("useDeferredValue");
108
- /** Check if the node is a React `useEffect` API identifier or member expression. */
109
66
  const isUseEffect = isAPI("useEffect");
110
- /** Check if the node is a React `useFormStatus` API identifier or member expression. */
111
67
  const isUseFormStatus = isAPI("useFormStatus");
112
- /** Check if the node is a React `useId` API identifier or member expression. */
113
68
  const isUseId = isAPI("useId");
114
- /** Check if the node is a React `useImperativeHandle` API identifier or member expression. */
115
69
  const isUseImperativeHandle = isAPI("useImperativeHandle");
116
- /** Check if the node is a React `useInsertionEffect` API identifier or member expression. */
117
70
  const isUseInsertionEffect = isAPI("useInsertionEffect");
118
- /** Check if the node is a React `useLayoutEffect` API identifier or member expression. */
119
71
  const isUseLayoutEffect = isAPI("useLayoutEffect");
120
- /** Check if the node is a React `useMemo` API identifier or member expression. */
121
72
  const isUseMemo = isAPI("useMemo");
122
- /** Check if the node is a React `useOptimistic` API identifier or member expression. */
123
73
  const isUseOptimistic = isAPI("useOptimistic");
124
- /** Check if the node is a React `useReducer` API identifier or member expression. */
125
74
  const isUseReducer = isAPI("useReducer");
126
- /** Check if the node is a React `useRef` API identifier or member expression. */
127
75
  const isUseRef = isAPI("useRef");
128
- /** Check if the node is a React `useState` API identifier or member expression. */
129
76
  const isUseState = isAPI("useState");
130
- /** Check if the node is a React `useSyncExternalStore` API identifier or member expression. */
131
77
  const isUseSyncExternalStore = isAPI("useSyncExternalStore");
132
- /** Check if the node is a React `useTransition` API identifier or member expression. */
133
78
  const isUseTransition = isAPI("useTransition");
134
- /** Check if the node is a call expression to the React `use` API. */
135
79
  const isUseCall = isAPICall("use");
136
- /** Check if the node is a call expression to the React `useActionState` API. */
137
80
  const isUseActionStateCall = isAPICall("useActionState");
138
- /** Check if the node is a call expression to the React `useCallback` API. */
139
81
  const isUseCallbackCall = isAPICall("useCallback");
140
- /** Check if the node is a call expression to the React `useContext` API. */
141
82
  const isUseContextCall = isAPICall("useContext");
142
- /** Check if the node is a call expression to the React `useDebugValue` API. */
143
83
  const isUseDebugValueCall = isAPICall("useDebugValue");
144
- /** Check if the node is a call expression to the React `useDeferredValue` API. */
145
84
  const isUseDeferredValueCall = isAPICall("useDeferredValue");
146
- /** Check if the node is a call expression to the React `useEffect` API. */
147
85
  const isUseEffectCall = isAPICall("useEffect");
148
- /** Check if the node is a call expression to the React `useFormStatus` API. */
149
86
  const isUseFormStatusCall = isAPICall("useFormStatus");
150
- /** Check if the node is a call expression to the React `useId` API. */
151
87
  const isUseIdCall = isAPICall("useId");
152
- /** Check if the node is a call expression to the React `useImperativeHandle` API. */
153
88
  const isUseImperativeHandleCall = isAPICall("useImperativeHandle");
154
- /** Check if the node is a call expression to the React `useInsertionEffect` API. */
155
89
  const isUseInsertionEffectCall = isAPICall("useInsertionEffect");
156
- /** Check if the node is a call expression to the React `useLayoutEffect` API. */
157
90
  const isUseLayoutEffectCall = isAPICall("useLayoutEffect");
158
- /** Check if the node is a call expression to the React `useMemo` API. */
159
91
  const isUseMemoCall = isAPICall("useMemo");
160
- /** Check if the node is a call expression to the React `useOptimistic` API. */
161
92
  const isUseOptimisticCall = isAPICall("useOptimistic");
162
- /** Check if the node is a call expression to the React `useReducer` API. */
163
93
  const isUseReducerCall = isAPICall("useReducer");
164
- /** Check if the node is a call expression to the React `useRef` API. */
165
94
  const isUseRefCall = isAPICall("useRef");
166
- /** Check if the node is a call expression to the React `useState` API. */
167
95
  const isUseStateCall = isAPICall("useState");
168
- /** Check if the node is a call expression to the React `useSyncExternalStore` API. */
169
96
  const isUseSyncExternalStoreCall = isAPICall("useSyncExternalStore");
170
- /** Check if the node is a call expression to the React `useTransition` API. */
171
97
  const isUseTransitionCall = isAPICall("useTransition");
172
98
 
173
99
  //#endregion
174
100
  //#region src/class.ts
175
- /**
176
- * Get the class identifier of a class node.
177
- * @param node The class node to get the identifier from.
178
- * @returns The class identifier or `null` if not found.
179
- */
180
101
  function getClassId(node) {
181
102
  if (node.id != null) return node.id;
182
103
  if (node.parent.type === AST_NODE_TYPES.VariableDeclarator) return node.parent.id;
183
104
  return null;
184
105
  }
185
106
 
107
+ //#endregion
108
+ //#region ../../.pkgs/eff/dist/index.js
109
+ const pipeArguments = (self, args) => {
110
+ switch (args.length) {
111
+ case 0: return self;
112
+ case 1: return args[0](self);
113
+ case 2: return args[1](args[0](self));
114
+ case 3: return args[2](args[1](args[0](self)));
115
+ case 4: return args[3](args[2](args[1](args[0](self))));
116
+ case 5: return args[4](args[3](args[2](args[1](args[0](self)))));
117
+ case 6: return args[5](args[4](args[3](args[2](args[1](args[0](self))))));
118
+ case 7: return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))));
119
+ case 8: return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))));
120
+ case 9: return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))));
121
+ default: {
122
+ let ret = self;
123
+ for (let i = 0, len = args.length; i < len; i++) ret = args[i](ret);
124
+ return ret;
125
+ }
126
+ }
127
+ };
128
+ const Prototype = { pipe() {
129
+ return pipeArguments(this, arguments);
130
+ } };
131
+ const Class = (function() {
132
+ function PipeableBase() {}
133
+ PipeableBase.prototype = Prototype;
134
+ return PipeableBase;
135
+ })();
136
+ const dual = function(arity, body) {
137
+ if (typeof arity === "function") return function() {
138
+ return arity(arguments) ? body.apply(this, arguments) : ((self) => body(self, ...arguments));
139
+ };
140
+ switch (arity) {
141
+ case 0:
142
+ case 1: throw new RangeError(`Invalid arity ${arity}`);
143
+ case 2: return function(a, b) {
144
+ if (arguments.length >= 2) return body(a, b);
145
+ return function(self) {
146
+ return body(self, a);
147
+ };
148
+ };
149
+ case 3: return function(a, b, c) {
150
+ if (arguments.length >= 3) return body(a, b, c);
151
+ return function(self) {
152
+ return body(self, a, b);
153
+ };
154
+ };
155
+ default: return function() {
156
+ if (arguments.length >= arity) return body.apply(this, arguments);
157
+ const args = arguments;
158
+ return function(self) {
159
+ return body(self, ...args);
160
+ };
161
+ };
162
+ }
163
+ };
164
+ const identity = (a) => a;
165
+ const cast = identity;
166
+ const constant = (value) => () => value;
167
+ const constTrue = constant(true);
168
+ const constFalse = constant(false);
169
+ const constNull = constant(null);
170
+ const constUndefined = constant(void 0);
171
+ const compose = dual(2, (ab, bc) => (a) => bc(ab(a)));
172
+ const absurd = (_) => {
173
+ throw new Error("Called `absurd` function which should be uncallable");
174
+ };
175
+ const hole = cast(absurd);
176
+ const and = dual(2, (a, b) => (data) => a(data) && b(data));
177
+ const or = dual(2, (a, b) => (data) => a(data) || b(data));
178
+ const xor = dual(2, (a, b) => (data) => a(data) !== b(data));
179
+ const eqv = dual(2, (a, b) => (data) => a(data) === b(data));
180
+ const implies = dual(2, (antecedent, consequent) => (data) => !antecedent(data) || consequent(data));
181
+ const nor = dual(2, (a, b) => (data) => !a(data) && !b(data));
182
+ const nand = dual(2, (a, b) => (data) => !a(data) || !b(data));
183
+ function isFunction(input) {
184
+ return typeof input === "function";
185
+ }
186
+ function isObjectKeyword(input) {
187
+ return typeof input === "object" && input !== null || isFunction(input);
188
+ }
189
+ const hasProperty = dual(2, (data, property) => isObjectKeyword(data) && property in data);
190
+ const dropWhile = dual(2, (self, predicate) => {
191
+ const input = Array.isArray(self) ? self : Array.from(self);
192
+ const len = input.length;
193
+ let idx = 0;
194
+ while (idx < len && predicate(input[idx], idx)) idx++;
195
+ return input.slice(idx);
196
+ });
197
+ const takeWhile = dual(2, (self, predicate) => {
198
+ const input = Array.isArray(self) ? self : Array.from(self);
199
+ const len = input.length;
200
+ let idx = 0;
201
+ while (idx < len && predicate(input[idx], idx)) idx++;
202
+ return input.slice(0, idx);
203
+ });
204
+
186
205
  //#endregion
187
206
  //#region src/class-component.ts
188
- /**
189
- * Check if the node is a class component (extends `Component` or `PureComponent`).
190
- * @param node The node to check.
191
- * @returns `true` if the node is a class component.
192
- */
193
207
  function isClassComponent(node) {
194
- if ("superClass" in node && node.superClass != null) {
208
+ if (hasProperty(node, "superClass") && node.superClass != null) {
195
209
  const re = /^(?:Pure)?Component$/u;
196
210
  switch (true) {
197
211
  case Check.isIdentifier(node.superClass): return re.test(node.superClass.name);
@@ -200,14 +214,8 @@ function isClassComponent(node) {
200
214
  }
201
215
  return false;
202
216
  }
203
- /**
204
- * Check if the node is a pure component (extends `PureComponent`).
205
- * @param node The AST node to check.
206
- * @returns `true` if the node is a pure component.
207
- * @deprecated Class components are legacy. This function exists only to support legacy rules.
208
- */
209
217
  function isPureComponent(node) {
210
- if ("superClass" in node && node.superClass != null) {
218
+ if (hasProperty(node, "superClass") && node.superClass != null) {
211
219
  const re = /^PureComponent$/u;
212
220
  switch (true) {
213
221
  case Check.isIdentifier(node.superClass): return re.test(node.superClass.name);
@@ -219,68 +227,33 @@ function isPureComponent(node) {
219
227
  function createLifecycleChecker(methodName, isStatic = false) {
220
228
  return (node) => Check.isPropertyOrMethod(node) && node.static === isStatic && Check.isIdentifier(node.key, methodName);
221
229
  }
222
- /** @deprecated Class components are legacy. */
223
230
  const isRender = createLifecycleChecker("render");
224
- /** @deprecated Class components are legacy. */
225
231
  const isComponentDidCatch = createLifecycleChecker("componentDidCatch");
226
- /** @deprecated Class components are legacy. */
227
232
  const isComponentDidMount = createLifecycleChecker("componentDidMount");
228
- /** @deprecated Class components are legacy. */
229
233
  const isComponentDidUpdate = createLifecycleChecker("componentDidUpdate");
230
- /** @deprecated Class components are legacy. */
231
234
  const isComponentWillMount = createLifecycleChecker("componentWillMount");
232
- /** @deprecated Class components are legacy. */
233
235
  const isComponentWillReceiveProps = createLifecycleChecker("componentWillReceiveProps");
234
- /** @deprecated Class components are legacy. */
235
236
  const isComponentWillUnmount = createLifecycleChecker("componentWillUnmount");
236
- /** @deprecated Class components are legacy. */
237
237
  const isComponentWillUpdate = createLifecycleChecker("componentWillUpdate");
238
- /** @deprecated Class components are legacy. */
239
238
  const isGetChildContext = createLifecycleChecker("getChildContext");
240
- /** @deprecated Class components are legacy. */
241
239
  const isGetInitialState = createLifecycleChecker("getInitialState");
242
- /** @deprecated Class components are legacy. */
243
240
  const isGetSnapshotBeforeUpdate = createLifecycleChecker("getSnapshotBeforeUpdate");
244
- /** @deprecated Class components are legacy. */
245
241
  const isShouldComponentUpdate = createLifecycleChecker("shouldComponentUpdate");
246
- /** @deprecated Class components are legacy. */
247
242
  const isUnsafeComponentWillMount = createLifecycleChecker("UNSAFE_componentWillMount");
248
- /** @deprecated Class components are legacy. */
249
243
  const isUnsafeComponentWillReceiveProps = createLifecycleChecker("UNSAFE_componentWillReceiveProps");
250
- /** @deprecated Class components are legacy. */
251
244
  const isUnsafeComponentWillUpdate = createLifecycleChecker("UNSAFE_componentWillUpdate");
252
- /** @deprecated Class components are legacy. */
253
245
  const isGetDefaultProps = createLifecycleChecker("getDefaultProps", true);
254
- /** @deprecated Class components are legacy. */
255
246
  const isGetDerivedStateFromProps = createLifecycleChecker("getDerivedStateFromProps", true);
256
- /** @deprecated Class components are legacy. */
257
247
  const isGetDerivedStateFromError = createLifecycleChecker("getDerivedStateFromError", true);
258
- /**
259
- * Check if the node is a render-like method of a class component.
260
- * @param node The AST node to check.
261
- * @returns `true` if the node is a render-like method.
262
- * @deprecated Class components are legacy. This function exists only to support legacy rules.
263
- */
264
248
  function isRenderMethodLike(node) {
265
249
  return Check.isPropertyOrMethod(node) && Check.isIdentifier(node.key) && node.key.name.startsWith("render") && Check.isOneOf([AST_NODE_TYPES.ClassDeclaration, AST_NODE_TYPES.ClassExpression])(node.parent.parent);
266
250
  }
267
- /**
268
- * Check if the function is a callback passed to a class component's render method.
269
- * @param node The function node to check.
270
- * @returns `true` if the function is a render method callback.
271
- */
272
251
  function isRenderMethodCallback(node) {
273
252
  const parent = node.parent;
274
253
  const greatGrandparent = parent.parent?.parent;
275
254
  if (greatGrandparent == null) return false;
276
255
  return isRenderMethodLike(parent) && isClassComponent(greatGrandparent);
277
256
  }
278
- /**
279
- * Check if the call expression is a `this.setState(...)` call.
280
- * @param node The call expression node to check.
281
- * @returns `true` if the node is a `this.setState(...)` call.
282
- * @deprecated Class components are legacy. This function exists only to support legacy rules.
283
- */
284
257
  function isThisSetStateCall(node) {
285
258
  const callee = Extract.unwrap(node.callee);
286
259
  return callee.type === AST_NODE_TYPES.MemberExpression && Extract.unwrap(callee.object).type === AST_NODE_TYPES.ThisExpression && Extract.getCalleeName(node) === "setState";
@@ -288,11 +261,6 @@ function isThisSetStateCall(node) {
288
261
 
289
262
  //#endregion
290
263
  //#region src/class-component-collector.ts
291
- /**
292
- * Get an api and visitor object for the rule to collect class components.
293
- * @param context The rule context.
294
- * @deprecated Class components are legacy. This function exists only to support legacy rules.
295
- */
296
264
  function getClassComponentCollector(context) {
297
265
  const components = /* @__PURE__ */ new Map();
298
266
  const getText = (n) => context.sourceCode.getText(n);
@@ -326,27 +294,10 @@ function getClassComponentCollector(context) {
326
294
 
327
295
  //#endregion
328
296
  //#region src/create-element.ts
329
- /**
330
- * Get the type argument (the first argument) of a `createElement` call.
331
- * @param context The ESLint rule context.
332
- * @param node The node to inspect.
333
- * @returns The type argument, or `null` when the node is not a `createElement` call or has no arguments.
334
- */
335
297
  function getCreateElementTypeArgument(context, node) {
336
298
  if (!isCreateElementCall(context, node)) return null;
337
299
  return node.arguments[0] ?? null;
338
300
  }
339
- /**
340
- * Get the props object (the second argument) of a `createElement` call.
341
- *
342
- * Type expressions and chain expressions wrapping the argument are unwrapped
343
- * before the object check; `null`, spread, or otherwise non-object props
344
- * arguments yield `null`.
345
- *
346
- * @param context The ESLint rule context.
347
- * @param node The node to inspect.
348
- * @returns The props `ObjectExpression`, or `null` when absent or not statically an object literal.
349
- */
350
301
  function getCreateElementPropsObject(context, node) {
351
302
  if (!isCreateElementCall(context, node)) return null;
352
303
  const propsArg = node.arguments[1];
@@ -354,57 +305,21 @@ function getCreateElementPropsObject(context, node) {
354
305
  const expr = Extract.unwrap(propsArg);
355
306
  return expr.type === AST_NODE_TYPES.ObjectExpression ? expr : null;
356
307
  }
357
- /**
358
- * Get the children arguments (the arguments after the props object) of a `createElement` call.
359
- * @param context The ESLint rule context.
360
- * @param node The node to inspect.
361
- * @returns The children arguments, or an empty array when the node is not a `createElement` call.
362
- */
363
308
  function getCreateElementChildrenArguments(context, node) {
364
309
  if (!isCreateElementCall(context, node)) return [];
365
310
  return node.arguments.slice(2);
366
311
  }
367
- /**
368
- * Find a statically named property in the props object of a `createElement` call.
369
- *
370
- * Statically resolvable names include plain identifier keys as well as
371
- * string-literal and simple template-literal keys (computed or not).
372
- * @param context The ESLint rule context.
373
- * @param node The node to inspect.
374
- * @param name The property name to look for (ex: `"children"`, `"key"`).
375
- * @returns The matching `Property` node, or `null` when the call has no static property with that name.
376
- *
377
- * @example
378
- * ```ts
379
- * import { getCreateElementProp } from "@eslint-react/core";
380
- *
381
- * const childrenProp = getCreateElementProp(context, node, "children");
382
- * ```
383
- */
384
312
  function getCreateElementProp(context, node, name) {
385
313
  const propsObject = getCreateElementPropsObject(context, node);
386
314
  if (propsObject == null) return null;
387
315
  for (const prop of propsObject.properties) if (prop.type === AST_NODE_TYPES.Property && Extract.getPropertyName(prop, "max") === name) return prop;
388
316
  return null;
389
317
  }
390
- /**
391
- * Check if the node is passed as a children argument (the third argument or
392
- * later) of a `createElement` call.
393
- * @param context The ESLint rule context.
394
- * @param node The node to check.
395
- * @returns `true` if the node is a direct children argument of a `createElement` call.
396
- */
397
318
  function isCreateElementChildrenArgument(context, node) {
398
319
  let parent = node.parent;
399
320
  while (Check.isTypeExpression(parent)) parent = parent.parent;
400
321
  return parent?.type === AST_NODE_TYPES.CallExpression && isCreateElementCall(context, parent) && parent.arguments.slice(2).some((arg) => Extract.unwrap(arg) === node);
401
322
  }
402
- /**
403
- * Check if the node is inside the props object (the second argument) of a `createElement` call.
404
- * @param context The ESLint rule context.
405
- * @param node The node to check.
406
- * @returns `true` if the node is inside `createElement`'s props object.
407
- */
408
323
  function isInsideCreateElementProps(context, node) {
409
324
  const call = Traverse.findParent(node, isCreateElementCall(context));
410
325
  if (call == null) return false;
@@ -415,23 +330,9 @@ function isInsideCreateElementProps(context, node) {
415
330
 
416
331
  //#endregion
417
332
  //#region src/function.ts
418
- /**
419
- * Get the static identifier of a function AST node.
420
- *
421
- * @remarks
422
- * For function declarations this is straightforward. For anonymous function
423
- * expressions it is more complex. This function roughly detects the same AST
424
- * nodes as the ECMAScript spec's `IsAnonymousFunctionDefinition()` with some
425
- * exceptions to better fit our use case.
426
- *
427
- * Ported from {@link https://github.com/facebook/react/blob/bb8a76c6cc77ea2976d690ea09f5a1b3d9b1792a/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts#L860 | RulesOfHooks.ts}
428
- *
429
- * @param node The function node to analyze.
430
- * @returns The identifier node if found, `null` otherwise.
431
- */
432
333
  function getFunctionId(node) {
433
334
  switch (true) {
434
- case "id" in node && node.id != null: return node.id;
335
+ case hasProperty(node, "id") && node.id != null: return node.id;
435
336
  case node.parent.type === AST_NODE_TYPES.VariableDeclarator && node.parent.init === node: return node.parent.id;
436
337
  case node.parent.type === AST_NODE_TYPES.AssignmentExpression && node.parent.right === node && node.parent.operator === "=": return node.parent.left;
437
338
  case node.parent.type === AST_NODE_TYPES.Property && node.parent.value === node && !node.parent.computed: return node.parent.key;
@@ -442,12 +343,6 @@ function getFunctionId(node) {
442
343
  }
443
344
  return null;
444
345
  }
445
- /**
446
- * Get the initialization path of a function node in the AST.
447
- *
448
- * @param node The function node to analyze.
449
- * @returns The function initialization path or `null` if not identifiable.
450
- */
451
346
  function getFunctionInitPath(node) {
452
347
  if (node.type === AST_NODE_TYPES.FunctionDeclaration) return [node];
453
348
  let parent = node.parent;
@@ -493,36 +388,18 @@ function getFunctionInitPath(node) {
493
388
  }
494
389
  return null;
495
390
  }
496
- /**
497
- * Check if a specific function call exists in the function initialization path.
498
- *
499
- * @param callName The name of the call to check for (e.g., "memo", "forwardRef").
500
- * @param initPath The function initialization path to search in.
501
- * @returns `true` if the call exists in the path, `false` otherwise.
502
- */
503
391
  function isFunctionHasCallInInitPath(callName, initPath) {
504
392
  return initPath.some((node) => {
505
393
  if (node.type !== AST_NODE_TYPES.CallExpression) return false;
506
394
  const callee = Extract.unwrap(node.callee);
507
395
  if (Check.isIdentifier(callee)) return callee.name === callName;
508
- if (callee.type === AST_NODE_TYPES.MemberExpression && "name" in callee.property) return callee.property.name === callName;
396
+ if (callee.type === AST_NODE_TYPES.MemberExpression && hasProperty(callee.property, "name")) return callee.property.name === callName;
509
397
  return false;
510
398
  });
511
399
  }
512
- /**
513
- * Check if a function is empty.
514
- *
515
- * @param node The function node to check.
516
- * @returns `true` if the function is empty, `false` otherwise.
517
- */
518
400
  function isFunctionEmpty(node) {
519
401
  return node.body.type === AST_NODE_TYPES.BlockStatement && node.body.body.length === 0;
520
402
  }
521
- /**
522
- * Get the directives of a function (ex: "use strict", "use client", "use server").
523
- * @param node The function node to get the directives from.
524
- * @returns The directives of the function.
525
- */
526
403
  function getFunctionDirectives(node) {
527
404
  const directives = [];
528
405
  if (node.body.type !== AST_NODE_TYPES.BlockStatement) return directives;
@@ -535,17 +412,9 @@ function getFunctionDirectives(node) {
535
412
  }
536
413
  return directives;
537
414
  }
538
- /**
539
- * Check if a directive with the given name exists in the function directives.
540
- *
541
- * @param node The function AST node.
542
- * @param name The directive name to check (e.g., "use memo", "use no memo").
543
- * @returns `true` if the directive exists, `false` otherwise.
544
- */
545
415
  function isFunctionHasDirective(node, name) {
546
416
  return getFunctionDirectives(node).some((d) => d.directive === name);
547
417
  }
548
- /** The esquery selector matching `displayName` assignment expressions. */
549
418
  const SEL_FUNCTION_DISPLAY_NAME_ASSIGNMENT = [
550
419
  "AssignmentExpression",
551
420
  "[operator='=']",
@@ -555,67 +424,21 @@ const SEL_FUNCTION_DISPLAY_NAME_ASSIGNMENT = [
555
424
 
556
425
  //#endregion
557
426
  //#region src/jsx.ts
558
- /**
559
- * Hints for JSX detection.
560
- */
561
427
  const JsxDetectionHint = {
562
- /** No hints set. */
563
428
  None: 0n,
564
- /** Do not treat `null` values as JSX-like. */
565
429
  DoNotIncludeJsxWithNullValue: 1n << 0n,
566
- /** Do not treat number values as JSX-like. */
567
430
  DoNotIncludeJsxWithNumberValue: 1n << 1n,
568
- /** Do not treat bigint values as JSX-like. */
569
431
  DoNotIncludeJsxWithBigIntValue: 1n << 2n,
570
- /** Do not treat string values as JSX-like. */
571
432
  DoNotIncludeJsxWithStringValue: 1n << 3n,
572
- /** Do not treat boolean values as JSX-like. */
573
433
  DoNotIncludeJsxWithBooleanValue: 1n << 4n,
574
- /** Do not treat undefined values as JSX-like. */
575
434
  DoNotIncludeJsxWithUndefinedValue: 1n << 5n,
576
- /** Do not treat empty array values as JSX-like. */
577
435
  DoNotIncludeJsxWithEmptyArrayValue: 1n << 6n,
578
- /** Do not treat `createElement` calls as JSX-like. */
579
436
  DoNotIncludeJsxWithCreateElementValue: 1n << 7n,
580
- /** Require all array elements to be JSX-like for the array to be JSX-like. */
581
437
  RequireAllArrayElementsToBeJsx: 1n << 8n,
582
- /** Require both sides of a logical expression to be JSX-like. */
583
438
  RequireBothSidesOfLogicalExpressionToBeJsx: 1n << 9n,
584
- /** Require both branches of a conditional expression to be JSX-like. */
585
439
  RequireBothBranchesOfConditionalExpressionToBeJsx: 1n << 10n
586
440
  };
587
- /**
588
- * Default JSX detection hint.
589
- *
590
- * Skips number, bigint, boolean, string, and undefined literals,
591
- * the value types that are commonly returned alongside JSX in React
592
- * components but are not themselves renderable elements.
593
- */
594
441
  const DEFAULT_JSX_DETECTION_HINT = 0n | JsxDetectionHint.DoNotIncludeJsxWithNumberValue | JsxDetectionHint.DoNotIncludeJsxWithBigIntValue | JsxDetectionHint.DoNotIncludeJsxWithBooleanValue | JsxDetectionHint.DoNotIncludeJsxWithStringValue | JsxDetectionHint.DoNotIncludeJsxWithUndefinedValue;
595
- /**
596
- * Check if the node represents JSX-like content based on heuristics.
597
- *
598
- * The detection behavior is configurable through {@link JsxDetectionHint}
599
- * bit-flags so that callers can opt individual value kinds in or out.
600
- *
601
- * Identifiers are resolved to their definitions via scope analysis;
602
- * circular definitions (e.g. `var a = b; var b = a;`) are detected and
603
- * treated as not JSX-like instead of recursing indefinitely.
604
- *
605
- * @param context The ESLint rule context (needed for variable resolution).
606
- * @param node The AST node to analyze.
607
- * @param hint Optional bit-flags to adjust detection behavior. Defaults to {@link DEFAULT_JSX_DETECTION_HINT}.
608
- * @returns Whether the node is considered JSX-like.
609
- *
610
- * @example
611
- * ```ts
612
- * import { isJsxLike } from "@eslint-react/core";
613
- *
614
- * if (isJsxLike(context, node)) {
615
- * // node looks like it evaluates to a React element
616
- * }
617
- * ```
618
- */
619
442
  function isJsxLike(context, node, hint = DEFAULT_JSX_DETECTION_HINT) {
620
443
  const seen = /* @__PURE__ */ new Set();
621
444
  function visit(node) {
@@ -655,49 +478,23 @@ function isJsxLike(context, node, hint = DEFAULT_JSX_DETECTION_HINT) {
655
478
 
656
479
  //#endregion
657
480
  //#region src/function-component.ts
658
- /**
659
- * Component flag constants.
660
- */
661
481
  const FunctionComponentFlag = {
662
- /** No flags set. */
663
482
  None: 0n,
664
- /** Indicates the component is a pure component (ex: extends PureComponent). */
665
483
  PureComponent: 1n << 0n,
666
- /** Indicates the component creates elements using `createElement` instead of JSX. */
667
484
  CreateElement: 1n << 1n,
668
- /** Indicates the component is memoized (ex: React.memo). */
669
485
  Memo: 1n << 2n,
670
- /** Indicates the component forwards a ref (ex: React.forwardRef). */
671
486
  ForwardRef: 1n << 3n
672
487
  };
673
- /**
674
- * Get component flag from init path.
675
- * @param initPath The init path of the function component.
676
- * @returns The component flag.
677
- * @internal
678
- */
679
488
  function getFunctionComponentFlagFromInitPath(initPath) {
680
489
  let flag = FunctionComponentFlag.None;
681
490
  if (initPath != null && isFunctionHasCallInInitPath("memo", initPath)) flag |= FunctionComponentFlag.Memo;
682
491
  if (initPath != null && isFunctionHasCallInInitPath("forwardRef", initPath)) flag |= FunctionComponentFlag.ForwardRef;
683
492
  return flag;
684
493
  }
685
- /**
686
- * Check if the node is a call expression for a component wrapper.
687
- * @param context The ESLint rule context.
688
- * @param node The node to check.
689
- * @returns `true` if the node is a call expression for a component wrapper.
690
- */
691
494
  function isFunctionComponentWrapperCall(context, node) {
692
495
  if (node.type !== AST_NODE_TYPES.CallExpression) return false;
693
496
  return isMemoCall(context, node) || isForwardRefCall(context, node);
694
497
  }
695
- /**
696
- * Check if the node is a callback function passed to a component wrapper.
697
- * @param context The ESLint rule context.
698
- * @param node The node to check.
699
- * @returns `true` if the node is a callback function passed to a component wrapper.
700
- */
701
498
  function isFunctionComponentWrapperCallback(context, node) {
702
499
  if (!Check.isFunction(node)) return false;
703
500
  let parent = node.parent;
@@ -705,12 +502,6 @@ function isFunctionComponentWrapperCallback(context, node) {
705
502
  if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
706
503
  return isFunctionComponentWrapperCall(context, parent);
707
504
  }
708
- /**
709
- * Get function component identifier from `const Component = memo(() => {});`.
710
- * @param context The rule context.
711
- * @param node The AST node to get the function component identifier from.
712
- * @internal
713
- */
714
505
  function getFunctionComponentId(context, node) {
715
506
  const functionId = getFunctionId(node);
716
507
  if (functionId != null) return functionId;
@@ -722,29 +513,12 @@ function getFunctionComponentId(context, node) {
722
513
  default: return null;
723
514
  }
724
515
  }
725
- /**
726
- * Check if a string matches the strict component name pattern.
727
- * @param name The name to check.
728
- * @returns `true` if the name matches the strict component name pattern.
729
- */
730
516
  function isFunctionComponentName(name) {
731
517
  return RE_COMPONENT_NAME.test(name);
732
518
  }
733
- /**
734
- * Check if a string matches the loose component name pattern.
735
- * @param name The name to check.
736
- * @returns `true` if the name matches the loose component name pattern.
737
- */
738
519
  function isFunctionComponentNameLoose(name) {
739
520
  return RE_COMPONENT_NAME_LOOSE.test(name);
740
521
  }
741
- /**
742
- * Check if a function has a loose component name.
743
- * @param context The rule context.
744
- * @param fn The function to check.
745
- * @param allowNone Whether to allow no name.
746
- * @returns `true` if the function has a loose component name.
747
- */
748
522
  function isFunctionWithLooseComponentName(context, fn, allowNone = false) {
749
523
  const id = getFunctionComponentId(context, fn);
750
524
  if (id == null) return allowNone;
@@ -752,40 +526,18 @@ function isFunctionWithLooseComponentName(context, fn, allowNone = false) {
752
526
  if (id.type === AST_NODE_TYPES.MemberExpression && Check.isIdentifier(id.property)) return isFunctionComponentNameLoose(id.property.name);
753
527
  return false;
754
528
  }
755
- /**
756
- * Hints for component collector.
757
- */
758
529
  const FunctionComponentDetectionHint = {
759
530
  ...JsxDetectionHint,
760
- /** Exclude functions defined as class methods from component detection. */
761
531
  DoNotIncludeFunctionDefinedAsClassMethod: 1n << 11n,
762
- /** Exclude functions defined as class properties from component detection. */
763
532
  DoNotIncludeFunctionDefinedAsClassProperty: 1n << 12n,
764
- /** Exclude functions defined as object methods from component detection. */
765
533
  DoNotIncludeFunctionDefinedAsObjectMethod: 1n << 13n,
766
- /** Exclude functions defined as array expression elements from component detection. */
767
534
  DoNotIncludeFunctionDefinedAsArrayExpressionElement: 1n << 14n,
768
- /** Exclude functions defined as array pattern elements from component detection. */
769
535
  DoNotIncludeFunctionDefinedAsArrayPatternElement: 1n << 15n,
770
- /** Exclude functions defined as array flatMap callbacks from component detection. */
771
536
  DoNotIncludeFunctionDefinedAsArrayFlatMapCallback: 1n << 16n,
772
- /** Exclude functions defined as array map callbacks from component detection. */
773
537
  DoNotIncludeFunctionDefinedAsArrayMapCallback: 1n << 17n,
774
- /** Exclude functions defined as arbitrary call expression callbacks from component detection. */
775
538
  DoNotIncludeFunctionDefinedAsArbitraryCallExpressionCallback: 1n << 18n
776
539
  };
777
- /**
778
- * Default component detection hint.
779
- */
780
540
  const DEFAULT_COMPONENT_DETECTION_HINT = 0n | FunctionComponentDetectionHint.DoNotIncludeJsxWithBigIntValue | FunctionComponentDetectionHint.DoNotIncludeJsxWithBooleanValue | FunctionComponentDetectionHint.DoNotIncludeJsxWithNumberValue | FunctionComponentDetectionHint.DoNotIncludeJsxWithStringValue | FunctionComponentDetectionHint.DoNotIncludeJsxWithUndefinedValue | FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArbitraryCallExpressionCallback | FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayExpressionElement | FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayFlatMapCallback | FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback | FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayPatternElement | FunctionComponentDetectionHint.RequireAllArrayElementsToBeJsx | FunctionComponentDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx | FunctionComponentDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx;
781
- /**
782
- * Check if the function node is a valid React component definition.
783
- *
784
- * @param context The rule context.
785
- * @param node The function node to analyze.
786
- * @param hint Component detection hints (bit flags) to customize detection logic.
787
- * @returns `true` if the node is considered a component definition.
788
- */
789
541
  function isFunctionComponentDefinition(context, node, hint) {
790
542
  if (!isFunctionWithLooseComponentName(context, node, true)) return false;
791
543
  let parent = node.parent;
@@ -828,783 +580,8 @@ function isFunctionComponentDefinition(context, node, hint) {
828
580
  return significantParent.type !== AST_NODE_TYPES.JSXExpressionContainer;
829
581
  }
830
582
 
831
- //#endregion
832
- //#region ../../.pkgs/eff/dist/index.js
833
- /**
834
- * Applies a `pipe` method's variadic arguments to an initial value from left
835
- * to right.
836
- *
837
- * **When to use**
838
- *
839
- * Use to implement a custom `.pipe(...)` method from JavaScript's `arguments`
840
- * object.
841
- *
842
- * **Details**
843
- *
844
- * This helper is intended for implementing `Pipeable.pipe` methods that
845
- * receive JavaScript's `arguments` object. With no functions it returns the
846
- * original value; otherwise it feeds each result into the next function.
847
- *
848
- * **Example** (Implementing a pipe method)
849
- *
850
- * ```ts
851
- * import { Pipeable } from "effect"
852
- *
853
- * class NumberBox {
854
- * constructor(readonly value: number) {}
855
- *
856
- * pipe(..._fns: ReadonlyArray<(value: number) => number>): number {
857
- * return Pipeable.pipeArguments(this.value, arguments) as number
858
- * }
859
- * }
860
- *
861
- * const result = new NumberBox(5).pipe(
862
- * (n) => n + 2,
863
- * (n) => n * 3
864
- * )
865
- * result // => 21
866
- * ```
867
- *
868
- * @category combinators
869
- * @since 2.0.0
870
- */
871
- const pipeArguments = (self, args) => {
872
- switch (args.length) {
873
- case 0: return self;
874
- case 1: return args[0](self);
875
- case 2: return args[1](args[0](self));
876
- case 3: return args[2](args[1](args[0](self)));
877
- case 4: return args[3](args[2](args[1](args[0](self))));
878
- case 5: return args[4](args[3](args[2](args[1](args[0](self)))));
879
- case 6: return args[5](args[4](args[3](args[2](args[1](args[0](self))))));
880
- case 7: return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))));
881
- case 8: return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))));
882
- case 9: return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))));
883
- default: {
884
- let ret = self;
885
- for (let i = 0, len = args.length; i < len; i++) ret = args[i](ret);
886
- return ret;
887
- }
888
- }
889
- };
890
- /**
891
- * Reusable prototype that implements `Pipeable.pipe`.
892
- *
893
- * **When to use**
894
- *
895
- * Use when classes or object prototypes can reuse this value when they need the
896
- * standard pipe implementation backed by `pipeArguments`.
897
- *
898
- * @category prototypes
899
- * @since 3.15.0
900
- */
901
- const Prototype = { pipe() {
902
- return pipeArguments(this, arguments);
903
- } };
904
- /**
905
- * Provides a base constructor whose instances implement the standard `Pipeable.pipe`
906
- * method.
907
- *
908
- * **When to use**
909
- *
910
- * Use when you need to define a class that supports Effect-style method
911
- * chaining through `.pipe(...)`.
912
- *
913
- * @category constructors
914
- * @since 3.15.0
915
- */
916
- const Class = (function() {
917
- function PipeableBase() {}
918
- PipeableBase.prototype = Prototype;
919
- return PipeableBase;
920
- })();
921
- /**
922
- * Creates a function that can be called in data-first style or data-last
923
- * (`pipe`-friendly) style.
924
- *
925
- * **When to use**
926
- *
927
- * Use to expose one implementation through both direct and `pipe`-friendly
928
- * call styles.
929
- *
930
- * **Details**
931
- *
932
- * Pass either the arity of the uncurried function or a predicate that decides
933
- * whether the current call is data-first. Arity is the common case. Use a
934
- * predicate when optional arguments make arity ambiguous.
935
- *
936
- * **Example** (Selecting data-first or data-last style by arity)
937
- *
938
- * ```ts
939
- * import { Function, pipe } from "effect"
940
- *
941
- * const sum = Function.dual<
942
- * (that: number) => (self: number) => number,
943
- * (self: number, that: number) => number
944
- * >(2, (self, that) => self + that)
945
- *
946
- * sum(2, 3) // => 5
947
- * pipe(2, sum(3)) // => 5
948
- * ```
949
- *
950
- * **Example** (Defining overloads with call signatures)
951
- *
952
- * ```ts
953
- * import { Function, pipe } from "effect"
954
- *
955
- * const sum: {
956
- * (that: number): (self: number) => number
957
- * (self: number, that: number): number
958
- * } = Function.dual(2, (self: number, that: number): number => self + that)
959
- *
960
- * sum(2, 3) // => 5
961
- * pipe(2, sum(3)) // => 5
962
- * ```
963
- *
964
- * **Example** (Selecting data-first or data-last style with a predicate)
965
- *
966
- * ```ts
967
- * import { Function, pipe } from "effect"
968
- *
969
- * const sum = Function.dual<
970
- * (that: number) => (self: number) => number,
971
- * (self: number, that: number) => number
972
- * >(
973
- * (args) => args.length === 2,
974
- * (self, that) => self + that
975
- * )
976
- *
977
- * sum(2, 3) // => 5
978
- * pipe(2, sum(3)) // => 5
979
- * ```
980
- *
981
- * @category combinators
982
- * @since 2.0.0
983
- */
984
- const dual = function(arity, body) {
985
- if (typeof arity === "function") return function() {
986
- return arity(arguments) ? body.apply(this, arguments) : ((self) => body(self, ...arguments));
987
- };
988
- switch (arity) {
989
- case 0:
990
- case 1: throw new RangeError(`Invalid arity ${arity}`);
991
- case 2: return function(a, b) {
992
- if (arguments.length >= 2) return body(a, b);
993
- return function(self) {
994
- return body(self, a);
995
- };
996
- };
997
- case 3: return function(a, b, c) {
998
- if (arguments.length >= 3) return body(a, b, c);
999
- return function(self) {
1000
- return body(self, a, b);
1001
- };
1002
- };
1003
- default: return function() {
1004
- if (arguments.length >= arity) return body.apply(this, arguments);
1005
- const args = arguments;
1006
- return function(self) {
1007
- return body(self, ...args);
1008
- };
1009
- };
1010
- }
1011
- };
1012
- /**
1013
- * Returns its input argument unchanged.
1014
- *
1015
- * **When to use**
1016
- *
1017
- * Use to return a value unchanged where a function is required.
1018
- *
1019
- * **Example** (Returning the same value)
1020
- *
1021
- * ```ts
1022
- * import { identity } from "effect"
1023
- *
1024
- * identity(5) // => 5
1025
- * ```
1026
- *
1027
- * @category combinators
1028
- * @since 2.0.0
1029
- */
1030
- const identity = (a) => a;
1031
- /**
1032
- * Returns the input value with a different static type.
1033
- *
1034
- * **When to use**
1035
- *
1036
- * Use when you need an explicit type-level cast and accept that the value is
1037
- * returned unchanged at runtime.
1038
- *
1039
- * **Gotchas**
1040
- *
1041
- * This is a type-level cast only; it performs no runtime validation or
1042
- * conversion.
1043
- *
1044
- * @see {@link satisfies} for checking assignability without changing the resulting type
1045
- *
1046
- * @category utility types
1047
- * @since 4.0.0
1048
- */
1049
- const cast = identity;
1050
- /**
1051
- * Creates a zero-argument function that always returns the provided value.
1052
- *
1053
- * **When to use**
1054
- *
1055
- * Use when you need a thunk or callback that returns the same value on every
1056
- * invocation.
1057
- *
1058
- * **Example** (Creating a constant thunk)
1059
- *
1060
- * ```ts
1061
- * import { Function } from "effect"
1062
- *
1063
- * const constNull = Function.constant(null)
1064
- *
1065
- * constNull() // => null
1066
- * constNull() // => null
1067
- * ```
1068
- *
1069
- * @category constructors
1070
- * @since 2.0.0
1071
- */
1072
- const constant = (value) => () => value;
1073
- /**
1074
- * Returns `true` when called.
1075
- *
1076
- * **When to use**
1077
- *
1078
- * Use when you need a thunk that returns `true` on every invocation.
1079
- *
1080
- * **Example** (Returning true from a thunk)
1081
- *
1082
- * ```ts
1083
- * import { Function } from "effect"
1084
- *
1085
- * Function.constTrue() // => true
1086
- * ```
1087
- *
1088
- * @category constants
1089
- * @since 2.0.0
1090
- */
1091
- const constTrue = constant(true);
1092
- /**
1093
- * Returns `false` when called.
1094
- *
1095
- * **When to use**
1096
- *
1097
- * Use when you need a thunk that returns `false` on every invocation.
1098
- *
1099
- * **Example** (Returning false from a thunk)
1100
- *
1101
- * ```ts
1102
- * import { Function } from "effect"
1103
- *
1104
- * Function.constFalse() // => false
1105
- * ```
1106
- *
1107
- * @category constants
1108
- * @since 2.0.0
1109
- */
1110
- const constFalse = constant(false);
1111
- /**
1112
- * Returns `null` when called.
1113
- *
1114
- * **When to use**
1115
- *
1116
- * Use when you need a thunk that returns `null` on every invocation.
1117
- *
1118
- * **Example** (Returning null from a thunk)
1119
- *
1120
- * ```ts
1121
- * import { Function } from "effect"
1122
- *
1123
- * Function.constNull() // => null
1124
- * ```
1125
- *
1126
- * @category constants
1127
- * @since 2.0.0
1128
- */
1129
- const constNull = constant(null);
1130
- /**
1131
- * Returns `undefined` when called.
1132
- *
1133
- * **When to use**
1134
- *
1135
- * Use when you need a thunk that returns `undefined` on every invocation.
1136
- *
1137
- * **Example** (Returning undefined from a thunk)
1138
- *
1139
- * ```ts
1140
- * import { Function } from "effect"
1141
- *
1142
- * Function.constUndefined() // => undefined
1143
- * ```
1144
- *
1145
- * @category constants
1146
- * @since 2.0.0
1147
- */
1148
- const constUndefined = constant(void 0);
1149
- /**
1150
- * Composes two functions, `ab` and `bc` into a single function that takes in an argument `a` of type `A` and returns a result of type `C`.
1151
- * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`.
1152
- *
1153
- * **When to use**
1154
- *
1155
- * Use to compose exactly two unary functions into a reusable unary function.
1156
- *
1157
- * **Example** (Composing two functions)
1158
- *
1159
- * ```ts
1160
- * import { Function } from "effect"
1161
- *
1162
- * const increment = (n: number) => n + 1
1163
- * const square = (n: number) => n * n
1164
- *
1165
- * Function.compose(increment, square)(2) // => 9
1166
- * ```
1167
- *
1168
- * @see {@link flow} for composing a left-to-right sequence of functions
1169
- * @see {@link pipe} for applying a value through a left-to-right sequence immediately
1170
- *
1171
- * @category combinators
1172
- * @since 2.0.0
1173
- */
1174
- const compose = dual(2, (ab, bc) => (a) => bc(ab(a)));
1175
- /**
1176
- * Marks an impossible branch by accepting a `never` value and returning any
1177
- * type.
1178
- *
1179
- * **When to use**
1180
- *
1181
- * Use when you need a return value in a branch that exhaustive checks prove
1182
- * cannot be reached.
1183
- *
1184
- * **Gotchas**
1185
- *
1186
- * Calling `absurd` throws, because a value of type `never` should be
1187
- * impossible at runtime.
1188
- *
1189
- * **Example** (Handling impossible values)
1190
- *
1191
- * ```ts
1192
- * import { absurd } from "effect"
1193
- *
1194
- * const handleNever = (value: never) => {
1195
- * return absurd(value) // This will throw an error if called
1196
- * }
1197
- * ```
1198
- *
1199
- * @category utility types
1200
- * @since 2.0.0
1201
- */
1202
- const absurd = (_) => {
1203
- throw new Error("Called `absurd` function which should be uncallable");
1204
- };
1205
- /**
1206
- * Creates a compile-time placeholder for a value of any type.
1207
- *
1208
- * **When to use**
1209
- *
1210
- * Use as a temporary typed placeholder while developing incomplete code.
1211
- *
1212
- * **Gotchas**
1213
- *
1214
- * `hole` is intended for temporary development use. If the placeholder is
1215
- * evaluated at runtime, it throws.
1216
- *
1217
- * **Example** (Creating a development placeholder)
1218
- *
1219
- * ```ts
1220
- * import { hole } from "effect"
1221
- *
1222
- * // Intentionally not called: `hole` throws if the placeholder is evaluated.
1223
- * const buildUser = (id: number): { readonly id: number; readonly name: string } => ({
1224
- * id,
1225
- * name: hole<string>()
1226
- * })
1227
- *
1228
- * ```
1229
- *
1230
- * @category utility types
1231
- * @since 2.0.0
1232
- */
1233
- const hole = cast(absurd);
1234
- /**
1235
- * Creates a predicate that returns `true` only if both predicates are `true`.
1236
- *
1237
- * **When to use**
1238
- *
1239
- * Use when you want to combine `Predicate`s with AND, accepting values that
1240
- * satisfy multiple conditions, including refinements that narrow to an
1241
- * intersection.
1242
- *
1243
- * **Details**
1244
- *
1245
- * Evaluation short-circuits on the first `false`. For refinements, the output
1246
- * type is an intersection.
1247
- *
1248
- * **Example** (Checking both conditions)
1249
- *
1250
- * ```ts
1251
- * import { Predicate } from "effect"
1252
- *
1253
- * const hasAAndB = Predicate.and(
1254
- * Predicate.hasProperty("a"),
1255
- * Predicate.hasProperty("b")
1256
- * )
1257
- *
1258
- * const input: unknown = JSON.parse(`{"a":1,"b":"ok"}`)
1259
- * if (hasAAndB(input)) {
1260
- * // input has both properties at this point
1261
- * const a = input.a
1262
- * const b = input.b
1263
- *
1264
- * const values = [a, b] // => [1, "ok"]
1265
- * }
1266
- * ```
1267
- *
1268
- * @see {@link or}
1269
- * @see {@link not}
1270
- * @category combinators
1271
- * @since 2.0.0
1272
- */
1273
- const and = dual(2, (a, b) => (data) => a(data) && b(data));
1274
- /**
1275
- * Creates a predicate that returns `true` if either predicate is `true`.
1276
- *
1277
- * **When to use**
1278
- *
1279
- * Use when you want to combine `Predicate`s with OR, accepting values that
1280
- * satisfy at least one condition, including refinements that narrow to a union.
1281
- *
1282
- * **Details**
1283
- *
1284
- * Evaluation short-circuits on the first `true`. For refinements, the output
1285
- * type is a union.
1286
- *
1287
- * **Example** (Checking either condition)
1288
- *
1289
- * ```ts
1290
- * import { Predicate } from "effect"
1291
- *
1292
- * const isStringOrNumber = Predicate.or(Predicate.isString, Predicate.isNumber)
1293
- *
1294
- * isStringOrNumber("a") // => true
1295
- * ```
1296
- *
1297
- * @see {@link and}
1298
- * @see {@link xor}
1299
- * @category combinators
1300
- * @since 2.0.0
1301
- */
1302
- const or = dual(2, (a, b) => (data) => a(data) || b(data));
1303
- /**
1304
- * Creates a predicate that returns `true` if exactly one predicate is `true`.
1305
- *
1306
- * **When to use**
1307
- *
1308
- * Use when you want to combine two `Predicate`s with exclusive-or semantics.
1309
- *
1310
- * **Details**
1311
- *
1312
- * Returns `true` when results differ.
1313
- *
1314
- * **Example** (Checking exclusive-or conditions)
1315
- *
1316
- * ```ts
1317
- * import { Predicate } from "effect"
1318
- *
1319
- * const isEven = (n: number) => n % 2 === 0
1320
- * const isPositive = (n: number) => n > 0
1321
- * const either = Predicate.xor(isEven, isPositive)
1322
- *
1323
- * either(-2) // => true
1324
- * ```
1325
- *
1326
- * @see {@link or}
1327
- * @see {@link and}
1328
- * @category combinators
1329
- * @since 2.0.0
1330
- */
1331
- const xor = dual(2, (a, b) => (data) => a(data) !== b(data));
1332
- /**
1333
- * Creates a predicate that returns `true` when both predicates agree.
1334
- *
1335
- * **When to use**
1336
- *
1337
- * Use when you want to check equivalence of two `Predicate`s.
1338
- *
1339
- * **Details**
1340
- *
1341
- * Returns `true` when both results are equal.
1342
- *
1343
- * **Example** (Defining equivalence)
1344
- *
1345
- * ```ts
1346
- * import { Predicate } from "effect"
1347
- *
1348
- * const isEven = (n: number) => n % 2 === 0
1349
- * const same = Predicate.eqv(isEven, isEven)
1350
- *
1351
- * same(3) // => true
1352
- * ```
1353
- *
1354
- * @see {@link xor}
1355
- * @category combinators
1356
- * @since 2.0.0
1357
- */
1358
- const eqv = dual(2, (a, b) => (data) => a(data) === b(data));
1359
- /**
1360
- * Creates a predicate representing logical implication: if `antecedent`, then `consequent`.
1361
- *
1362
- * **When to use**
1363
- *
1364
- * Use when you need to encode logical implication between `Predicate` rules,
1365
- * where one rule only applies when a precondition holds.
1366
- *
1367
- * **Details**
1368
- *
1369
- * Models constraints like "if A then B" and returns `true` when the antecedent
1370
- * is `false`.
1371
- *
1372
- * **Example** (Checking implication)
1373
- *
1374
- * ```ts
1375
- * import { Predicate } from "effect"
1376
- *
1377
- * const isAdult = (age: number) => age >= 18
1378
- * const canVote = (age: number) => age >= 18
1379
- * const implies = Predicate.implies(isAdult, canVote)
1380
- *
1381
- * implies(16) // => true
1382
- * ```
1383
- *
1384
- * @see {@link and}
1385
- * @see {@link or}
1386
- * @category combinators
1387
- * @since 2.0.0
1388
- */
1389
- const implies = dual(2, (antecedent, consequent) => (data) => !antecedent(data) || consequent(data));
1390
- /**
1391
- * Creates a predicate that returns `true` when neither predicate is `true`.
1392
- *
1393
- * **When to use**
1394
- *
1395
- * Use when you want to combine two `Predicate`s with logical NOR semantics.
1396
- *
1397
- * **Details**
1398
- *
1399
- * Returns the negation of `or`.
1400
- *
1401
- * **Example** (Checking NOR conditions)
1402
- *
1403
- * ```ts
1404
- * import { Predicate } from "effect"
1405
- *
1406
- * const neither = Predicate.nor(Predicate.isString, Predicate.isNumber)
1407
- *
1408
- * neither(true) // => true
1409
- * ```
1410
- *
1411
- * @see {@link or}
1412
- * @see {@link not}
1413
- * @category combinators
1414
- * @since 2.0.0
1415
- */
1416
- const nor = dual(2, (a, b) => (data) => !a(data) && !b(data));
1417
- /**
1418
- * Creates a predicate that returns `true` unless both predicates are `true`.
1419
- *
1420
- * **When to use**
1421
- *
1422
- * Use when you want to combine two `Predicate`s with logical NAND semantics.
1423
- *
1424
- * **Details**
1425
- *
1426
- * Returns the negation of `and`.
1427
- *
1428
- * **Example** (Checking NAND conditions)
1429
- *
1430
- * ```ts
1431
- * import { Predicate } from "effect"
1432
- *
1433
- * const notBoth = Predicate.nand(Predicate.isString, Predicate.isNumber)
1434
- *
1435
- * notBoth("a") // => true
1436
- * ```
1437
- *
1438
- * @see {@link and}
1439
- * @see {@link not}
1440
- * @category combinators
1441
- * @since 2.0.0
1442
- */
1443
- const nand = dual(2, (a, b) => (data) => !a(data) || !b(data));
1444
- /**
1445
- * Checks whether a value is a `function`.
1446
- *
1447
- * **When to use**
1448
- *
1449
- * Use when you need a `Predicate` guard to narrow an `unknown` value to a
1450
- * callable function.
1451
- *
1452
- * **Details**
1453
- *
1454
- * Uses `typeof input === "function"`.
1455
- *
1456
- * **Example** (Guarding functions)
1457
- *
1458
- * ```ts
1459
- * import { Predicate } from "effect"
1460
- *
1461
- * const data: unknown = () => 1
1462
- *
1463
- * if (Predicate.isFunction(data)) {
1464
- * data() // => 1
1465
- * }
1466
- * ```
1467
- *
1468
- * @see {@link isObjectKeyword}
1469
- * @category guards
1470
- * @since 2.0.0
1471
- */
1472
- function isFunction(input) {
1473
- return typeof input === "function";
1474
- }
1475
- /**
1476
- * Checks whether a value is an `object` in the JavaScript sense (objects, arrays, functions).
1477
- *
1478
- * **When to use**
1479
- *
1480
- * Use when you need a `Predicate` guard that accepts arrays and functions as
1481
- * well as objects.
1482
- *
1483
- * **Details**
1484
- *
1485
- * Returns `true` for arrays and functions, and `false` for `null`.
1486
- *
1487
- * **Example** (Checking object keywords)
1488
- *
1489
- * ```ts
1490
- * import { Predicate } from "effect"
1491
- *
1492
- * Predicate.isObjectKeyword(() => 1) // => true
1493
- * Predicate.isObjectKeyword(null) // => false
1494
- * ```
1495
- *
1496
- * @see {@link isObject}
1497
- * @see {@link isObjectOrArray}
1498
- * @category guards
1499
- * @since 4.0.0
1500
- */
1501
- function isObjectKeyword(input) {
1502
- return typeof input === "object" && input !== null || isFunction(input);
1503
- }
1504
- /**
1505
- * Checks whether a value has a given property key.
1506
- *
1507
- * **When to use**
1508
- *
1509
- * Use when you need a `Predicate` guard for property access on `unknown`
1510
- * values with a simple structural object check.
1511
- *
1512
- * **Details**
1513
- *
1514
- * Uses the `in` operator and `isObjectKeyword`. This does not check property
1515
- * value types.
1516
- *
1517
- * **Example** (Guarding object properties)
1518
- *
1519
- * ```ts
1520
- * import { Predicate } from "effect"
1521
- *
1522
- * const hasName = Predicate.hasProperty("name")
1523
- * const data: unknown = { name: "Ada" }
1524
- *
1525
- * if (hasName(data)) {
1526
- * data.name // => "Ada"
1527
- * }
1528
- * ```
1529
- *
1530
- * @see {@link isTagged}
1531
- * @see {@link isObjectKeyword}
1532
- * @category guards
1533
- * @since 2.0.0
1534
- */
1535
- const hasProperty = dual(2, (data, property) => isObjectKeyword(data) && property in data);
1536
- /**
1537
- * Drops elements from the start while the predicate holds, returning the rest.
1538
- *
1539
- * **When to use**
1540
- *
1541
- * Use to remove a leading prefix of elements that satisfy a predicate.
1542
- *
1543
- * **Details**
1544
- *
1545
- * The predicate receives `(element, index)`.
1546
- *
1547
- * **Example** (Dropping while condition holds)
1548
- *
1549
- * ```ts
1550
- * import { Array } from "effect"
1551
- *
1552
- * Array.dropWhile([1, 2, 3, 4, 5], (x) => x < 4) // => [4, 5]
1553
- * ```
1554
- *
1555
- * @see {@link takeWhile} — keep the matching prefix instead
1556
- * @see {@link drop} — drop a fixed count
1557
- *
1558
- * @category getters
1559
- * @since 2.0.0
1560
- */
1561
- const dropWhile = dual(2, (self, predicate) => {
1562
- const input = Array.isArray(self) ? self : Array.from(self);
1563
- const len = input.length;
1564
- let idx = 0;
1565
- while (idx < len && predicate(input[idx], idx)) idx++;
1566
- return input.slice(idx);
1567
- });
1568
- /**
1569
- * Takes elements from the start while the predicate holds, stopping at the
1570
- * first element that fails.
1571
- *
1572
- * **When to use**
1573
- *
1574
- * Use to keep the leading elements of an iterable while each element satisfies
1575
- * a predicate, returning the retained prefix as an array.
1576
- *
1577
- * **Details**
1578
- *
1579
- * Supports refinements for type narrowing. The predicate receives
1580
- * `(element, index)`.
1581
- *
1582
- * **Example** (Taking while condition holds)
1583
- *
1584
- * ```ts
1585
- * import { Array } from "effect"
1586
- *
1587
- * Array.takeWhile([1, 3, 2, 4, 1, 2], (x) => x < 4) // => [1, 3, 2]
1588
- * ```
1589
- *
1590
- * @see {@link take} for keeping a fixed number of leading elements
1591
- * @see {@link dropWhile} for removing the matching prefix and keeping the rest
1592
- * @see {@link span} for splitting the matching prefix from the remaining elements
1593
- *
1594
- * @category getters
1595
- * @since 2.0.0
1596
- */
1597
- const takeWhile = dual(2, (self, predicate) => {
1598
- const input = Array.isArray(self) ? self : Array.from(self);
1599
- const len = input.length;
1600
- let idx = 0;
1601
- while (idx < len && predicate(input[idx], idx)) idx++;
1602
- return input.slice(0, idx);
1603
- });
1604
-
1605
583
  //#endregion
1606
584
  //#region src/hook.ts
1607
- /** The names of React's built-in hooks. */
1608
585
  const REACT_BUILTIN_HOOK_NAMES = [
1609
586
  "use",
1610
587
  "useActionState",
@@ -1626,55 +603,29 @@ const REACT_BUILTIN_HOOK_NAMES = [
1626
603
  "useSyncExternalStore",
1627
604
  "useTransition"
1628
605
  ];
1629
- /**
1630
- * Check if the name is a hook name (starts with `use` followed by an uppercase letter or digit).
1631
- * @param name The name of the identifier to check.
1632
- * @returns `true` if the name is a hook name.
1633
- * @see https://github.com/facebook/react/blob/1d6c8168db1d82713202e842df3167787ffa00ed/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts#L16
1634
- */
1635
606
  function isHookName(name) {
1636
607
  return name === "use" || /^use[A-Z0-9]/.test(name);
1637
608
  }
1638
- /**
1639
- * Checks if the given node is a hook identifier.
1640
- * @param id The AST node to check.
1641
- * @returns `true` if the node is a hook identifier or member expression with hook name, `false` otherwise.
1642
- */
1643
609
  function isHookId(id) {
1644
610
  switch (id.type) {
1645
611
  case AST_NODE_TYPES.Identifier: return isHookName(id.name);
1646
- case AST_NODE_TYPES.MemberExpression: return "name" in id.property && isHookName(id.property.name);
612
+ case AST_NODE_TYPES.MemberExpression: return hasProperty(id.property, "name") && isHookName(id.property.name);
1647
613
  default: return false;
1648
614
  }
1649
615
  }
1650
- /**
1651
- * Checks if the given expression is a hook tag (callee / tagged template tag).
1652
- * @param tag The expression node to check.
1653
- * @returns `true` if the expression is a hook identifier or member expression with hook name, `false` otherwise.
1654
- */
1655
616
  function isHookTag(tag) {
1656
617
  if (tag == null) return false;
1657
618
  return isHookId(Extract.unwrap(tag));
1658
619
  }
1659
- /**
1660
- * Check if the function node is a hook definition based on its name.
1661
- * @param node The function node to check.
1662
- * @returns `true` if the function is a hook definition.
1663
- */
1664
620
  function isHookDefinition(node) {
1665
621
  if (node == null) return false;
1666
622
  const id = getFunctionId(node);
1667
623
  switch (id?.type) {
1668
624
  case AST_NODE_TYPES.Identifier: return isHookName(id.name);
1669
- case AST_NODE_TYPES.MemberExpression: return "name" in id.property && isHookName(id.property.name);
625
+ case AST_NODE_TYPES.MemberExpression: return hasProperty(id.property, "name") && isHookName(id.property.name);
1670
626
  default: return false;
1671
627
  }
1672
628
  }
1673
- /**
1674
- * Check if the node is a React Hook call by its name.
1675
- * @param node The node to check.
1676
- * @returns `true` if the node is a React Hook call, `false` otherwise.
1677
- */
1678
629
  function isHookCall(node) {
1679
630
  if (node == null) return false;
1680
631
  if (node.type !== AST_NODE_TYPES.CallExpression) return false;
@@ -1682,12 +633,6 @@ function isHookCall(node) {
1682
633
  if (name == null) return false;
1683
634
  return isHookName(name);
1684
635
  }
1685
- /**
1686
- * Check if the node is a useRef-like call (ex: `useRef` or a custom ref hook).
1687
- * @param node The AST node to check.
1688
- * @param additionalRefHooks Regex pattern matching custom hooks that should be treated as ref hooks.
1689
- * @returns `true` if the node is a useRef-like call.
1690
- */
1691
636
  function isUseRefLikeCall(node, additionalRefHooks = { test: constFalse }) {
1692
637
  if (node == null) return false;
1693
638
  if (node.type !== AST_NODE_TYPES.CallExpression) return false;
@@ -1695,12 +640,6 @@ function isUseRefLikeCall(node, additionalRefHooks = { test: constFalse }) {
1695
640
  if (name == null) return false;
1696
641
  return name === "useRef" || additionalRefHooks.test(name);
1697
642
  }
1698
- /**
1699
- * Check if the node is a useState-like call (ex: `useState` or a custom state hook).
1700
- * @param node The AST node to check.
1701
- * @param additionalStateHooks Regex pattern matching custom hooks that should be treated as state hooks.
1702
- * @returns `true` if the node is a useState-like call.
1703
- */
1704
643
  function isUseStateLikeCall(node, additionalStateHooks = { test: constFalse }) {
1705
644
  if (node == null) return false;
1706
645
  if (node.type !== AST_NODE_TYPES.CallExpression) return false;
@@ -1708,12 +647,6 @@ function isUseStateLikeCall(node, additionalStateHooks = { test: constFalse }) {
1708
647
  if (name == null) return false;
1709
648
  return name === "useState" || additionalStateHooks.test(name);
1710
649
  }
1711
- /**
1712
- * Check if the node is a useEffect-like call (ex: `useEffect`, `useLayoutEffect`, or a custom effect hook).
1713
- * @param node The AST node to check.
1714
- * @param additionalEffectHooks Regex pattern matching custom hooks that should be treated as effect hooks.
1715
- * @returns `true` if the node is a useEffect-like call.
1716
- */
1717
650
  function isUseEffectLikeCall(node, additionalEffectHooks = { test: constFalse }) {
1718
651
  if (node == null) return false;
1719
652
  if (node.type !== AST_NODE_TYPES.CallExpression) return false;
@@ -1721,21 +654,11 @@ function isUseEffectLikeCall(node, additionalEffectHooks = { test: constFalse })
1721
654
  if (name == null) return false;
1722
655
  return /^use\w*Effect$/u.test(name) || additionalEffectHooks.test(name);
1723
656
  }
1724
- /**
1725
- * Check if the node is the setup callback passed to a useEffect-like call.
1726
- * @param node The AST node to check.
1727
- * @returns `true` if the node is a useEffect setup callback.
1728
- */
1729
657
  function isUseEffectSetupCallback(node) {
1730
658
  if (node == null) return false;
1731
659
  const expr = Extract.unwrap(node);
1732
660
  return expr.parent?.type === AST_NODE_TYPES.CallExpression && expr.parent.arguments.at(0) === expr && isUseEffectLikeCall(expr.parent);
1733
661
  }
1734
- /**
1735
- * Check if the node is the cleanup callback returned by a useEffect-like setup callback.
1736
- * @param node The AST node to check.
1737
- * @returns `true` if the node is a useEffect cleanup callback.
1738
- */
1739
662
  function isUseEffectCleanupCallback(node) {
1740
663
  if (node == null) return false;
1741
664
  const expr = Extract.unwrap(node);
@@ -1747,12 +670,6 @@ function isUseEffectCleanupCallback(node) {
1747
670
 
1748
671
  //#endregion
1749
672
  //#region src/function-component-collector.ts
1750
- /**
1751
- * Get an api and visitor object for the rule to collect function components.
1752
- * @param context The ESLint rule context.
1753
- * @param options The options to use.
1754
- * @returns The api and visitor of the collector.
1755
- */
1756
673
  function getFunctionComponentCollector(context, options = {}) {
1757
674
  const { collectDisplayName = false, hint = DEFAULT_COMPONENT_DETECTION_HINT } = options;
1758
675
  const functionEntries = [];
@@ -1848,11 +765,6 @@ function getFunctionComponentCollector(context, options = {}) {
1848
765
 
1849
766
  //#endregion
1850
767
  //#region src/hook-collector.ts
1851
- /**
1852
- * Get an api and visitor object for the rule to collect hooks.
1853
- * @param context The ESLint rule context.
1854
- * @returns The api and visitor of the collector.
1855
- */
1856
768
  function getHookCollector(context) {
1857
769
  const functionEntries = [];
1858
770
  const hooks = /* @__PURE__ */ new Map();
@@ -1918,25 +830,8 @@ function getHookCollector(context) {
1918
830
 
1919
831
  //#endregion
1920
832
  //#region src/jsx-config.ts
1921
- /**
1922
- * Weak‑map cache keyed by `sourceCode` so that the (potentially expensive)
1923
- * pragma‑scanning pass runs at most once per file.
1924
- */
1925
833
  const annotationCache = /* @__PURE__ */ new WeakMap();
1926
- /**
1927
- * Weak‑map cache for the fully‑merged config (compiler options + annotation).
1928
- */
1929
834
  const mergedCache = /* @__PURE__ */ new WeakMap();
1930
- /**
1931
- * Read JSX configuration from the TypeScript compiler options exposed by the
1932
- * parser services.
1933
- *
1934
- * Falls back to sensible React defaults when no compiler options are
1935
- * available (e.g. when the file is parsed without type information).
1936
- *
1937
- * @param context The ESLint rule context.
1938
- * @returns Fully‑populated `JsxConfig` derived from compiler options.
1939
- */
1940
835
  function getJsxConfigFromCompilerOptions(context) {
1941
836
  const options = context.sourceCode.parserServices?.program?.getCompilerOptions() ?? {};
1942
837
  return {
@@ -1946,16 +841,6 @@ function getJsxConfigFromCompilerOptions(context) {
1946
841
  jsxImportSource: options.jsxImportSource ?? "react"
1947
842
  };
1948
843
  }
1949
- /**
1950
- * Extract JSX configuration from `@jsx`, `@jsxFrag`, `@jsxRuntime` and
1951
- * `@jsxImportSource` pragma comments in the source file.
1952
- *
1953
- * The result is cached per `sourceCode` instance via a `WeakMap` so that
1954
- * repeated calls from different rules analysing the same file are free.
1955
- *
1956
- * @param context The ESLint rule context.
1957
- * @returns Partial `JsxConfig` containing only the values found in pragmas.
1958
- */
1959
844
  function getJsxConfigFromAnnotation(context) {
1960
845
  const cached = annotationCache.get(context.sourceCode);
1961
846
  if (cached != null) return cached;
@@ -1979,17 +864,6 @@ function getJsxConfigFromAnnotation(context) {
1979
864
  annotationCache.set(context.sourceCode, options);
1980
865
  return options;
1981
866
  }
1982
- /**
1983
- * Get the fully‑merged JSX configuration for the current file.
1984
- *
1985
- * Compiler options provide the base values; pragma annotations found in the
1986
- * source override them where present. The result is cached per `sourceCode`.
1987
- *
1988
- * This is the main entry‑point most consumers should use.
1989
- *
1990
- * @param context The ESLint rule context.
1991
- * @returns Fully‑populated, merged `JsxConfig`.
1992
- */
1993
867
  function getJsxConfig(context) {
1994
868
  const cached = mergedCache.get(context.sourceCode);
1995
869
  if (cached != null) return cached;
@@ -2010,113 +884,30 @@ function isFlagSetOnObject(obj, flag) {
2010
884
  return isFlagSet(obj.flags, flag);
2011
885
  }
2012
886
  const isTypeFlagSet = isFlagSetOnObject;
2013
- /**
2014
- * Check if the type is a boolean literal type.
2015
- * @param type The type to check.
2016
- * @returns `true` if the type is a boolean literal type.
2017
- */
2018
887
  function isBooleanLiteralType(type) {
2019
888
  return isTypeFlagSet(type, ts.TypeFlags.BooleanLiteral);
2020
889
  }
2021
- /**
2022
- * Check if the type is the `false` literal type.
2023
- * @internal
2024
- */
2025
890
  const isFalseLiteralType = (type) => isBooleanLiteralType(type) && type.intrinsicName === "false";
2026
- /**
2027
- * Check if the type is the `true` literal type.
2028
- * @internal
2029
- */
2030
891
  const isTrueLiteralType = (type) => isBooleanLiteralType(type) && type.intrinsicName === "true";
2031
- /**
2032
- * Check if the type is an any-like type.
2033
- * @internal
2034
- */
2035
892
  const isAnyType = (type) => isTypeFlagSet(type, ts.TypeFlags.TypeParameter | ts.TypeFlags.Any);
2036
- /**
2037
- * Check if the type is a bigint-like type.
2038
- * @internal
2039
- */
2040
893
  const isBigIntType = (type) => isTypeFlagSet(type, ts.TypeFlags.BigIntLike);
2041
- /**
2042
- * Check if the type is a boolean-like type.
2043
- * @internal
2044
- */
2045
894
  const isBooleanType = (type) => isTypeFlagSet(type, ts.TypeFlags.BooleanLike);
2046
- /**
2047
- * Check if the type is an enum-like type.
2048
- * @internal
2049
- */
2050
895
  const isEnumType = (type) => isTypeFlagSet(type, ts.TypeFlags.EnumLike);
2051
- /**
2052
- * Check if the type is a falsy bigint literal type.
2053
- * @internal
2054
- */
2055
896
  const isFalsyBigIntType = (type) => type.isLiteral() && isMatching({ value: { base10Value: "0" } }, type);
2056
- /**
2057
- * Check if the type is a falsy number literal type.
2058
- * @internal
2059
- */
2060
897
  const isFalsyNumberType = (type) => type.isNumberLiteral() && type.value === 0;
2061
- /**
2062
- * Check if the type is a falsy string literal type.
2063
- * @internal
2064
- */
2065
898
  const isFalsyStringType = (type) => type.isStringLiteral() && type.value === "";
2066
- /**
2067
- * Check if the type is the never type.
2068
- * @internal
2069
- */
2070
899
  const isNeverType = (type) => isTypeFlagSet(type, ts.TypeFlags.Never);
2071
- /**
2072
- * Check if the type is a nullish type (null, undefined, or void).
2073
- * @internal
2074
- */
2075
900
  const isNullishType = (type) => isTypeFlagSet(type, ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.VoidLike);
2076
- /**
2077
- * Check if the type is a number-like type.
2078
- * @internal
2079
- */
2080
901
  const isNumberType = (type) => isTypeFlagSet(type, ts.TypeFlags.NumberLike);
2081
- /**
2082
- * Check if the type is an object type.
2083
- * @internal
2084
- */
2085
902
  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);
2086
- /**
2087
- * Check if the type is a string-like type.
2088
- * @internal
2089
- */
2090
903
  const isStringType = (type) => isTypeFlagSet(type, ts.TypeFlags.StringLike);
2091
- /**
2092
- * Check if the type is a truthy bigint literal type.
2093
- * @internal
2094
- */
2095
904
  const isTruthyBigIntType = (type) => type.isLiteral() && isMatching({ value: { base10Value: P.not("0") } }, type);
2096
- /**
2097
- * Check if the type is a truthy number literal type.
2098
- * @internal
2099
- */
2100
905
  const isTruthyNumberType = (type) => type.isNumberLiteral() && type.value !== 0;
2101
- /**
2102
- * Check if the type is a truthy string literal type.
2103
- * @internal
2104
- */
2105
906
  const isTruthyStringType = (type) => type.isStringLiteral() && type.value !== "";
2106
- /**
2107
- * Check if the type is the unknown type.
2108
- * @internal
2109
- */
2110
907
  const isUnknownType = (type) => isTypeFlagSet(type, ts.TypeFlags.Unknown);
2111
908
 
2112
909
  //#endregion
2113
910
  //#region src/type-name.ts
2114
- /**
2115
- * Get the fully qualified name of a symbol, handling cases that `ts.TypeChecker.getFullyQualifiedName` does not handle (ex: `export as namespace preact`).
2116
- * @param checker The TypeScript type checker.
2117
- * @param symbol The symbol to get fully qualified name for.
2118
- * @returns The fully qualified name of the symbol.
2119
- */
2120
911
  function getFullyQualifiedNameEx(checker, symbol) {
2121
912
  let name = symbol.name;
2122
913
  let parent = symbol.declarations?.at(0)?.parent;
@@ -2163,13 +954,6 @@ function getFullyQualifiedNameEx(checker, symbol) {
2163
954
 
2164
955
  //#endregion
2165
956
  //#region src/type-variant.ts
2166
- /**
2167
- * Get the variants of an array of types.
2168
- * @param types The types to get the variants of.
2169
- * @returns The variants of the types.
2170
- * @remarks Ported from https://github.com/typescript-eslint/typescript-eslint/blob/eb736bbfc22554694400e6a4f97051d845d32e0b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts#L826 with some enhancements.
2171
- * @internal
2172
- */
2173
957
  function getTypeVariants(types) {
2174
958
  const variants = /* @__PURE__ */ new Set();
2175
959
  if (types.some(isUnknownType)) {