@eslint-react/core 5.18.4 → 5.18.6

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 +63 -2
  2. package/dist/index.js +843 -757
  3. package/package.json +12 -12
package/dist/index.js CHANGED
@@ -6,480 +6,6 @@ import { resolve } from "@eslint-react/var";
6
6
  import ts from "typescript";
7
7
  import { P, isMatching, match } from "ts-pattern";
8
8
 
9
- //#region ../../.pkgs/eff/dist/index.js
10
- /**
11
- * Applies a `pipe` method's variadic arguments to an initial value from left
12
- * to right.
13
- *
14
- * **When to use**
15
- *
16
- * Use to implement a custom `.pipe(...)` method from JavaScript's `arguments`
17
- * object.
18
- *
19
- * **Details**
20
- *
21
- * This helper is intended for implementing `Pipeable.pipe` methods that
22
- * receive JavaScript's `arguments` object. With no functions it returns the
23
- * original value; otherwise it feeds each result into the next function.
24
- *
25
- * **Example** (Implementing a pipe method)
26
- *
27
- * ```ts
28
- * import { Pipeable } from "effect"
29
- *
30
- * class NumberBox {
31
- * constructor(readonly value: number) {}
32
- *
33
- * pipe(..._fns: ReadonlyArray<(value: number) => number>): number {
34
- * return Pipeable.pipeArguments(this.value, arguments) as number
35
- * }
36
- * }
37
- *
38
- * const result = new NumberBox(5).pipe(
39
- * (n) => n + 2,
40
- * (n) => n * 3
41
- * )
42
- * console.log(result) // 21
43
- * ```
44
- *
45
- * @category combinators
46
- * @since 2.0.0
47
- */
48
- const pipeArguments = (self, args) => {
49
- switch (args.length) {
50
- case 0: return self;
51
- case 1: return args[0](self);
52
- case 2: return args[1](args[0](self));
53
- case 3: return args[2](args[1](args[0](self)));
54
- case 4: return args[3](args[2](args[1](args[0](self))));
55
- case 5: return args[4](args[3](args[2](args[1](args[0](self)))));
56
- case 6: return args[5](args[4](args[3](args[2](args[1](args[0](self))))));
57
- case 7: return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))));
58
- case 8: return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))));
59
- case 9: return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))));
60
- default: {
61
- let ret = self;
62
- for (let i = 0, len = args.length; i < len; i++) ret = args[i](ret);
63
- return ret;
64
- }
65
- }
66
- };
67
- /**
68
- * Reusable prototype that implements `Pipeable.pipe`.
69
- *
70
- * **When to use**
71
- *
72
- * Use when classes or object prototypes can reuse this value when they need the
73
- * standard pipe implementation backed by `pipeArguments`.
74
- *
75
- * @category prototypes
76
- * @since 3.15.0
77
- */
78
- const Prototype = { pipe() {
79
- return pipeArguments(this, arguments);
80
- } };
81
- /**
82
- * Provides a base constructor whose instances implement the standard `Pipeable.pipe`
83
- * method.
84
- *
85
- * **When to use**
86
- *
87
- * Use when you need to define a class that supports Effect-style method
88
- * chaining through `.pipe(...)`.
89
- *
90
- * @category constructors
91
- * @since 3.15.0
92
- */
93
- const Class = (function() {
94
- function PipeableBase() {}
95
- PipeableBase.prototype = Prototype;
96
- return PipeableBase;
97
- })();
98
- /**
99
- * Provides small helpers for defining and reusing TypeScript functions.
100
- *
101
- * The main helpers are `pipe` and `flow` for left-to-right composition and
102
- * `dual` for APIs that support both direct and pipe-friendly call styles. The
103
- * module also contains small identity, constant, tuple, type-level, and
104
- * memoization helpers used across the library.
105
- *
106
- * @since 2.0.0
107
- */
108
- /**
109
- * Creates a function that can be called in data-first style or data-last
110
- * (`pipe`-friendly) style.
111
- *
112
- * **When to use**
113
- *
114
- * Use to expose one implementation through both direct and `pipe`-friendly
115
- * call styles.
116
- *
117
- * **Details**
118
- *
119
- * Pass either the arity of the uncurried function or a predicate that decides
120
- * whether the current call is data-first. Arity is the common case. Use a
121
- * predicate when optional arguments make arity ambiguous.
122
- *
123
- * **Example** (Selecting data-first or data-last style by arity)
124
- *
125
- * ```ts
126
- * import { Function, pipe } from "effect"
127
- *
128
- * const sum = Function.dual<
129
- * (that: number) => (self: number) => number,
130
- * (self: number, that: number) => number
131
- * >(2, (self, that) => self + that)
132
- *
133
- * console.log(sum(2, 3)) // 5
134
- * console.log(pipe(2, sum(3))) // 5
135
- * ```
136
- *
137
- * **Example** (Defining overloads with call signatures)
138
- *
139
- * ```ts
140
- * import { Function, pipe } from "effect"
141
- *
142
- * const sum: {
143
- * (that: number): (self: number) => number
144
- * (self: number, that: number): number
145
- * } = Function.dual(2, (self: number, that: number): number => self + that)
146
- *
147
- * console.log(sum(2, 3)) // 5
148
- * console.log(pipe(2, sum(3))) // 5
149
- * ```
150
- *
151
- * **Example** (Selecting data-first or data-last style with a predicate)
152
- *
153
- * ```ts
154
- * import { Function, pipe } from "effect"
155
- *
156
- * const sum = Function.dual<
157
- * (that: number) => (self: number) => number,
158
- * (self: number, that: number) => number
159
- * >(
160
- * (args) => args.length === 2,
161
- * (self, that) => self + that
162
- * )
163
- *
164
- * console.log(sum(2, 3)) // 5
165
- * console.log(pipe(2, sum(3))) // 5
166
- * ```
167
- *
168
- * @category combinators
169
- * @since 2.0.0
170
- */
171
- const dual = function(arity, body) {
172
- if (typeof arity === "function") return function() {
173
- return arity(arguments) ? body.apply(this, arguments) : ((self) => body(self, ...arguments));
174
- };
175
- switch (arity) {
176
- case 0:
177
- case 1: throw new RangeError(`Invalid arity ${arity}`);
178
- case 2: return function(a, b) {
179
- if (arguments.length >= 2) return body(a, b);
180
- return function(self) {
181
- return body(self, a);
182
- };
183
- };
184
- case 3: return function(a, b, c) {
185
- if (arguments.length >= 3) return body(a, b, c);
186
- return function(self) {
187
- return body(self, a, b);
188
- };
189
- };
190
- default: return function() {
191
- if (arguments.length >= arity) return body.apply(this, arguments);
192
- const args = arguments;
193
- return function(self) {
194
- return body(self, ...args);
195
- };
196
- };
197
- }
198
- };
199
- /**
200
- * Returns its input argument unchanged.
201
- *
202
- * **When to use**
203
- *
204
- * Use to return a value unchanged where a function is required.
205
- *
206
- * **Example** (Returning the same value)
207
- *
208
- * ```ts
209
- * import { identity } from "effect"
210
- * import * as assert from "node:assert"
211
- *
212
- * assert.deepStrictEqual(identity(5), 5)
213
- * ```
214
- *
215
- * @category combinators
216
- * @since 2.0.0
217
- */
218
- const identity = (a) => a;
219
- /**
220
- * Returns the input value with a different static type.
221
- *
222
- * **When to use**
223
- *
224
- * Use when you need an explicit type-level cast and accept that the value is
225
- * returned unchanged at runtime.
226
- *
227
- * **Gotchas**
228
- *
229
- * This is a type-level cast only; it performs no runtime validation or
230
- * conversion.
231
- *
232
- * @see {@link satisfies} for checking assignability without changing the resulting type
233
- *
234
- * @category utility types
235
- * @since 4.0.0
236
- */
237
- const cast = identity;
238
- /**
239
- * Creates a zero-argument function that always returns the provided value.
240
- *
241
- * **When to use**
242
- *
243
- * Use when you need a thunk or callback that returns the same value on every
244
- * invocation.
245
- *
246
- * **Example** (Creating a constant thunk)
247
- *
248
- * ```ts
249
- * import { Function } from "effect"
250
- * import * as assert from "node:assert"
251
- *
252
- * const constNull = Function.constant(null)
253
- *
254
- * assert.deepStrictEqual(constNull(), null)
255
- * assert.deepStrictEqual(constNull(), null)
256
- * ```
257
- *
258
- * @category constructors
259
- * @since 2.0.0
260
- */
261
- const constant = (value) => () => value;
262
- /**
263
- * Returns `true` when called.
264
- *
265
- * **When to use**
266
- *
267
- * Use when you need a thunk that returns `true` on every invocation.
268
- *
269
- * **Example** (Returning true from a thunk)
270
- *
271
- * ```ts
272
- * import { Function } from "effect"
273
- * import * as assert from "node:assert"
274
- *
275
- * assert.deepStrictEqual(Function.constTrue(), true)
276
- * ```
277
- *
278
- * @category constants
279
- * @since 2.0.0
280
- */
281
- const constTrue = constant(true);
282
- /**
283
- * Returns `false` when called.
284
- *
285
- * **When to use**
286
- *
287
- * Use when you need a thunk that returns `false` on every invocation.
288
- *
289
- * **Example** (Returning false from a thunk)
290
- *
291
- * ```ts
292
- * import { Function } from "effect"
293
- * import * as assert from "node:assert"
294
- *
295
- * assert.deepStrictEqual(Function.constFalse(), false)
296
- * ```
297
- *
298
- * @category constants
299
- * @since 2.0.0
300
- */
301
- const constFalse = constant(false);
302
- /**
303
- * Returns `null` when called.
304
- *
305
- * **When to use**
306
- *
307
- * Use when you need a thunk that returns `null` on every invocation.
308
- *
309
- * **Example** (Returning null from a thunk)
310
- *
311
- * ```ts
312
- * import { Function } from "effect"
313
- * import * as assert from "node:assert"
314
- *
315
- * assert.deepStrictEqual(Function.constNull(), null)
316
- * ```
317
- *
318
- * @category constants
319
- * @since 2.0.0
320
- */
321
- const constNull = constant(null);
322
- /**
323
- * Returns `undefined` when called.
324
- *
325
- * **When to use**
326
- *
327
- * Use when you need a thunk that returns `undefined` on every invocation.
328
- *
329
- * **Example** (Returning undefined from a thunk)
330
- *
331
- * ```ts
332
- * import { Function } from "effect"
333
- * import * as assert from "node:assert"
334
- *
335
- * assert.deepStrictEqual(Function.constUndefined(), undefined)
336
- * ```
337
- *
338
- * @category constants
339
- * @since 2.0.0
340
- */
341
- const constUndefined = constant(void 0);
342
- /**
343
- * 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`.
344
- * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`.
345
- *
346
- * **When to use**
347
- *
348
- * Use to compose exactly two unary functions into a reusable unary function.
349
- *
350
- * **Example** (Composing two functions)
351
- *
352
- * ```ts
353
- * import { Function } from "effect"
354
- * import * as assert from "node:assert"
355
- *
356
- * const increment = (n: number) => n + 1
357
- * const square = (n: number) => n * n
358
- *
359
- * assert.strictEqual(Function.compose(increment, square)(2), 9)
360
- * ```
361
- *
362
- * @see {@link flow} for composing a left-to-right sequence of functions
363
- * @see {@link pipe} for applying a value through a left-to-right sequence immediately
364
- *
365
- * @category combinators
366
- * @since 2.0.0
367
- */
368
- const compose = dual(2, (ab, bc) => (a) => bc(ab(a)));
369
- /**
370
- * Marks an impossible branch by accepting a `never` value and returning any
371
- * type.
372
- *
373
- * **When to use**
374
- *
375
- * Use when you need a return value in a branch that exhaustive checks prove
376
- * cannot be reached.
377
- *
378
- * **Gotchas**
379
- *
380
- * Calling `absurd` throws, because a value of type `never` should be
381
- * impossible at runtime.
382
- *
383
- * **Example** (Handling impossible values)
384
- *
385
- * ```ts
386
- * import { absurd } from "effect"
387
- *
388
- * const handleNever = (value: never) => {
389
- * return absurd(value) // This will throw an error if called
390
- * }
391
- * ```
392
- *
393
- * @category utility types
394
- * @since 2.0.0
395
- */
396
- const absurd = (_) => {
397
- throw new Error("Called `absurd` function which should be uncallable");
398
- };
399
- /**
400
- * Creates a compile-time placeholder for a value of any type.
401
- *
402
- * **When to use**
403
- *
404
- * Use as a temporary typed placeholder while developing incomplete code.
405
- *
406
- * **Gotchas**
407
- *
408
- * `hole` is intended for temporary development use. If the placeholder is
409
- * evaluated at runtime, it throws.
410
- *
411
- * **Example** (Creating a development placeholder)
412
- *
413
- * ```ts
414
- * import { hole } from "effect"
415
- *
416
- * // Intentionally not called: `hole` throws if the placeholder is evaluated.
417
- * const buildUser = (id: number): { readonly id: number; readonly name: string } => ({
418
- * id,
419
- * name: hole<string>()
420
- * })
421
- *
422
- * console.log(typeof buildUser) // "function"
423
- * ```
424
- *
425
- * @category utility types
426
- * @since 2.0.0
427
- */
428
- const hole = cast(absurd);
429
- /**
430
- * Drops the longest prefix of elements from an array that satisfy the given predicate.
431
- *
432
- * Supports both data-first and data-last (`pipe`-friendly) call styles.
433
- *
434
- * @param pred - The predicate to test each element with.
435
- * @returns A new array without the matching prefix.
436
- * @example
437
- * ```ts
438
- * import * as assert from "node:assert"
439
- * import { dropWhile, pipe } from "@local/eff"
440
- *
441
- * // data-first
442
- * assert.deepStrictEqual(dropWhile([1, 2, 3, 2, 1], (n: number) => n < 3), [3, 2, 1])
443
- *
444
- * // data-last
445
- * assert.deepStrictEqual(pipe([1, 2, 3, 2, 1], dropWhile((n: number) => n < 3)), [3, 2, 1])
446
- * ```
447
- * @category array
448
- */
449
- const dropWhile = dual(2, (xs, pred) => {
450
- const len = xs.length;
451
- let idx = 0;
452
- while (idx < len && pred(xs[idx])) idx++;
453
- return xs.slice(idx);
454
- });
455
- /**
456
- * Takes the longest prefix of elements from an array that satisfy the given predicate.
457
- *
458
- * Supports both data-first and data-last (`pipe`-friendly) call styles.
459
- *
460
- * @param pred - The predicate to test each element with.
461
- * @returns A new array containing only the matching prefix.
462
- * @example
463
- * ```ts
464
- * import * as assert from "node:assert"
465
- * import { pipe, takeWhile } from "@local/eff"
466
- *
467
- * // data-first
468
- * assert.deepStrictEqual(takeWhile([1, 2, 3, 2, 1], (n: number) => n < 3), [1, 2])
469
- *
470
- * // data-last
471
- * assert.deepStrictEqual(pipe([1, 2, 3, 2, 1], takeWhile((n: number) => n < 3)), [1, 2])
472
- * ```
473
- * @category array
474
- */
475
- const takeWhile = dual(2, (xs, pred) => {
476
- const len = xs.length;
477
- let idx = 0;
478
- while (idx < len && pred(xs[idx])) idx++;
479
- return xs.slice(0, idx);
480
- });
481
-
482
- //#endregion
483
9
  //#region src/api.ts
484
10
  /**
485
11
  * Check if the node is a React API identifier or member expression.
@@ -496,7 +22,10 @@ function isAPI(api) {
496
22
  if (name.endsWith(`.${api}`)) return true;
497
23
  return false;
498
24
  };
499
- return dual(2, func);
25
+ function dual(context, ...rest) {
26
+ return rest.length === 1 ? func(context, rest[0]) : (node) => func(context, node);
27
+ }
28
+ return dual;
500
29
  }
501
30
  /**
502
31
  * Check if the node is a call expression to a specific React API.
@@ -509,7 +38,10 @@ function isAPICall(api) {
509
38
  if (node.type !== AST_NODE_TYPES.CallExpression) return false;
510
39
  return isAPI(api)(context, Extract.unwrap(node.callee));
511
40
  };
512
- return dual(2, func);
41
+ function dual(context, ...rest) {
42
+ return rest.length === 1 ? func(context, rest[0]) : (node) => func(context, node);
43
+ }
44
+ return dual;
513
45
  }
514
46
  /** Check if the node is a React `captureOwnerStack` API identifier or member expression. */
515
47
  const isCaptureOwnerStack = isAPI("captureOwnerStack");
@@ -810,6 +342,95 @@ function getClassComponentCollector(context) {
810
342
  };
811
343
  }
812
344
 
345
+ //#endregion
346
+ //#region src/create-element.ts
347
+ /**
348
+ * Get the type argument (the first argument) of a `createElement` call.
349
+ * @param context The ESLint rule context.
350
+ * @param node The node to inspect.
351
+ * @returns The type argument, or `null` when the node is not a `createElement` call or has no arguments.
352
+ */
353
+ function getCreateElementTypeArgument(context, node) {
354
+ if (!isCreateElementCall(context, node)) return null;
355
+ return node.arguments[0] ?? null;
356
+ }
357
+ /**
358
+ * Get the props object (the second argument) of a `createElement` call.
359
+ *
360
+ * Type expressions and chain expressions wrapping the argument are unwrapped
361
+ * before the object check; `null`, spread, or otherwise non-object props
362
+ * arguments yield `null`.
363
+ *
364
+ * @param context The ESLint rule context.
365
+ * @param node The node to inspect.
366
+ * @returns The props `ObjectExpression`, or `null` when absent or not statically an object literal.
367
+ */
368
+ function getCreateElementPropsObject(context, node) {
369
+ if (!isCreateElementCall(context, node)) return null;
370
+ const propsArg = node.arguments[1];
371
+ if (propsArg == null) return null;
372
+ const propsObject = Extract.unwrap(propsArg);
373
+ return propsObject.type === AST_NODE_TYPES.ObjectExpression ? propsObject : null;
374
+ }
375
+ /**
376
+ * Get the children arguments (the arguments after the props object) of a `createElement` call.
377
+ * @param context The ESLint rule context.
378
+ * @param node The node to inspect.
379
+ * @returns The children arguments, or an empty array when the node is not a `createElement` call.
380
+ */
381
+ function getCreateElementChildrenArguments(context, node) {
382
+ if (!isCreateElementCall(context, node)) return [];
383
+ return node.arguments.slice(2);
384
+ }
385
+ /**
386
+ * Find a statically named property in the props object of a `createElement` call.
387
+ *
388
+ * Statically resolvable names include plain identifier keys as well as
389
+ * string-literal and simple template-literal keys (computed or not).
390
+ * @param context The ESLint rule context.
391
+ * @param node The node to inspect.
392
+ * @param name The property name to look for (ex: `"children"`, `"key"`).
393
+ * @returns The matching `Property` node, or `null` when the call has no static property with that name.
394
+ *
395
+ * @example
396
+ * ```ts
397
+ * import { getCreateElementProp } from "@eslint-react/core";
398
+ *
399
+ * const childrenProp = getCreateElementProp(context, node, "children");
400
+ * ```
401
+ */
402
+ function getCreateElementProp(context, node, name) {
403
+ const propsObject = getCreateElementPropsObject(context, node);
404
+ if (propsObject == null) return null;
405
+ for (const prop of propsObject.properties) if (prop.type === AST_NODE_TYPES.Property && Extract.getPropertyName(prop, "max") === name) return prop;
406
+ return null;
407
+ }
408
+ /**
409
+ * Check if the node is passed as a children argument (the third argument or
410
+ * later) of a `createElement` call.
411
+ * @param context The ESLint rule context.
412
+ * @param node The node to check.
413
+ * @returns `true` if the node is a direct children argument of a `createElement` call.
414
+ */
415
+ function isCreateElementChildrenArgument(context, node) {
416
+ let parent = node.parent;
417
+ while (Check.isTypeExpression(parent)) parent = parent.parent;
418
+ return parent?.type === AST_NODE_TYPES.CallExpression && isCreateElementCall(context, parent) && parent.arguments.slice(2).some((arg) => Extract.unwrap(arg) === node);
419
+ }
420
+ /**
421
+ * Check if the node is inside the props object (the second argument) of a `createElement` call.
422
+ * @param context The ESLint rule context.
423
+ * @param node The node to check.
424
+ * @returns `true` if the node is inside `createElement`'s props object.
425
+ */
426
+ function isInsideCreateElementProps(context, node) {
427
+ const call = Traverse.findParent(node, isCreateElementCall(context));
428
+ if (call == null) return false;
429
+ const prop = Traverse.findParent(node, Check.is(AST_NODE_TYPES.ObjectExpression));
430
+ if (prop == null) return false;
431
+ return prop === call.arguments[1];
432
+ }
433
+
813
434
  //#endregion
814
435
  //#region src/function.ts
815
436
  /**
@@ -907,335 +528,800 @@ function isFunctionHasCallInInitPath(callName, initPath) {
907
528
  });
908
529
  }
909
530
  /**
910
- * Check if a function is empty.
911
- *
912
- * @param node The function node to check.
913
- * @returns `true` if the function is empty, `false` otherwise.
531
+ * Check if a function is empty.
532
+ *
533
+ * @param node The function node to check.
534
+ * @returns `true` if the function is empty, `false` otherwise.
535
+ */
536
+ function isFunctionEmpty(node) {
537
+ return node.body.type === AST_NODE_TYPES.BlockStatement && node.body.body.length === 0;
538
+ }
539
+ /**
540
+ * Get the directives of a function (ex: "use strict", "use client", "use server").
541
+ * @param node The function node to get the directives from.
542
+ * @returns The directives of the function.
543
+ */
544
+ function getFunctionDirectives(node) {
545
+ const directives = [];
546
+ if (node.body.type !== AST_NODE_TYPES.BlockStatement) return directives;
547
+ function isDirective(node) {
548
+ return node.type === AST_NODE_TYPES.ExpressionStatement && node.directive != null;
549
+ }
550
+ for (const stmt of node.body.body) {
551
+ if (!isDirective(stmt)) continue;
552
+ directives.push(stmt);
553
+ }
554
+ return directives;
555
+ }
556
+ /**
557
+ * Check if a directive with the given name exists in the function directives.
558
+ *
559
+ * @param node The function AST node.
560
+ * @param name The directive name to check (e.g., "use memo", "use no memo").
561
+ * @returns `true` if the directive exists, `false` otherwise.
562
+ */
563
+ function isFunctionHasDirective(node, name) {
564
+ return getFunctionDirectives(node).some((d) => d.directive === name);
565
+ }
566
+ /** The esquery selector matching `displayName` assignment expressions. */
567
+ const SEL_FUNCTION_DISPLAY_NAME_ASSIGNMENT = [
568
+ "AssignmentExpression",
569
+ "[operator='=']",
570
+ "[left.type='MemberExpression']",
571
+ "[left.property.name='displayName']"
572
+ ].join("");
573
+
574
+ //#endregion
575
+ //#region src/jsx.ts
576
+ /**
577
+ * Hints for JSX detection.
578
+ */
579
+ const JsxDetectionHint = {
580
+ /** No hints set. */
581
+ None: 0n,
582
+ /** Do not treat `null` values as JSX-like. */
583
+ DoNotIncludeJsxWithNullValue: 1n << 0n,
584
+ /** Do not treat number values as JSX-like. */
585
+ DoNotIncludeJsxWithNumberValue: 1n << 1n,
586
+ /** Do not treat bigint values as JSX-like. */
587
+ DoNotIncludeJsxWithBigIntValue: 1n << 2n,
588
+ /** Do not treat string values as JSX-like. */
589
+ DoNotIncludeJsxWithStringValue: 1n << 3n,
590
+ /** Do not treat boolean values as JSX-like. */
591
+ DoNotIncludeJsxWithBooleanValue: 1n << 4n,
592
+ /** Do not treat undefined values as JSX-like. */
593
+ DoNotIncludeJsxWithUndefinedValue: 1n << 5n,
594
+ /** Do not treat empty array values as JSX-like. */
595
+ DoNotIncludeJsxWithEmptyArrayValue: 1n << 6n,
596
+ /** Do not treat `createElement` calls as JSX-like. */
597
+ DoNotIncludeJsxWithCreateElementValue: 1n << 7n,
598
+ /** Require all array elements to be JSX-like for the array to be JSX-like. */
599
+ RequireAllArrayElementsToBeJsx: 1n << 8n,
600
+ /** Require both sides of a logical expression to be JSX-like. */
601
+ RequireBothSidesOfLogicalExpressionToBeJsx: 1n << 9n,
602
+ /** Require both branches of a conditional expression to be JSX-like. */
603
+ RequireBothBranchesOfConditionalExpressionToBeJsx: 1n << 10n
604
+ };
605
+ /**
606
+ * Default JSX detection hint.
607
+ *
608
+ * Skips number, bigint, boolean, string, and undefined literals,
609
+ * the value types that are commonly returned alongside JSX in React
610
+ * components but are not themselves renderable elements.
611
+ */
612
+ const DEFAULT_JSX_DETECTION_HINT = 0n | JsxDetectionHint.DoNotIncludeJsxWithNumberValue | JsxDetectionHint.DoNotIncludeJsxWithBigIntValue | JsxDetectionHint.DoNotIncludeJsxWithBooleanValue | JsxDetectionHint.DoNotIncludeJsxWithStringValue | JsxDetectionHint.DoNotIncludeJsxWithUndefinedValue;
613
+ /**
614
+ * Check if the node represents JSX-like content based on heuristics.
615
+ *
616
+ * The detection behavior is configurable through {@link JsxDetectionHint}
617
+ * bit-flags so that callers can opt individual value kinds in or out.
618
+ *
619
+ * Identifiers are resolved to their definitions via scope analysis;
620
+ * circular definitions (e.g. `var a = b; var b = a;`) are detected and
621
+ * treated as not JSX-like instead of recursing indefinitely.
622
+ *
623
+ * @param context The ESLint rule context (needed for variable resolution).
624
+ * @param node The AST node to analyze.
625
+ * @param hint Optional bit-flags to adjust detection behavior. Defaults to {@link DEFAULT_JSX_DETECTION_HINT}.
626
+ * @returns Whether the node is considered JSX-like.
627
+ *
628
+ * @example
629
+ * ```ts
630
+ * import { isJsxLike } from "@eslint-react/core";
631
+ *
632
+ * if (isJsxLike(context, node)) {
633
+ * // node looks like it evaluates to a React element
634
+ * }
635
+ * ```
636
+ */
637
+ function isJsxLike(context, node, hint = DEFAULT_JSX_DETECTION_HINT) {
638
+ const seen = /* @__PURE__ */ new Set();
639
+ function visit(node) {
640
+ if (node == null) return false;
641
+ if (Check.isJSX(node)) return true;
642
+ switch (node.type) {
643
+ case AST_NODE_TYPES.Literal:
644
+ switch (typeof node.value) {
645
+ case "boolean": return !(hint & JsxDetectionHint.DoNotIncludeJsxWithBooleanValue);
646
+ case "string": return !(hint & JsxDetectionHint.DoNotIncludeJsxWithStringValue);
647
+ case "number": return !(hint & JsxDetectionHint.DoNotIncludeJsxWithNumberValue);
648
+ case "bigint": return !(hint & JsxDetectionHint.DoNotIncludeJsxWithBigIntValue);
649
+ }
650
+ return node.value == null && !(hint & JsxDetectionHint.DoNotIncludeJsxWithNullValue);
651
+ case AST_NODE_TYPES.TemplateLiteral: return !(hint & JsxDetectionHint.DoNotIncludeJsxWithStringValue);
652
+ case AST_NODE_TYPES.ArrayExpression:
653
+ if (node.elements.length === 0) return !(hint & JsxDetectionHint.DoNotIncludeJsxWithEmptyArrayValue);
654
+ return hint & JsxDetectionHint.RequireAllArrayElementsToBeJsx ? node.elements.every(visit) : node.elements.some(visit);
655
+ case AST_NODE_TYPES.LogicalExpression:
656
+ if (hint & JsxDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx) return visit(node.left) && visit(node.right);
657
+ return visit(node.left) || visit(node.right);
658
+ case AST_NODE_TYPES.ConditionalExpression:
659
+ if (hint & JsxDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx) return visit(node.consequent) && visit(node.alternate);
660
+ return visit(node.consequent) || visit(node.alternate);
661
+ case AST_NODE_TYPES.SequenceExpression: return visit(node.expressions.at(-1) ?? null);
662
+ case AST_NODE_TYPES.CallExpression:
663
+ if (hint & JsxDetectionHint.DoNotIncludeJsxWithCreateElementValue) return false;
664
+ return Extract.getCalleeName(node) === "createElement";
665
+ case AST_NODE_TYPES.Identifier:
666
+ if (node.name === "undefined") return !(hint & JsxDetectionHint.DoNotIncludeJsxWithUndefinedValue);
667
+ if (seen.has(node)) return false;
668
+ seen.add(node);
669
+ return visit(resolve(context, node));
670
+ }
671
+ return false;
672
+ }
673
+ return visit(node);
674
+ }
675
+
676
+ //#endregion
677
+ //#region src/function-component.ts
678
+ /**
679
+ * Component flag constants.
680
+ */
681
+ const FunctionComponentFlag = {
682
+ /** No flags set. */
683
+ None: 0n,
684
+ /** Indicates the component is a pure component (ex: extends PureComponent). */
685
+ PureComponent: 1n << 0n,
686
+ /** Indicates the component creates elements using `createElement` instead of JSX. */
687
+ CreateElement: 1n << 1n,
688
+ /** Indicates the component is memoized (ex: React.memo). */
689
+ Memo: 1n << 2n,
690
+ /** Indicates the component forwards a ref (ex: React.forwardRef). */
691
+ ForwardRef: 1n << 3n
692
+ };
693
+ /**
694
+ * Get component flag from init path.
695
+ * @param initPath The init path of the function component.
696
+ * @returns The component flag.
697
+ * @internal
698
+ */
699
+ function getFunctionComponentFlagFromInitPath(initPath) {
700
+ let flag = FunctionComponentFlag.None;
701
+ if (initPath != null && isFunctionHasCallInInitPath("memo", initPath)) flag |= FunctionComponentFlag.Memo;
702
+ if (initPath != null && isFunctionHasCallInInitPath("forwardRef", initPath)) flag |= FunctionComponentFlag.ForwardRef;
703
+ return flag;
704
+ }
705
+ /**
706
+ * Check if the node is a call expression for a component wrapper.
707
+ * @param context The ESLint rule context.
708
+ * @param node The node to check.
709
+ * @returns `true` if the node is a call expression for a component wrapper.
710
+ */
711
+ function isFunctionComponentWrapperCall(context, node) {
712
+ if (node.type !== AST_NODE_TYPES.CallExpression) return false;
713
+ return isMemoCall(context, node) || isForwardRefCall(context, node);
714
+ }
715
+ /**
716
+ * Check if the node is a callback function passed to a component wrapper.
717
+ * @param context The ESLint rule context.
718
+ * @param node The node to check.
719
+ * @returns `true` if the node is a callback function passed to a component wrapper.
720
+ */
721
+ function isFunctionComponentWrapperCallback(context, node) {
722
+ if (!Check.isFunction(node)) return false;
723
+ let parent = node.parent;
724
+ while (Check.isTypeExpression(parent)) parent = parent.parent;
725
+ if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
726
+ return isFunctionComponentWrapperCall(context, parent);
727
+ }
728
+ /**
729
+ * Get function component identifier from `const Component = memo(() => {});`.
730
+ * @param context The rule context.
731
+ * @param node The AST node to get the function component identifier from.
732
+ * @internal
733
+ */
734
+ function getFunctionComponentId(context, node) {
735
+ const functionId = getFunctionId(node);
736
+ if (functionId != null) return functionId;
737
+ let parent = node.parent;
738
+ while (Check.isTypeExpression(parent)) parent = parent.parent;
739
+ switch (true) {
740
+ case parent.type === AST_NODE_TYPES.CallExpression && isFunctionComponentWrapperCall(context, parent) && parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return parent.parent.id;
741
+ case parent.type === AST_NODE_TYPES.CallExpression && isFunctionComponentWrapperCall(context, parent) && parent.parent.type === AST_NODE_TYPES.CallExpression && isFunctionComponentWrapperCall(context, parent.parent) && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return parent.parent.parent.id;
742
+ default: return null;
743
+ }
744
+ }
745
+ /**
746
+ * Check if a string matches the strict component name pattern.
747
+ * @param name The name to check.
748
+ * @returns `true` if the name matches the strict component name pattern.
749
+ */
750
+ function isFunctionComponentName(name) {
751
+ return RE_COMPONENT_NAME.test(name);
752
+ }
753
+ /**
754
+ * Check if a string matches the loose component name pattern.
755
+ * @param name The name to check.
756
+ * @returns `true` if the name matches the loose component name pattern.
757
+ */
758
+ function isFunctionComponentNameLoose(name) {
759
+ return RE_COMPONENT_NAME_LOOSE.test(name);
760
+ }
761
+ /**
762
+ * Check if a function has a loose component name.
763
+ * @param context The rule context.
764
+ * @param fn The function to check.
765
+ * @param allowNone Whether to allow no name.
766
+ * @returns `true` if the function has a loose component name.
767
+ */
768
+ function isFunctionWithLooseComponentName(context, fn, allowNone = false) {
769
+ const id = getFunctionComponentId(context, fn);
770
+ if (id == null) return allowNone;
771
+ if (id.type === AST_NODE_TYPES.Identifier) return isFunctionComponentNameLoose(id.name);
772
+ if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) return isFunctionComponentNameLoose(id.property.name);
773
+ return false;
774
+ }
775
+ /**
776
+ * Hints for component collector.
914
777
  */
915
- function isFunctionEmpty(node) {
916
- return node.body.type === AST_NODE_TYPES.BlockStatement && node.body.body.length === 0;
917
- }
778
+ const FunctionComponentDetectionHint = {
779
+ ...JsxDetectionHint,
780
+ /** Exclude functions defined as class methods from component detection. */
781
+ DoNotIncludeFunctionDefinedAsClassMethod: 1n << 11n,
782
+ /** Exclude functions defined as class properties from component detection. */
783
+ DoNotIncludeFunctionDefinedAsClassProperty: 1n << 12n,
784
+ /** Exclude functions defined as object methods from component detection. */
785
+ DoNotIncludeFunctionDefinedAsObjectMethod: 1n << 13n,
786
+ /** Exclude functions defined as array expression elements from component detection. */
787
+ DoNotIncludeFunctionDefinedAsArrayExpressionElement: 1n << 14n,
788
+ /** Exclude functions defined as array pattern elements from component detection. */
789
+ DoNotIncludeFunctionDefinedAsArrayPatternElement: 1n << 15n,
790
+ /** Exclude functions defined as array flatMap callbacks from component detection. */
791
+ DoNotIncludeFunctionDefinedAsArrayFlatMapCallback: 1n << 16n,
792
+ /** Exclude functions defined as array map callbacks from component detection. */
793
+ DoNotIncludeFunctionDefinedAsArrayMapCallback: 1n << 17n,
794
+ /** Exclude functions defined as arbitrary call expression callbacks from component detection. */
795
+ DoNotIncludeFunctionDefinedAsArbitraryCallExpressionCallback: 1n << 18n
796
+ };
918
797
  /**
919
- * Get the directives of a function (ex: "use strict", "use client", "use server").
920
- * @param node The function node to get the directives from.
921
- * @returns The directives of the function.
798
+ * Default component detection hint.
922
799
  */
923
- function getFunctionDirectives(node) {
924
- const directives = [];
925
- if (node.body.type !== AST_NODE_TYPES.BlockStatement) return directives;
926
- function isDirective(node) {
927
- return node.type === AST_NODE_TYPES.ExpressionStatement && node.directive != null;
928
- }
929
- for (const stmt of node.body.body) {
930
- if (!isDirective(stmt)) continue;
931
- directives.push(stmt);
932
- }
933
- return directives;
934
- }
800
+ 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;
935
801
  /**
936
- * Check if a directive with the given name exists in the function directives.
802
+ * Check if the function node is a valid React component definition.
937
803
  *
938
- * @param node The function AST node.
939
- * @param name The directive name to check (e.g., "use memo", "use no memo").
940
- * @returns `true` if the directive exists, `false` otherwise.
804
+ * @param context The rule context.
805
+ * @param node The function node to analyze.
806
+ * @param hint Component detection hints (bit flags) to customize detection logic.
807
+ * @returns `true` if the node is considered a component definition.
941
808
  */
942
- function isFunctionHasDirective(node, name) {
943
- return getFunctionDirectives(node).some((d) => d.directive === name);
809
+ function isFunctionComponentDefinition(context, node, hint) {
810
+ if (!isFunctionWithLooseComponentName(context, node, true)) return false;
811
+ let parent = node.parent;
812
+ while (Check.isTypeExpression(parent)) parent = parent.parent;
813
+ if (isRenderMethodCallback(node)) return false;
814
+ if (isCreateElementChildrenArgument(context, node)) return false;
815
+ const [parentCallee, parentCalleeName] = parent.type === AST_NODE_TYPES.CallExpression ? [Extract.unwrap(parent.callee), Extract.getCalleeName(parent)] : [null, null];
816
+ switch (true) {
817
+ case Check.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && parent.type === AST_NODE_TYPES.Property && parent.parent.type === AST_NODE_TYPES.ObjectExpression:
818
+ if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsObjectMethod) return false;
819
+ break;
820
+ case Check.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && parent.type === AST_NODE_TYPES.MethodDefinition:
821
+ if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsClassMethod) return false;
822
+ break;
823
+ case Check.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && parent.type === AST_NODE_TYPES.PropertyDefinition:
824
+ if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsClassProperty) return false;
825
+ break;
826
+ case parent.type === AST_NODE_TYPES.ArrayPattern:
827
+ if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayPatternElement) return false;
828
+ break;
829
+ case parent.type === AST_NODE_TYPES.ArrayExpression:
830
+ if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayExpressionElement) return false;
831
+ break;
832
+ case parentCallee != null && parentCallee.type === AST_NODE_TYPES.MemberExpression && parentCalleeName === "map":
833
+ if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback) return false;
834
+ break;
835
+ case parentCallee != null && parentCallee.type === AST_NODE_TYPES.MemberExpression && parentCalleeName === "flatMap":
836
+ if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayFlatMapCallback) return false;
837
+ break;
838
+ case parent.type === AST_NODE_TYPES.CallExpression && getFunctionId(node) == null && !isFunctionComponentWrapperCall(context, parent) && !isCreateElementCall(context, parent): if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArbitraryCallExpressionCallback) return false;
839
+ }
840
+ const significantParent = Traverse.findParent(node, Check.isOneOf([
841
+ AST_NODE_TYPES.JSXExpressionContainer,
842
+ AST_NODE_TYPES.ArrowFunctionExpression,
843
+ AST_NODE_TYPES.FunctionExpression,
844
+ AST_NODE_TYPES.Property,
845
+ AST_NODE_TYPES.ClassBody
846
+ ]));
847
+ if (significantParent == null) return true;
848
+ if (significantParent.type === AST_NODE_TYPES.JSXExpressionContainer) return false;
849
+ return true;
944
850
  }
945
- /** The esquery selector matching `displayName` assignment expressions. */
946
- const SEL_FUNCTION_DISPLAY_NAME_ASSIGNMENT = [
947
- "AssignmentExpression",
948
- "[operator='=']",
949
- "[left.type='MemberExpression']",
950
- "[left.property.name='displayName']"
951
- ].join("");
952
851
 
953
852
  //#endregion
954
- //#region src/jsx.ts
853
+ //#region ../../.pkgs/eff/dist/index.js
955
854
  /**
956
- * Hints for JSX detection.
855
+ * Applies a `pipe` method's variadic arguments to an initial value from left
856
+ * to right.
857
+ *
858
+ * **When to use**
859
+ *
860
+ * Use to implement a custom `.pipe(...)` method from JavaScript's `arguments`
861
+ * object.
862
+ *
863
+ * **Details**
864
+ *
865
+ * This helper is intended for implementing `Pipeable.pipe` methods that
866
+ * receive JavaScript's `arguments` object. With no functions it returns the
867
+ * original value; otherwise it feeds each result into the next function.
868
+ *
869
+ * **Example** (Implementing a pipe method)
870
+ *
871
+ * ```ts
872
+ * import { Pipeable } from "effect"
873
+ *
874
+ * class NumberBox {
875
+ * constructor(readonly value: number) {}
876
+ *
877
+ * pipe(..._fns: ReadonlyArray<(value: number) => number>): number {
878
+ * return Pipeable.pipeArguments(this.value, arguments) as number
879
+ * }
880
+ * }
881
+ *
882
+ * const result = new NumberBox(5).pipe(
883
+ * (n) => n + 2,
884
+ * (n) => n * 3
885
+ * )
886
+ * console.log(result) // 21
887
+ * ```
888
+ *
889
+ * @category combinators
890
+ * @since 2.0.0
957
891
  */
958
- const JsxDetectionHint = {
959
- /** No hints set. */
960
- None: 0n,
961
- /** Do not treat `null` values as JSX-like. */
962
- DoNotIncludeJsxWithNullValue: 1n << 0n,
963
- /** Do not treat number values as JSX-like. */
964
- DoNotIncludeJsxWithNumberValue: 1n << 1n,
965
- /** Do not treat bigint values as JSX-like. */
966
- DoNotIncludeJsxWithBigIntValue: 1n << 2n,
967
- /** Do not treat string values as JSX-like. */
968
- DoNotIncludeJsxWithStringValue: 1n << 3n,
969
- /** Do not treat boolean values as JSX-like. */
970
- DoNotIncludeJsxWithBooleanValue: 1n << 4n,
971
- /** Do not treat undefined values as JSX-like. */
972
- DoNotIncludeJsxWithUndefinedValue: 1n << 5n,
973
- /** Do not treat empty array values as JSX-like. */
974
- DoNotIncludeJsxWithEmptyArrayValue: 1n << 6n,
975
- /** Do not treat `createElement` calls as JSX-like. */
976
- DoNotIncludeJsxWithCreateElementValue: 1n << 7n,
977
- /** Require all array elements to be JSX-like for the array to be JSX-like. */
978
- RequireAllArrayElementsToBeJsx: 1n << 8n,
979
- /** Require both sides of a logical expression to be JSX-like. */
980
- RequireBothSidesOfLogicalExpressionToBeJsx: 1n << 9n,
981
- /** Require both branches of a conditional expression to be JSX-like. */
982
- RequireBothBranchesOfConditionalExpressionToBeJsx: 1n << 10n
892
+ const pipeArguments = (self, args) => {
893
+ switch (args.length) {
894
+ case 0: return self;
895
+ case 1: return args[0](self);
896
+ case 2: return args[1](args[0](self));
897
+ case 3: return args[2](args[1](args[0](self)));
898
+ case 4: return args[3](args[2](args[1](args[0](self))));
899
+ case 5: return args[4](args[3](args[2](args[1](args[0](self)))));
900
+ case 6: return args[5](args[4](args[3](args[2](args[1](args[0](self))))));
901
+ case 7: return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))));
902
+ case 8: return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))));
903
+ case 9: return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))));
904
+ default: {
905
+ let ret = self;
906
+ for (let i = 0, len = args.length; i < len; i++) ret = args[i](ret);
907
+ return ret;
908
+ }
909
+ }
983
910
  };
984
911
  /**
985
- * Default JSX detection hint.
912
+ * Reusable prototype that implements `Pipeable.pipe`.
986
913
  *
987
- * Skips number, bigint, boolean, string, and undefined literals,
988
- * the value types that are commonly returned alongside JSX in React
989
- * components but are not themselves renderable elements.
914
+ * **When to use**
915
+ *
916
+ * Use when classes or object prototypes can reuse this value when they need the
917
+ * standard pipe implementation backed by `pipeArguments`.
918
+ *
919
+ * @category prototypes
920
+ * @since 3.15.0
990
921
  */
991
- const DEFAULT_JSX_DETECTION_HINT = 0n | JsxDetectionHint.DoNotIncludeJsxWithNumberValue | JsxDetectionHint.DoNotIncludeJsxWithBigIntValue | JsxDetectionHint.DoNotIncludeJsxWithBooleanValue | JsxDetectionHint.DoNotIncludeJsxWithStringValue | JsxDetectionHint.DoNotIncludeJsxWithUndefinedValue;
922
+ const Prototype = { pipe() {
923
+ return pipeArguments(this, arguments);
924
+ } };
992
925
  /**
993
- * Check if the node represents JSX-like content based on heuristics.
926
+ * Provides a base constructor whose instances implement the standard `Pipeable.pipe`
927
+ * method.
928
+ *
929
+ * **When to use**
930
+ *
931
+ * Use when you need to define a class that supports Effect-style method
932
+ * chaining through `.pipe(...)`.
933
+ *
934
+ * @category constructors
935
+ * @since 3.15.0
936
+ */
937
+ const Class = (function() {
938
+ function PipeableBase() {}
939
+ PipeableBase.prototype = Prototype;
940
+ return PipeableBase;
941
+ })();
942
+ /**
943
+ * Provides small helpers for defining and reusing TypeScript functions.
944
+ *
945
+ * The main helpers are `pipe` and `flow` for left-to-right composition and
946
+ * `dual` for APIs that support both direct and pipe-friendly call styles. The
947
+ * module also contains small identity, constant, tuple, type-level, and
948
+ * memoization helpers used across the library.
949
+ *
950
+ * @since 2.0.0
951
+ */
952
+ /**
953
+ * Creates a function that can be called in data-first style or data-last
954
+ * (`pipe`-friendly) style.
955
+ *
956
+ * **When to use**
957
+ *
958
+ * Use to expose one implementation through both direct and `pipe`-friendly
959
+ * call styles.
960
+ *
961
+ * **Details**
962
+ *
963
+ * Pass either the arity of the uncurried function or a predicate that decides
964
+ * whether the current call is data-first. Arity is the common case. Use a
965
+ * predicate when optional arguments make arity ambiguous.
966
+ *
967
+ * **Example** (Selecting data-first or data-last style by arity)
968
+ *
969
+ * ```ts
970
+ * import { Function, pipe } from "effect"
971
+ *
972
+ * const sum = Function.dual<
973
+ * (that: number) => (self: number) => number,
974
+ * (self: number, that: number) => number
975
+ * >(2, (self, that) => self + that)
976
+ *
977
+ * console.log(sum(2, 3)) // 5
978
+ * console.log(pipe(2, sum(3))) // 5
979
+ * ```
980
+ *
981
+ * **Example** (Defining overloads with call signatures)
994
982
  *
995
- * The detection behavior is configurable through {@link JsxDetectionHint}
996
- * bit-flags so that callers can opt individual value kinds in or out.
983
+ * ```ts
984
+ * import { Function, pipe } from "effect"
997
985
  *
998
- * Identifiers are resolved to their definitions via scope analysis;
999
- * circular definitions (e.g. `var a = b; var b = a;`) are detected and
1000
- * treated as not JSX-like instead of recursing indefinitely.
986
+ * const sum: {
987
+ * (that: number): (self: number) => number
988
+ * (self: number, that: number): number
989
+ * } = Function.dual(2, (self: number, that: number): number => self + that)
1001
990
  *
1002
- * @param context The ESLint rule context (needed for variable resolution).
1003
- * @param node The AST node to analyze.
1004
- * @param hint Optional bit-flags to adjust detection behavior. Defaults to {@link DEFAULT_JSX_DETECTION_HINT}.
1005
- * @returns Whether the node is considered JSX-like.
991
+ * console.log(sum(2, 3)) // 5
992
+ * console.log(pipe(2, sum(3))) // 5
993
+ * ```
994
+ *
995
+ * **Example** (Selecting data-first or data-last style with a predicate)
1006
996
  *
1007
- * @example
1008
997
  * ```ts
1009
- * import { isJsxLike } from "@eslint-react/core";
998
+ * import { Function, pipe } from "effect"
1010
999
  *
1011
- * if (isJsxLike(context, node)) {
1012
- * // node looks like it evaluates to a React element
1013
- * }
1000
+ * const sum = Function.dual<
1001
+ * (that: number) => (self: number) => number,
1002
+ * (self: number, that: number) => number
1003
+ * >(
1004
+ * (args) => args.length === 2,
1005
+ * (self, that) => self + that
1006
+ * )
1007
+ *
1008
+ * console.log(sum(2, 3)) // 5
1009
+ * console.log(pipe(2, sum(3))) // 5
1014
1010
  * ```
1011
+ *
1012
+ * @category combinators
1013
+ * @since 2.0.0
1015
1014
  */
1016
- function isJsxLike(context, node, hint = DEFAULT_JSX_DETECTION_HINT) {
1017
- const seen = /* @__PURE__ */ new Set();
1018
- function visit(node) {
1019
- if (node == null) return false;
1020
- if (Check.isJSX(node)) return true;
1021
- switch (node.type) {
1022
- case AST_NODE_TYPES.Literal:
1023
- switch (typeof node.value) {
1024
- case "boolean": return !(hint & JsxDetectionHint.DoNotIncludeJsxWithBooleanValue);
1025
- case "string": return !(hint & JsxDetectionHint.DoNotIncludeJsxWithStringValue);
1026
- case "number": return !(hint & JsxDetectionHint.DoNotIncludeJsxWithNumberValue);
1027
- case "bigint": return !(hint & JsxDetectionHint.DoNotIncludeJsxWithBigIntValue);
1028
- }
1029
- return node.value == null && !(hint & JsxDetectionHint.DoNotIncludeJsxWithNullValue);
1030
- case AST_NODE_TYPES.TemplateLiteral: return !(hint & JsxDetectionHint.DoNotIncludeJsxWithStringValue);
1031
- case AST_NODE_TYPES.ArrayExpression:
1032
- if (node.elements.length === 0) return !(hint & JsxDetectionHint.DoNotIncludeJsxWithEmptyArrayValue);
1033
- return hint & JsxDetectionHint.RequireAllArrayElementsToBeJsx ? node.elements.every(visit) : node.elements.some(visit);
1034
- case AST_NODE_TYPES.LogicalExpression:
1035
- if (hint & JsxDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx) return visit(node.left) && visit(node.right);
1036
- return visit(node.left) || visit(node.right);
1037
- case AST_NODE_TYPES.ConditionalExpression:
1038
- if (hint & JsxDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx) return visit(node.consequent) && visit(node.alternate);
1039
- return visit(node.consequent) || visit(node.alternate);
1040
- case AST_NODE_TYPES.SequenceExpression: return visit(node.expressions.at(-1) ?? null);
1041
- case AST_NODE_TYPES.CallExpression:
1042
- if (hint & JsxDetectionHint.DoNotIncludeJsxWithCreateElementValue) return false;
1043
- return Extract.getCalleeName(node) === "createElement";
1044
- case AST_NODE_TYPES.Identifier:
1045
- if (node.name === "undefined") return !(hint & JsxDetectionHint.DoNotIncludeJsxWithUndefinedValue);
1046
- if (seen.has(node)) return false;
1047
- seen.add(node);
1048
- return visit(resolve(context, node));
1049
- }
1050
- return false;
1015
+ const dual = function(arity, body) {
1016
+ if (typeof arity === "function") return function() {
1017
+ return arity(arguments) ? body.apply(this, arguments) : ((self) => body(self, ...arguments));
1018
+ };
1019
+ switch (arity) {
1020
+ case 0:
1021
+ case 1: throw new RangeError(`Invalid arity ${arity}`);
1022
+ case 2: return function(a, b) {
1023
+ if (arguments.length >= 2) return body(a, b);
1024
+ return function(self) {
1025
+ return body(self, a);
1026
+ };
1027
+ };
1028
+ case 3: return function(a, b, c) {
1029
+ if (arguments.length >= 3) return body(a, b, c);
1030
+ return function(self) {
1031
+ return body(self, a, b);
1032
+ };
1033
+ };
1034
+ default: return function() {
1035
+ if (arguments.length >= arity) return body.apply(this, arguments);
1036
+ const args = arguments;
1037
+ return function(self) {
1038
+ return body(self, ...args);
1039
+ };
1040
+ };
1051
1041
  }
1052
- return visit(node);
1053
- }
1054
-
1055
- //#endregion
1056
- //#region src/function-component.ts
1042
+ };
1057
1043
  /**
1058
- * Component flag constants.
1044
+ * Returns its input argument unchanged.
1045
+ *
1046
+ * **When to use**
1047
+ *
1048
+ * Use to return a value unchanged where a function is required.
1049
+ *
1050
+ * **Example** (Returning the same value)
1051
+ *
1052
+ * ```ts
1053
+ * import { identity } from "effect"
1054
+ * import * as assert from "node:assert"
1055
+ *
1056
+ * assert.deepStrictEqual(identity(5), 5)
1057
+ * ```
1058
+ *
1059
+ * @category combinators
1060
+ * @since 2.0.0
1059
1061
  */
1060
- const FunctionComponentFlag = {
1061
- /** No flags set. */
1062
- None: 0n,
1063
- /** Indicates the component is a pure component (ex: extends PureComponent). */
1064
- PureComponent: 1n << 0n,
1065
- /** Indicates the component creates elements using `createElement` instead of JSX. */
1066
- CreateElement: 1n << 1n,
1067
- /** Indicates the component is memoized (ex: React.memo). */
1068
- Memo: 1n << 2n,
1069
- /** Indicates the component forwards a ref (ex: React.forwardRef). */
1070
- ForwardRef: 1n << 3n
1071
- };
1062
+ const identity = (a) => a;
1072
1063
  /**
1073
- * Get component flag from init path.
1074
- * @param initPath The init path of the function component.
1075
- * @returns The component flag.
1076
- * @internal
1064
+ * Returns the input value with a different static type.
1065
+ *
1066
+ * **When to use**
1067
+ *
1068
+ * Use when you need an explicit type-level cast and accept that the value is
1069
+ * returned unchanged at runtime.
1070
+ *
1071
+ * **Gotchas**
1072
+ *
1073
+ * This is a type-level cast only; it performs no runtime validation or
1074
+ * conversion.
1075
+ *
1076
+ * @see {@link satisfies} for checking assignability without changing the resulting type
1077
+ *
1078
+ * @category utility types
1079
+ * @since 4.0.0
1077
1080
  */
1078
- function getFunctionComponentFlagFromInitPath(initPath) {
1079
- let flag = FunctionComponentFlag.None;
1080
- if (initPath != null && isFunctionHasCallInInitPath("memo", initPath)) flag |= FunctionComponentFlag.Memo;
1081
- if (initPath != null && isFunctionHasCallInInitPath("forwardRef", initPath)) flag |= FunctionComponentFlag.ForwardRef;
1082
- return flag;
1083
- }
1081
+ const cast = identity;
1084
1082
  /**
1085
- * Check if the node is a call expression for a component wrapper.
1086
- * @param context The ESLint rule context.
1087
- * @param node The node to check.
1088
- * @returns `true` if the node is a call expression for a component wrapper.
1083
+ * Creates a zero-argument function that always returns the provided value.
1084
+ *
1085
+ * **When to use**
1086
+ *
1087
+ * Use when you need a thunk or callback that returns the same value on every
1088
+ * invocation.
1089
+ *
1090
+ * **Example** (Creating a constant thunk)
1091
+ *
1092
+ * ```ts
1093
+ * import { Function } from "effect"
1094
+ * import * as assert from "node:assert"
1095
+ *
1096
+ * const constNull = Function.constant(null)
1097
+ *
1098
+ * assert.deepStrictEqual(constNull(), null)
1099
+ * assert.deepStrictEqual(constNull(), null)
1100
+ * ```
1101
+ *
1102
+ * @category constructors
1103
+ * @since 2.0.0
1089
1104
  */
1090
- function isFunctionComponentWrapperCall(context, node) {
1091
- if (node.type !== AST_NODE_TYPES.CallExpression) return false;
1092
- return isMemoCall(context, node) || isForwardRefCall(context, node);
1093
- }
1105
+ const constant = (value) => () => value;
1094
1106
  /**
1095
- * Check if the node is a callback function passed to a component wrapper.
1096
- * @param context The ESLint rule context.
1097
- * @param node The node to check.
1098
- * @returns `true` if the node is a callback function passed to a component wrapper.
1107
+ * Returns `true` when called.
1108
+ *
1109
+ * **When to use**
1110
+ *
1111
+ * Use when you need a thunk that returns `true` on every invocation.
1112
+ *
1113
+ * **Example** (Returning true from a thunk)
1114
+ *
1115
+ * ```ts
1116
+ * import { Function } from "effect"
1117
+ * import * as assert from "node:assert"
1118
+ *
1119
+ * assert.deepStrictEqual(Function.constTrue(), true)
1120
+ * ```
1121
+ *
1122
+ * @category constants
1123
+ * @since 2.0.0
1099
1124
  */
1100
- function isFunctionComponentWrapperCallback(context, node) {
1101
- if (!Check.isFunction(node)) return false;
1102
- let parent = node.parent;
1103
- while (Check.isTypeExpression(parent)) parent = parent.parent;
1104
- if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
1105
- return isFunctionComponentWrapperCall(context, parent);
1106
- }
1125
+ const constTrue = constant(true);
1107
1126
  /**
1108
- * Get function component identifier from `const Component = memo(() => {});`.
1109
- * @param context The rule context.
1110
- * @param node The AST node to get the function component identifier from.
1111
- * @internal
1127
+ * Returns `false` when called.
1128
+ *
1129
+ * **When to use**
1130
+ *
1131
+ * Use when you need a thunk that returns `false` on every invocation.
1132
+ *
1133
+ * **Example** (Returning false from a thunk)
1134
+ *
1135
+ * ```ts
1136
+ * import { Function } from "effect"
1137
+ * import * as assert from "node:assert"
1138
+ *
1139
+ * assert.deepStrictEqual(Function.constFalse(), false)
1140
+ * ```
1141
+ *
1142
+ * @category constants
1143
+ * @since 2.0.0
1112
1144
  */
1113
- function getFunctionComponentId(context, node) {
1114
- const functionId = getFunctionId(node);
1115
- if (functionId != null) return functionId;
1116
- let parent = node.parent;
1117
- while (Check.isTypeExpression(parent)) parent = parent.parent;
1118
- switch (true) {
1119
- case parent.type === AST_NODE_TYPES.CallExpression && isFunctionComponentWrapperCall(context, parent) && parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return parent.parent.id;
1120
- case parent.type === AST_NODE_TYPES.CallExpression && isFunctionComponentWrapperCall(context, parent) && parent.parent.type === AST_NODE_TYPES.CallExpression && isFunctionComponentWrapperCall(context, parent.parent) && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return parent.parent.parent.id;
1121
- default: return null;
1122
- }
1123
- }
1145
+ const constFalse = constant(false);
1124
1146
  /**
1125
- * Check if a string matches the strict component name pattern.
1126
- * @param name The name to check.
1127
- * @returns `true` if the name matches the strict component name pattern.
1147
+ * Returns `null` when called.
1148
+ *
1149
+ * **When to use**
1150
+ *
1151
+ * Use when you need a thunk that returns `null` on every invocation.
1152
+ *
1153
+ * **Example** (Returning null from a thunk)
1154
+ *
1155
+ * ```ts
1156
+ * import { Function } from "effect"
1157
+ * import * as assert from "node:assert"
1158
+ *
1159
+ * assert.deepStrictEqual(Function.constNull(), null)
1160
+ * ```
1161
+ *
1162
+ * @category constants
1163
+ * @since 2.0.0
1128
1164
  */
1129
- function isFunctionComponentName(name) {
1130
- return RE_COMPONENT_NAME.test(name);
1131
- }
1165
+ const constNull = constant(null);
1132
1166
  /**
1133
- * Check if a string matches the loose component name pattern.
1134
- * @param name The name to check.
1135
- * @returns `true` if the name matches the loose component name pattern.
1167
+ * Returns `undefined` when called.
1168
+ *
1169
+ * **When to use**
1170
+ *
1171
+ * Use when you need a thunk that returns `undefined` on every invocation.
1172
+ *
1173
+ * **Example** (Returning undefined from a thunk)
1174
+ *
1175
+ * ```ts
1176
+ * import { Function } from "effect"
1177
+ * import * as assert from "node:assert"
1178
+ *
1179
+ * assert.deepStrictEqual(Function.constUndefined(), undefined)
1180
+ * ```
1181
+ *
1182
+ * @category constants
1183
+ * @since 2.0.0
1136
1184
  */
1137
- function isFunctionComponentNameLoose(name) {
1138
- return RE_COMPONENT_NAME_LOOSE.test(name);
1139
- }
1185
+ const constUndefined = constant(void 0);
1140
1186
  /**
1141
- * Check if a function has a loose component name.
1142
- * @param context The rule context.
1143
- * @param fn The function to check.
1144
- * @param allowNone Whether to allow no name.
1145
- * @returns `true` if the function has a loose component name.
1187
+ * 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`.
1188
+ * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`.
1189
+ *
1190
+ * **When to use**
1191
+ *
1192
+ * Use to compose exactly two unary functions into a reusable unary function.
1193
+ *
1194
+ * **Example** (Composing two functions)
1195
+ *
1196
+ * ```ts
1197
+ * import { Function } from "effect"
1198
+ * import * as assert from "node:assert"
1199
+ *
1200
+ * const increment = (n: number) => n + 1
1201
+ * const square = (n: number) => n * n
1202
+ *
1203
+ * assert.strictEqual(Function.compose(increment, square)(2), 9)
1204
+ * ```
1205
+ *
1206
+ * @see {@link flow} for composing a left-to-right sequence of functions
1207
+ * @see {@link pipe} for applying a value through a left-to-right sequence immediately
1208
+ *
1209
+ * @category combinators
1210
+ * @since 2.0.0
1146
1211
  */
1147
- function isFunctionWithLooseComponentName(context, fn, allowNone = false) {
1148
- const id = getFunctionComponentId(context, fn);
1149
- if (id == null) return allowNone;
1150
- if (id.type === AST_NODE_TYPES.Identifier) return isFunctionComponentNameLoose(id.name);
1151
- if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) return isFunctionComponentNameLoose(id.property.name);
1152
- return false;
1153
- }
1212
+ const compose = dual(2, (ab, bc) => (a) => bc(ab(a)));
1154
1213
  /**
1155
- * Hints for component collector.
1214
+ * Marks an impossible branch by accepting a `never` value and returning any
1215
+ * type.
1216
+ *
1217
+ * **When to use**
1218
+ *
1219
+ * Use when you need a return value in a branch that exhaustive checks prove
1220
+ * cannot be reached.
1221
+ *
1222
+ * **Gotchas**
1223
+ *
1224
+ * Calling `absurd` throws, because a value of type `never` should be
1225
+ * impossible at runtime.
1226
+ *
1227
+ * **Example** (Handling impossible values)
1228
+ *
1229
+ * ```ts
1230
+ * import { absurd } from "effect"
1231
+ *
1232
+ * const handleNever = (value: never) => {
1233
+ * return absurd(value) // This will throw an error if called
1234
+ * }
1235
+ * ```
1236
+ *
1237
+ * @category utility types
1238
+ * @since 2.0.0
1156
1239
  */
1157
- const FunctionComponentDetectionHint = {
1158
- ...JsxDetectionHint,
1159
- /** Exclude functions defined as class methods from component detection. */
1160
- DoNotIncludeFunctionDefinedAsClassMethod: 1n << 11n,
1161
- /** Exclude functions defined as class properties from component detection. */
1162
- DoNotIncludeFunctionDefinedAsClassProperty: 1n << 12n,
1163
- /** Exclude functions defined as object methods from component detection. */
1164
- DoNotIncludeFunctionDefinedAsObjectMethod: 1n << 13n,
1165
- /** Exclude functions defined as array expression elements from component detection. */
1166
- DoNotIncludeFunctionDefinedAsArrayExpressionElement: 1n << 14n,
1167
- /** Exclude functions defined as array pattern elements from component detection. */
1168
- DoNotIncludeFunctionDefinedAsArrayPatternElement: 1n << 15n,
1169
- /** Exclude functions defined as array flatMap callbacks from component detection. */
1170
- DoNotIncludeFunctionDefinedAsArrayFlatMapCallback: 1n << 16n,
1171
- /** Exclude functions defined as array map callbacks from component detection. */
1172
- DoNotIncludeFunctionDefinedAsArrayMapCallback: 1n << 17n,
1173
- /** Exclude functions defined as arbitrary call expression callbacks from component detection. */
1174
- DoNotIncludeFunctionDefinedAsArbitraryCallExpressionCallback: 1n << 18n
1240
+ const absurd = (_) => {
1241
+ throw new Error("Called `absurd` function which should be uncallable");
1175
1242
  };
1176
1243
  /**
1177
- * Default component detection hint.
1244
+ * Creates a compile-time placeholder for a value of any type.
1245
+ *
1246
+ * **When to use**
1247
+ *
1248
+ * Use as a temporary typed placeholder while developing incomplete code.
1249
+ *
1250
+ * **Gotchas**
1251
+ *
1252
+ * `hole` is intended for temporary development use. If the placeholder is
1253
+ * evaluated at runtime, it throws.
1254
+ *
1255
+ * **Example** (Creating a development placeholder)
1256
+ *
1257
+ * ```ts
1258
+ * import { hole } from "effect"
1259
+ *
1260
+ * // Intentionally not called: `hole` throws if the placeholder is evaluated.
1261
+ * const buildUser = (id: number): { readonly id: number; readonly name: string } => ({
1262
+ * id,
1263
+ * name: hole<string>()
1264
+ * })
1265
+ *
1266
+ * console.log(typeof buildUser) // "function"
1267
+ * ```
1268
+ *
1269
+ * @category utility types
1270
+ * @since 2.0.0
1178
1271
  */
1179
- 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;
1272
+ const hole = cast(absurd);
1180
1273
  /**
1181
- * Check if the function node is a valid React component definition.
1274
+ * Drops the longest prefix of elements from an array that satisfy the given predicate.
1182
1275
  *
1183
- * @param context The rule context.
1184
- * @param node The function node to analyze.
1185
- * @param hint Component detection hints (bit flags) to customize detection logic.
1186
- * @returns `true` if the node is considered a component definition.
1276
+ * Supports both data-first and data-last (`pipe`-friendly) call styles.
1277
+ *
1278
+ * @param pred - The predicate to test each element with.
1279
+ * @returns A new array without the matching prefix.
1280
+ * @example
1281
+ * ```ts
1282
+ * import * as assert from "node:assert"
1283
+ * import { dropWhile, pipe } from "@local/eff"
1284
+ *
1285
+ * // data-first
1286
+ * assert.deepStrictEqual(dropWhile([1, 2, 3, 2, 1], (n: number) => n < 3), [3, 2, 1])
1287
+ *
1288
+ * // data-last
1289
+ * assert.deepStrictEqual(pipe([1, 2, 3, 2, 1], dropWhile((n: number) => n < 3)), [3, 2, 1])
1290
+ * ```
1291
+ * @category array
1187
1292
  */
1188
- function isFunctionComponentDefinition(context, node, hint) {
1189
- if (!isFunctionWithLooseComponentName(context, node, true)) return false;
1190
- const isCreateElementArg = (() => {
1191
- let p = node.parent;
1192
- while (Check.isTypeExpression(p)) p = p.parent;
1193
- if (p.type !== AST_NODE_TYPES.CallExpression || !isCreateElementCall(context, p)) return false;
1194
- return p.arguments.slice(2).some((arg) => Extract.unwrap(arg) === node);
1195
- })();
1196
- switch (true) {
1197
- case isCreateElementArg: return false;
1198
- case isRenderMethodCallback(node): return false;
1199
- }
1200
- let parent = node.parent;
1201
- while (Check.isTypeExpression(parent)) parent = parent.parent;
1202
- const parentCallee = parent.type === AST_NODE_TYPES.CallExpression ? Extract.unwrap(parent.callee) : null;
1203
- const parentCalleeName = parent.type === AST_NODE_TYPES.CallExpression ? Extract.getCalleeName(parent) : null;
1204
- switch (true) {
1205
- case Check.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && parent.type === AST_NODE_TYPES.Property && parent.parent.type === AST_NODE_TYPES.ObjectExpression:
1206
- if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsObjectMethod) return false;
1207
- break;
1208
- case Check.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && parent.type === AST_NODE_TYPES.MethodDefinition:
1209
- if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsClassMethod) return false;
1210
- break;
1211
- case Check.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && parent.type === AST_NODE_TYPES.PropertyDefinition:
1212
- if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsClassProperty) return false;
1213
- break;
1214
- case parent.type === AST_NODE_TYPES.ArrayPattern:
1215
- if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayPatternElement) return false;
1216
- break;
1217
- case parent.type === AST_NODE_TYPES.ArrayExpression:
1218
- if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayExpressionElement) return false;
1219
- break;
1220
- case parentCallee != null && parentCallee.type === AST_NODE_TYPES.MemberExpression && parentCalleeName === "map":
1221
- if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback) return false;
1222
- break;
1223
- case parentCallee != null && parentCallee.type === AST_NODE_TYPES.MemberExpression && parentCalleeName === "flatMap":
1224
- if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayFlatMapCallback) return false;
1225
- break;
1226
- case parent.type === AST_NODE_TYPES.CallExpression && getFunctionId(node) == null && !isFunctionComponentWrapperCall(context, parent) && !isCreateElementCall(context, parent): if (hint & FunctionComponentDetectionHint.DoNotIncludeFunctionDefinedAsArbitraryCallExpressionCallback) return false;
1227
- }
1228
- const significantParent = Traverse.findParent(node, Check.isOneOf([
1229
- AST_NODE_TYPES.JSXExpressionContainer,
1230
- AST_NODE_TYPES.ArrowFunctionExpression,
1231
- AST_NODE_TYPES.FunctionExpression,
1232
- AST_NODE_TYPES.Property,
1233
- AST_NODE_TYPES.ClassBody
1234
- ]));
1235
- if (significantParent == null) return true;
1236
- if (significantParent.type === AST_NODE_TYPES.JSXExpressionContainer) return false;
1237
- return true;
1238
- }
1293
+ const dropWhile = dual(2, (xs, pred) => {
1294
+ const len = xs.length;
1295
+ let idx = 0;
1296
+ while (idx < len && pred(xs[idx])) idx++;
1297
+ return xs.slice(idx);
1298
+ });
1299
+ /**
1300
+ * Takes the longest prefix of elements from an array that satisfy the given predicate.
1301
+ *
1302
+ * Supports both data-first and data-last (`pipe`-friendly) call styles.
1303
+ *
1304
+ * @param pred - The predicate to test each element with.
1305
+ * @returns A new array containing only the matching prefix.
1306
+ * @example
1307
+ * ```ts
1308
+ * import * as assert from "node:assert"
1309
+ * import { pipe, takeWhile } from "@local/eff"
1310
+ *
1311
+ * // data-first
1312
+ * assert.deepStrictEqual(takeWhile([1, 2, 3, 2, 1], (n: number) => n < 3), [1, 2])
1313
+ *
1314
+ * // data-last
1315
+ * assert.deepStrictEqual(pipe([1, 2, 3, 2, 1], takeWhile((n: number) => n < 3)), [1, 2])
1316
+ * ```
1317
+ * @category array
1318
+ */
1319
+ const takeWhile = dual(2, (xs, pred) => {
1320
+ const len = xs.length;
1321
+ let idx = 0;
1322
+ while (idx < len && pred(xs[idx])) idx++;
1323
+ return xs.slice(0, idx);
1324
+ });
1239
1325
 
1240
1326
  //#endregion
1241
1327
  //#region src/hook.ts
@@ -1841,4 +1927,4 @@ function getTypeVariants(types) {
1841
1927
  }
1842
1928
 
1843
1929
  //#endregion
1844
- export { DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, FunctionComponentDetectionHint, FunctionComponentFlag, JsxDetectionHint, REACT_BUILTIN_HOOK_NAMES, SEL_FUNCTION_DISPLAY_NAME_ASSIGNMENT, getClassComponentCollector, getClassId, getFullyQualifiedNameEx, getFunctionComponentCollector, getFunctionComponentFlagFromInitPath, getFunctionComponentId, getFunctionDirectives, getFunctionId, getFunctionInitPath, getHookCollector, getJsxConfig, getJsxConfigFromAnnotation, getJsxConfigFromCompilerOptions, getTypeVariants, isAPI, isAPICall, isAnyType, isAssignmentToThisState, isBigIntType, isBooleanLiteralType, isBooleanType, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isEnumType, isFalseLiteralType, isFalsyBigIntType, isFalsyNumberType, isFalsyStringType, isForwardRef, isForwardRefCall, isFunctionComponentDefinition, isFunctionComponentName, isFunctionComponentNameLoose, isFunctionComponentWrapperCall, isFunctionComponentWrapperCallback, isFunctionEmpty, isFunctionHasCallInInitPath, isFunctionHasDirective, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHookCall, isHookDefinition, isHookId, isHookName, isHookTag, isJsxLike, isLazy, isLazyCall, isMemo, isMemoCall, isNeverType, isNullishType, isNumberType, isObjectType, isPureComponent, isRender, isRenderMethodCallback, isRenderMethodLike, isShouldComponentUpdate, isStringType, isThisSetStateCall, isTrueLiteralType, isTruthyBigIntType, isTruthyNumberType, isTruthyStringType, isUnknownType, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUse, isUseActionState, isUseActionStateCall, isUseCall, isUseCallback, isUseCallbackCall, isUseContext, isUseContextCall, isUseDebugValue, isUseDebugValueCall, isUseDeferredValue, isUseDeferredValueCall, isUseEffect, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatus, isUseFormStatusCall, isUseId, isUseIdCall, isUseImperativeHandle, isUseImperativeHandleCall, isUseInsertionEffect, isUseInsertionEffectCall, isUseLayoutEffect, isUseLayoutEffectCall, isUseMemo, isUseMemoCall, isUseOptimistic, isUseOptimisticCall, isUseReducer, isUseReducerCall, isUseRef, isUseRefCall, isUseRefLikeCall, isUseState, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStore, isUseSyncExternalStoreCall, isUseTransition, isUseTransitionCall };
1930
+ export { DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, FunctionComponentDetectionHint, FunctionComponentFlag, JsxDetectionHint, REACT_BUILTIN_HOOK_NAMES, SEL_FUNCTION_DISPLAY_NAME_ASSIGNMENT, getClassComponentCollector, getClassId, getCreateElementChildrenArguments, getCreateElementProp, getCreateElementPropsObject, getCreateElementTypeArgument, getFullyQualifiedNameEx, getFunctionComponentCollector, getFunctionComponentFlagFromInitPath, getFunctionComponentId, getFunctionDirectives, getFunctionId, getFunctionInitPath, getHookCollector, getJsxConfig, getJsxConfigFromAnnotation, getJsxConfigFromCompilerOptions, getTypeVariants, isAPI, isAPICall, isAnyType, isAssignmentToThisState, isBigIntType, isBooleanLiteralType, isBooleanType, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDidUpdate, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUpdate, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateElementChildrenArgument, isCreateRef, isCreateRefCall, isEnumType, isFalseLiteralType, isFalsyBigIntType, isFalsyNumberType, isFalsyStringType, isForwardRef, isForwardRefCall, isFunctionComponentDefinition, isFunctionComponentName, isFunctionComponentNameLoose, isFunctionComponentWrapperCall, isFunctionComponentWrapperCallback, isFunctionEmpty, isFunctionHasCallInInitPath, isFunctionHasDirective, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHookCall, isHookDefinition, isHookId, isHookName, isHookTag, isInsideCreateElementProps, isJsxLike, isLazy, isLazyCall, isMemo, isMemoCall, isNeverType, isNullishType, isNumberType, isObjectType, isPureComponent, isRender, isRenderMethodCallback, isRenderMethodLike, isShouldComponentUpdate, isStringType, isThisSetStateCall, isTrueLiteralType, isTruthyBigIntType, isTruthyNumberType, isTruthyStringType, isUnknownType, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUse, isUseActionState, isUseActionStateCall, isUseCall, isUseCallback, isUseCallbackCall, isUseContext, isUseContextCall, isUseDebugValue, isUseDebugValueCall, isUseDeferredValue, isUseDeferredValueCall, isUseEffect, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatus, isUseFormStatusCall, isUseId, isUseIdCall, isUseImperativeHandle, isUseImperativeHandleCall, isUseInsertionEffect, isUseInsertionEffectCall, isUseLayoutEffect, isUseLayoutEffectCall, isUseMemo, isUseMemoCall, isUseOptimistic, isUseOptimisticCall, isUseReducer, isUseReducerCall, isUseRef, isUseRefCall, isUseRefLikeCall, isUseState, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStore, isUseSyncExternalStoreCall, isUseTransition, isUseTransitionCall };