@eslint-react/core 5.18.5 → 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.
- package/dist/index.d.ts +62 -1
- package/dist/index.js +1072 -977
- package/package.json +5 -5
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
|
-
|
|
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
|
-
|
|
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");
|
|
@@ -643,590 +175,1153 @@ const isUseTransitionCall = isAPICall("useTransition");
|
|
|
643
175
|
//#endregion
|
|
644
176
|
//#region src/class.ts
|
|
645
177
|
/**
|
|
646
|
-
* Get the class identifier of a class node.
|
|
647
|
-
* @param node The class node to get the identifier from.
|
|
648
|
-
* @returns The class identifier or `null` if not found.
|
|
178
|
+
* Get the class identifier of a class node.
|
|
179
|
+
* @param node The class node to get the identifier from.
|
|
180
|
+
* @returns The class identifier or `null` if not found.
|
|
181
|
+
*/
|
|
182
|
+
function getClassId(node) {
|
|
183
|
+
if (node.id != null) return node.id;
|
|
184
|
+
if (node.parent.type === AST_NODE_TYPES.VariableDeclarator) return node.parent.id;
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
//#endregion
|
|
189
|
+
//#region src/class-component.ts
|
|
190
|
+
/**
|
|
191
|
+
* Check if the node is a class component (extends `Component` or `PureComponent`).
|
|
192
|
+
* @param node The node to check.
|
|
193
|
+
* @returns `true` if the node is a class component.
|
|
194
|
+
*/
|
|
195
|
+
function isClassComponent(node) {
|
|
196
|
+
if ("superClass" in node && node.superClass != null) {
|
|
197
|
+
const re = /^(?:Pure)?Component$/u;
|
|
198
|
+
switch (true) {
|
|
199
|
+
case node.superClass.type === AST_NODE_TYPES.Identifier: return re.test(node.superClass.name);
|
|
200
|
+
case node.superClass.type === AST_NODE_TYPES.MemberExpression && node.superClass.property.type === AST_NODE_TYPES.Identifier: return re.test(node.superClass.property.name);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check if the node is a pure component (extends `PureComponent`).
|
|
207
|
+
* @param node The AST node to check.
|
|
208
|
+
* @returns `true` if the node is a pure component.
|
|
209
|
+
* @deprecated Class components are legacy. This function exists only to support legacy rules.
|
|
210
|
+
*/
|
|
211
|
+
function isPureComponent(node) {
|
|
212
|
+
if ("superClass" in node && node.superClass != null) {
|
|
213
|
+
const re = /^PureComponent$/u;
|
|
214
|
+
switch (true) {
|
|
215
|
+
case node.superClass.type === AST_NODE_TYPES.Identifier: return re.test(node.superClass.name);
|
|
216
|
+
case node.superClass.type === AST_NODE_TYPES.MemberExpression && node.superClass.property.type === AST_NODE_TYPES.Identifier: return re.test(node.superClass.property.name);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
function createLifecycleChecker(methodName, isStatic = false) {
|
|
222
|
+
return (node) => Check.isPropertyOrMethod(node) && node.static === isStatic && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === methodName;
|
|
223
|
+
}
|
|
224
|
+
/** @deprecated Class components are legacy. */
|
|
225
|
+
const isRender = createLifecycleChecker("render");
|
|
226
|
+
/** @deprecated Class components are legacy. */
|
|
227
|
+
const isComponentDidCatch = createLifecycleChecker("componentDidCatch");
|
|
228
|
+
/** @deprecated Class components are legacy. */
|
|
229
|
+
const isComponentDidMount = createLifecycleChecker("componentDidMount");
|
|
230
|
+
/** @deprecated Class components are legacy. */
|
|
231
|
+
const isComponentDidUpdate = createLifecycleChecker("componentDidUpdate");
|
|
232
|
+
/** @deprecated Class components are legacy. */
|
|
233
|
+
const isComponentWillMount = createLifecycleChecker("componentWillMount");
|
|
234
|
+
/** @deprecated Class components are legacy. */
|
|
235
|
+
const isComponentWillReceiveProps = createLifecycleChecker("componentWillReceiveProps");
|
|
236
|
+
/** @deprecated Class components are legacy. */
|
|
237
|
+
const isComponentWillUnmount = createLifecycleChecker("componentWillUnmount");
|
|
238
|
+
/** @deprecated Class components are legacy. */
|
|
239
|
+
const isComponentWillUpdate = createLifecycleChecker("componentWillUpdate");
|
|
240
|
+
/** @deprecated Class components are legacy. */
|
|
241
|
+
const isGetChildContext = createLifecycleChecker("getChildContext");
|
|
242
|
+
/** @deprecated Class components are legacy. */
|
|
243
|
+
const isGetInitialState = createLifecycleChecker("getInitialState");
|
|
244
|
+
/** @deprecated Class components are legacy. */
|
|
245
|
+
const isGetSnapshotBeforeUpdate = createLifecycleChecker("getSnapshotBeforeUpdate");
|
|
246
|
+
/** @deprecated Class components are legacy. */
|
|
247
|
+
const isShouldComponentUpdate = createLifecycleChecker("shouldComponentUpdate");
|
|
248
|
+
/** @deprecated Class components are legacy. */
|
|
249
|
+
const isUnsafeComponentWillMount = createLifecycleChecker("UNSAFE_componentWillMount");
|
|
250
|
+
/** @deprecated Class components are legacy. */
|
|
251
|
+
const isUnsafeComponentWillReceiveProps = createLifecycleChecker("UNSAFE_componentWillReceiveProps");
|
|
252
|
+
/** @deprecated Class components are legacy. */
|
|
253
|
+
const isUnsafeComponentWillUpdate = createLifecycleChecker("UNSAFE_componentWillUpdate");
|
|
254
|
+
/** @deprecated Class components are legacy. */
|
|
255
|
+
const isGetDefaultProps = createLifecycleChecker("getDefaultProps", true);
|
|
256
|
+
/** @deprecated Class components are legacy. */
|
|
257
|
+
const isGetDerivedStateFromProps = createLifecycleChecker("getDerivedStateFromProps", true);
|
|
258
|
+
/** @deprecated Class components are legacy. */
|
|
259
|
+
const isGetDerivedStateFromError = createLifecycleChecker("getDerivedStateFromError", true);
|
|
260
|
+
/**
|
|
261
|
+
* Check if the node is a render-like method of a class component.
|
|
262
|
+
* @param node The AST node to check.
|
|
263
|
+
* @returns `true` if the node is a render-like method.
|
|
264
|
+
* @deprecated Class components are legacy. This function exists only to support legacy rules.
|
|
265
|
+
*/
|
|
266
|
+
function isRenderMethodLike(node) {
|
|
267
|
+
return Check.isPropertyOrMethod(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name.startsWith("render") && Check.isOneOf([AST_NODE_TYPES.ClassDeclaration, AST_NODE_TYPES.ClassExpression])(node.parent.parent);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Check if the function is a callback passed to a class component's render method.
|
|
271
|
+
* @param node The function node to check.
|
|
272
|
+
* @returns `true` if the function is a render method callback.
|
|
273
|
+
*/
|
|
274
|
+
function isRenderMethodCallback(node) {
|
|
275
|
+
const parent = node.parent;
|
|
276
|
+
const greatGrandparent = parent.parent?.parent;
|
|
277
|
+
return greatGrandparent != null && isRenderMethodLike(parent) && isClassComponent(greatGrandparent);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Check if the call expression is a `this.setState(...)` call.
|
|
281
|
+
* @param node The call expression node to check.
|
|
282
|
+
* @returns `true` if the node is a `this.setState(...)` call.
|
|
283
|
+
* @deprecated Class components are legacy. This function exists only to support legacy rules.
|
|
284
|
+
*/
|
|
285
|
+
function isThisSetStateCall(node) {
|
|
286
|
+
const callee = Extract.unwrap(node.callee);
|
|
287
|
+
return callee.type === AST_NODE_TYPES.MemberExpression && callee.object.type === AST_NODE_TYPES.ThisExpression && Extract.getCalleeName(node) === "setState";
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Check if the assignment expression assigns to `this.state`.
|
|
291
|
+
* @param node The assignment expression node to check.
|
|
292
|
+
* @returns `true` if the node assigns to `this.state`.
|
|
293
|
+
* @deprecated Class components are legacy. This function exists only to support legacy rules.
|
|
294
|
+
*/
|
|
295
|
+
function isAssignmentToThisState(node) {
|
|
296
|
+
const { left } = node;
|
|
297
|
+
let current = Extract.unwrap(left);
|
|
298
|
+
while (current.type === AST_NODE_TYPES.MemberExpression) {
|
|
299
|
+
const { object, property } = current;
|
|
300
|
+
if (object.type === AST_NODE_TYPES.ThisExpression && property.type === AST_NODE_TYPES.Identifier && property.name === "state") return true;
|
|
301
|
+
current = Extract.unwrap(object);
|
|
302
|
+
}
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
//#endregion
|
|
307
|
+
//#region src/class-component-collector.ts
|
|
308
|
+
/**
|
|
309
|
+
* Get an api and visitor object for the rule to collect class components.
|
|
310
|
+
* @param context The rule context.
|
|
311
|
+
* @deprecated Class components are legacy. This function exists only to support legacy rules.
|
|
312
|
+
*/
|
|
313
|
+
function getClassComponentCollector(context) {
|
|
314
|
+
const components = /* @__PURE__ */ new Map();
|
|
315
|
+
const api = { getAllComponents(_) {
|
|
316
|
+
return [...components.values()];
|
|
317
|
+
} };
|
|
318
|
+
const getText = (n) => context.sourceCode.getText(n);
|
|
319
|
+
const collect = (node) => {
|
|
320
|
+
if (!isClassComponent(node)) return;
|
|
321
|
+
const id = getClassId(node);
|
|
322
|
+
const key = randomBytes(8).toString("hex");
|
|
323
|
+
const name = id == null ? null : Extract.getFullyQualifiedName(id, getText);
|
|
324
|
+
components.set(key, {
|
|
325
|
+
id,
|
|
326
|
+
key,
|
|
327
|
+
kind: "class-component",
|
|
328
|
+
name,
|
|
329
|
+
displayName: null,
|
|
330
|
+
flag: 0n,
|
|
331
|
+
hint: 0n,
|
|
332
|
+
methods: [],
|
|
333
|
+
node
|
|
334
|
+
});
|
|
335
|
+
};
|
|
336
|
+
return {
|
|
337
|
+
api,
|
|
338
|
+
visitor: {
|
|
339
|
+
ClassDeclaration: collect,
|
|
340
|
+
ClassExpression: collect
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
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
|
+
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region src/function.ts
|
|
436
|
+
/**
|
|
437
|
+
* Get the static identifier of a function AST node.
|
|
438
|
+
*
|
|
439
|
+
* @remarks
|
|
440
|
+
* For function declarations this is straightforward. For anonymous function
|
|
441
|
+
* expressions it is more complex. This function roughly detects the same AST
|
|
442
|
+
* nodes as the ECMAScript spec's `IsAnonymousFunctionDefinition()` with some
|
|
443
|
+
* exceptions to better fit our use case.
|
|
444
|
+
*
|
|
445
|
+
* Ported from {@link https://github.com/facebook/react/blob/bb8a76c6cc77ea2976d690ea09f5a1b3d9b1792a/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts#L860 | RulesOfHooks.ts}
|
|
446
|
+
*
|
|
447
|
+
* @param node The function node to analyze.
|
|
448
|
+
* @returns The identifier node if found, `null` otherwise.
|
|
449
|
+
*/
|
|
450
|
+
function getFunctionId(node) {
|
|
451
|
+
switch (true) {
|
|
452
|
+
case "id" in node && node.id != null: return node.id;
|
|
453
|
+
case node.parent.type === AST_NODE_TYPES.VariableDeclarator && node.parent.init === node: return node.parent.id;
|
|
454
|
+
case node.parent.type === AST_NODE_TYPES.AssignmentExpression && node.parent.right === node && node.parent.operator === "=": return node.parent.left;
|
|
455
|
+
case node.parent.type === AST_NODE_TYPES.Property && node.parent.value === node && !node.parent.computed: return node.parent.key;
|
|
456
|
+
case Check.isPropertyOrMethod(node.parent) && node.parent.value === node: return node.parent.key;
|
|
457
|
+
case node.parent.type === AST_NODE_TYPES.AssignmentPattern && node.parent.right === node: return node.parent.left;
|
|
458
|
+
case node.parent.type === AST_NODE_TYPES.ConditionalExpression: return getFunctionId(node.parent);
|
|
459
|
+
case Check.isTypeAssertionExpression(node.parent): return getFunctionId(node.parent);
|
|
460
|
+
}
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Get the initialization path of a function node in the AST.
|
|
465
|
+
*
|
|
466
|
+
* @param node The function node to analyze.
|
|
467
|
+
* @returns The function initialization path or `null` if not identifiable.
|
|
649
468
|
*/
|
|
650
|
-
function
|
|
651
|
-
if (node.
|
|
652
|
-
|
|
469
|
+
function getFunctionInitPath(node) {
|
|
470
|
+
if (node.type === AST_NODE_TYPES.FunctionDeclaration) return [node];
|
|
471
|
+
let parent = node.parent;
|
|
472
|
+
while (Check.isTypeExpression(parent)) parent = parent.parent;
|
|
473
|
+
switch (true) {
|
|
474
|
+
case parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
475
|
+
parent.parent,
|
|
476
|
+
parent,
|
|
477
|
+
node
|
|
478
|
+
];
|
|
479
|
+
case parent.type === AST_NODE_TYPES.CallExpression && parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
480
|
+
parent.parent.parent,
|
|
481
|
+
parent.parent,
|
|
482
|
+
parent,
|
|
483
|
+
node
|
|
484
|
+
];
|
|
485
|
+
case parent.type === AST_NODE_TYPES.CallExpression && parent.parent.type === AST_NODE_TYPES.CallExpression && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
486
|
+
parent.parent.parent.parent,
|
|
487
|
+
parent.parent.parent,
|
|
488
|
+
parent.parent,
|
|
489
|
+
parent,
|
|
490
|
+
node
|
|
491
|
+
];
|
|
492
|
+
case parent.type === AST_NODE_TYPES.Property && parent.parent.type === AST_NODE_TYPES.ObjectExpression && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
493
|
+
parent.parent.parent.parent,
|
|
494
|
+
parent.parent.parent,
|
|
495
|
+
parent.parent,
|
|
496
|
+
parent,
|
|
497
|
+
node
|
|
498
|
+
];
|
|
499
|
+
case parent.type === AST_NODE_TYPES.MethodDefinition: return [
|
|
500
|
+
parent.parent.parent,
|
|
501
|
+
parent.parent,
|
|
502
|
+
parent,
|
|
503
|
+
node
|
|
504
|
+
];
|
|
505
|
+
case parent.type === AST_NODE_TYPES.PropertyDefinition: return [
|
|
506
|
+
parent.parent.parent,
|
|
507
|
+
parent.parent,
|
|
508
|
+
parent,
|
|
509
|
+
node
|
|
510
|
+
];
|
|
511
|
+
}
|
|
653
512
|
return null;
|
|
654
513
|
}
|
|
655
|
-
|
|
656
|
-
//#endregion
|
|
657
|
-
//#region src/class-component.ts
|
|
658
514
|
/**
|
|
659
|
-
* Check if
|
|
660
|
-
*
|
|
661
|
-
* @
|
|
515
|
+
* Check if a specific function call exists in the function initialization path.
|
|
516
|
+
*
|
|
517
|
+
* @param callName The name of the call to check for (e.g., "memo", "forwardRef").
|
|
518
|
+
* @param initPath The function initialization path to search in.
|
|
519
|
+
* @returns `true` if the call exists in the path, `false` otherwise.
|
|
662
520
|
*/
|
|
663
|
-
function
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
}
|
|
671
|
-
return false;
|
|
521
|
+
function isFunctionHasCallInInitPath(callName, initPath) {
|
|
522
|
+
return initPath.some((node) => {
|
|
523
|
+
if (node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
524
|
+
const callee = Extract.unwrap(node.callee);
|
|
525
|
+
if (callee.type === AST_NODE_TYPES.Identifier) return callee.name === callName;
|
|
526
|
+
if (callee.type === AST_NODE_TYPES.MemberExpression && "name" in callee.property) return callee.property.name === callName;
|
|
527
|
+
return false;
|
|
528
|
+
});
|
|
672
529
|
}
|
|
673
530
|
/**
|
|
674
|
-
* Check if
|
|
675
|
-
*
|
|
676
|
-
* @
|
|
677
|
-
* @
|
|
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.
|
|
678
535
|
*/
|
|
679
|
-
function
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
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;
|
|
686
549
|
}
|
|
687
|
-
|
|
550
|
+
for (const stmt of node.body.body) {
|
|
551
|
+
if (!isDirective(stmt)) continue;
|
|
552
|
+
directives.push(stmt);
|
|
553
|
+
}
|
|
554
|
+
return directives;
|
|
688
555
|
}
|
|
689
|
-
|
|
690
|
-
|
|
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);
|
|
691
565
|
}
|
|
692
|
-
/**
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
/**
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
const
|
|
706
|
-
/**
|
|
707
|
-
|
|
708
|
-
/**
|
|
709
|
-
|
|
710
|
-
/**
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
|
|
714
|
-
/**
|
|
715
|
-
|
|
716
|
-
/**
|
|
717
|
-
|
|
718
|
-
/**
|
|
719
|
-
|
|
720
|
-
/**
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
|
|
726
|
-
/**
|
|
727
|
-
|
|
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
|
|
728
678
|
/**
|
|
729
|
-
*
|
|
730
|
-
* @param node The AST node to check.
|
|
731
|
-
* @returns `true` if the node is a render-like method.
|
|
732
|
-
* @deprecated Class components are legacy. This function exists only to support legacy rules.
|
|
679
|
+
* Component flag constants.
|
|
733
680
|
*/
|
|
734
|
-
|
|
735
|
-
|
|
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;
|
|
736
704
|
}
|
|
737
705
|
/**
|
|
738
|
-
* Check if the
|
|
739
|
-
* @param
|
|
740
|
-
* @
|
|
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.
|
|
741
710
|
*/
|
|
742
|
-
function
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
return greatGrandparent != null && isRenderMethodLike(parent) && isClassComponent(greatGrandparent);
|
|
711
|
+
function isFunctionComponentWrapperCall(context, node) {
|
|
712
|
+
if (node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
713
|
+
return isMemoCall(context, node) || isForwardRefCall(context, node);
|
|
746
714
|
}
|
|
747
715
|
/**
|
|
748
|
-
* Check if the
|
|
749
|
-
* @param
|
|
750
|
-
* @
|
|
751
|
-
* @
|
|
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.
|
|
752
720
|
*/
|
|
753
|
-
function
|
|
754
|
-
|
|
755
|
-
|
|
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);
|
|
756
727
|
}
|
|
757
728
|
/**
|
|
758
|
-
*
|
|
759
|
-
* @param
|
|
760
|
-
* @
|
|
761
|
-
* @
|
|
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
|
|
762
733
|
*/
|
|
763
|
-
function
|
|
764
|
-
const
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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;
|
|
770
743
|
}
|
|
771
|
-
return false;
|
|
772
744
|
}
|
|
773
|
-
|
|
774
|
-
//#endregion
|
|
775
|
-
//#region src/class-component-collector.ts
|
|
776
745
|
/**
|
|
777
|
-
*
|
|
778
|
-
* @param
|
|
779
|
-
* @
|
|
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.
|
|
780
749
|
*/
|
|
781
|
-
function
|
|
782
|
-
|
|
783
|
-
const api = { getAllComponents(_) {
|
|
784
|
-
return [...components.values()];
|
|
785
|
-
} };
|
|
786
|
-
const getText = (n) => context.sourceCode.getText(n);
|
|
787
|
-
const collect = (node) => {
|
|
788
|
-
if (!isClassComponent(node)) return;
|
|
789
|
-
const id = getClassId(node);
|
|
790
|
-
const key = randomBytes(8).toString("hex");
|
|
791
|
-
const name = id == null ? null : Extract.getFullyQualifiedName(id, getText);
|
|
792
|
-
components.set(key, {
|
|
793
|
-
id,
|
|
794
|
-
key,
|
|
795
|
-
kind: "class-component",
|
|
796
|
-
name,
|
|
797
|
-
displayName: null,
|
|
798
|
-
flag: 0n,
|
|
799
|
-
hint: 0n,
|
|
800
|
-
methods: [],
|
|
801
|
-
node
|
|
802
|
-
});
|
|
803
|
-
};
|
|
804
|
-
return {
|
|
805
|
-
api,
|
|
806
|
-
visitor: {
|
|
807
|
-
ClassDeclaration: collect,
|
|
808
|
-
ClassExpression: collect
|
|
809
|
-
}
|
|
810
|
-
};
|
|
750
|
+
function isFunctionComponentName(name) {
|
|
751
|
+
return RE_COMPONENT_NAME.test(name);
|
|
811
752
|
}
|
|
812
|
-
|
|
813
|
-
//#endregion
|
|
814
|
-
//#region src/function.ts
|
|
815
753
|
/**
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
* @
|
|
819
|
-
* For function declarations this is straightforward. For anonymous function
|
|
820
|
-
* expressions it is more complex. This function roughly detects the same AST
|
|
821
|
-
* nodes as the ECMAScript spec's `IsAnonymousFunctionDefinition()` with some
|
|
822
|
-
* exceptions to better fit our use case.
|
|
823
|
-
*
|
|
824
|
-
* Ported from {@link https://github.com/facebook/react/blob/bb8a76c6cc77ea2976d690ea09f5a1b3d9b1792a/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts#L860 | RulesOfHooks.ts}
|
|
825
|
-
*
|
|
826
|
-
* @param node The function node to analyze.
|
|
827
|
-
* @returns The identifier node if found, `null` otherwise.
|
|
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.
|
|
828
757
|
*/
|
|
829
|
-
function
|
|
830
|
-
|
|
831
|
-
case "id" in node && node.id != null: return node.id;
|
|
832
|
-
case node.parent.type === AST_NODE_TYPES.VariableDeclarator && node.parent.init === node: return node.parent.id;
|
|
833
|
-
case node.parent.type === AST_NODE_TYPES.AssignmentExpression && node.parent.right === node && node.parent.operator === "=": return node.parent.left;
|
|
834
|
-
case node.parent.type === AST_NODE_TYPES.Property && node.parent.value === node && !node.parent.computed: return node.parent.key;
|
|
835
|
-
case Check.isPropertyOrMethod(node.parent) && node.parent.value === node: return node.parent.key;
|
|
836
|
-
case node.parent.type === AST_NODE_TYPES.AssignmentPattern && node.parent.right === node: return node.parent.left;
|
|
837
|
-
case node.parent.type === AST_NODE_TYPES.ConditionalExpression: return getFunctionId(node.parent);
|
|
838
|
-
case Check.isTypeAssertionExpression(node.parent): return getFunctionId(node.parent);
|
|
839
|
-
}
|
|
840
|
-
return null;
|
|
758
|
+
function isFunctionComponentNameLoose(name) {
|
|
759
|
+
return RE_COMPONENT_NAME_LOOSE.test(name);
|
|
841
760
|
}
|
|
842
761
|
/**
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
* @param
|
|
846
|
-
* @
|
|
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.
|
|
847
767
|
*/
|
|
848
|
-
function
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
parent.parent,
|
|
855
|
-
parent,
|
|
856
|
-
node
|
|
857
|
-
];
|
|
858
|
-
case parent.type === AST_NODE_TYPES.CallExpression && parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
859
|
-
parent.parent.parent,
|
|
860
|
-
parent.parent,
|
|
861
|
-
parent,
|
|
862
|
-
node
|
|
863
|
-
];
|
|
864
|
-
case parent.type === AST_NODE_TYPES.CallExpression && parent.parent.type === AST_NODE_TYPES.CallExpression && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
865
|
-
parent.parent.parent.parent,
|
|
866
|
-
parent.parent.parent,
|
|
867
|
-
parent.parent,
|
|
868
|
-
parent,
|
|
869
|
-
node
|
|
870
|
-
];
|
|
871
|
-
case parent.type === AST_NODE_TYPES.Property && parent.parent.type === AST_NODE_TYPES.ObjectExpression && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator: return [
|
|
872
|
-
parent.parent.parent.parent,
|
|
873
|
-
parent.parent.parent,
|
|
874
|
-
parent.parent,
|
|
875
|
-
parent,
|
|
876
|
-
node
|
|
877
|
-
];
|
|
878
|
-
case parent.type === AST_NODE_TYPES.MethodDefinition: return [
|
|
879
|
-
parent.parent.parent,
|
|
880
|
-
parent.parent,
|
|
881
|
-
parent,
|
|
882
|
-
node
|
|
883
|
-
];
|
|
884
|
-
case parent.type === AST_NODE_TYPES.PropertyDefinition: return [
|
|
885
|
-
parent.parent.parent,
|
|
886
|
-
parent.parent,
|
|
887
|
-
parent,
|
|
888
|
-
node
|
|
889
|
-
];
|
|
890
|
-
}
|
|
891
|
-
return null;
|
|
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;
|
|
892
774
|
}
|
|
893
775
|
/**
|
|
894
|
-
*
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
776
|
+
* Hints for component collector.
|
|
777
|
+
*/
|
|
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
|
+
};
|
|
797
|
+
/**
|
|
798
|
+
* Default component detection hint.
|
|
899
799
|
*/
|
|
900
|
-
|
|
901
|
-
return initPath.some((node) => {
|
|
902
|
-
if (node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
903
|
-
const callee = Extract.unwrap(node.callee);
|
|
904
|
-
if (callee.type === AST_NODE_TYPES.Identifier) return callee.name === callName;
|
|
905
|
-
if (callee.type === AST_NODE_TYPES.MemberExpression && "name" in callee.property) return callee.property.name === callName;
|
|
906
|
-
return false;
|
|
907
|
-
});
|
|
908
|
-
}
|
|
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;
|
|
909
801
|
/**
|
|
910
|
-
* Check if
|
|
802
|
+
* Check if the function node is a valid React component definition.
|
|
911
803
|
*
|
|
912
|
-
* @param
|
|
913
|
-
* @
|
|
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.
|
|
914
808
|
*/
|
|
915
|
-
function
|
|
916
|
-
|
|
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;
|
|
917
850
|
}
|
|
851
|
+
|
|
852
|
+
//#endregion
|
|
853
|
+
//#region ../../.pkgs/eff/dist/index.js
|
|
918
854
|
/**
|
|
919
|
-
*
|
|
920
|
-
*
|
|
921
|
-
*
|
|
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
|
|
922
891
|
*/
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
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
|
+
}
|
|
932
909
|
}
|
|
933
|
-
|
|
934
|
-
}
|
|
910
|
+
};
|
|
935
911
|
/**
|
|
936
|
-
*
|
|
912
|
+
* Reusable prototype that implements `Pipeable.pipe`.
|
|
937
913
|
*
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
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
|
|
941
921
|
*/
|
|
942
|
-
|
|
943
|
-
return
|
|
944
|
-
}
|
|
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
|
-
|
|
953
|
-
//#endregion
|
|
954
|
-
//#region src/jsx.ts
|
|
922
|
+
const Prototype = { pipe() {
|
|
923
|
+
return pipeArguments(this, arguments);
|
|
924
|
+
} };
|
|
955
925
|
/**
|
|
956
|
-
*
|
|
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
|
|
957
936
|
*/
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
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
|
|
983
|
-
};
|
|
937
|
+
const Class = (function() {
|
|
938
|
+
function PipeableBase() {}
|
|
939
|
+
PipeableBase.prototype = Prototype;
|
|
940
|
+
return PipeableBase;
|
|
941
|
+
})();
|
|
984
942
|
/**
|
|
985
|
-
*
|
|
943
|
+
* Provides small helpers for defining and reusing TypeScript functions.
|
|
986
944
|
*
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
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
|
|
990
951
|
*/
|
|
991
|
-
const DEFAULT_JSX_DETECTION_HINT = 0n | JsxDetectionHint.DoNotIncludeJsxWithNumberValue | JsxDetectionHint.DoNotIncludeJsxWithBigIntValue | JsxDetectionHint.DoNotIncludeJsxWithBooleanValue | JsxDetectionHint.DoNotIncludeJsxWithStringValue | JsxDetectionHint.DoNotIncludeJsxWithUndefinedValue;
|
|
992
952
|
/**
|
|
993
|
-
*
|
|
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
|
-
*
|
|
996
|
-
*
|
|
983
|
+
* ```ts
|
|
984
|
+
* import { Function, pipe } from "effect"
|
|
997
985
|
*
|
|
998
|
-
*
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
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
|
-
*
|
|
1003
|
-
*
|
|
1004
|
-
*
|
|
1005
|
-
*
|
|
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 {
|
|
998
|
+
* import { Function, pipe } from "effect"
|
|
1010
999
|
*
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
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
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
return
|
|
1040
|
-
|
|
1041
|
-
|
|
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
|
-
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
//#endregion
|
|
1056
|
-
//#region src/function-component.ts
|
|
1042
|
+
};
|
|
1057
1043
|
/**
|
|
1058
|
-
*
|
|
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
|
|
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
|
-
*
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
1076
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
1086
|
-
*
|
|
1087
|
-
*
|
|
1088
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
1096
|
-
*
|
|
1097
|
-
*
|
|
1098
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
1109
|
-
*
|
|
1110
|
-
*
|
|
1111
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
1126
|
-
*
|
|
1127
|
-
*
|
|
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
|
-
|
|
1130
|
-
return RE_COMPONENT_NAME.test(name);
|
|
1131
|
-
}
|
|
1165
|
+
const constNull = constant(null);
|
|
1132
1166
|
/**
|
|
1133
|
-
*
|
|
1134
|
-
*
|
|
1135
|
-
*
|
|
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
|
-
|
|
1138
|
-
return RE_COMPONENT_NAME_LOOSE.test(name);
|
|
1139
|
-
}
|
|
1185
|
+
const constUndefined = constant(void 0);
|
|
1140
1186
|
/**
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1143
|
-
*
|
|
1144
|
-
*
|
|
1145
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
1158
|
-
|
|
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
|
-
*
|
|
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
|
|
1272
|
+
const hole = cast(absurd);
|
|
1180
1273
|
/**
|
|
1181
|
-
*
|
|
1274
|
+
* Drops the longest prefix of elements from an array that satisfy the given predicate.
|
|
1182
1275
|
*
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1185
|
-
* @param
|
|
1186
|
-
* @returns
|
|
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
|
-
|
|
1189
|
-
|
|
1190
|
-
let
|
|
1191
|
-
while (
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
AST_NODE_TYPES.JSXExpressionContainer,
|
|
1221
|
-
AST_NODE_TYPES.ArrowFunctionExpression,
|
|
1222
|
-
AST_NODE_TYPES.FunctionExpression,
|
|
1223
|
-
AST_NODE_TYPES.Property,
|
|
1224
|
-
AST_NODE_TYPES.ClassBody
|
|
1225
|
-
]));
|
|
1226
|
-
if (significantParent == null) return true;
|
|
1227
|
-
if (significantParent.type === AST_NODE_TYPES.JSXExpressionContainer) return false;
|
|
1228
|
-
return true;
|
|
1229
|
-
}
|
|
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
|
+
});
|
|
1230
1325
|
|
|
1231
1326
|
//#endregion
|
|
1232
1327
|
//#region src/hook.ts
|
|
@@ -1832,4 +1927,4 @@ function getTypeVariants(types) {
|
|
|
1832
1927
|
}
|
|
1833
1928
|
|
|
1834
1929
|
//#endregion
|
|
1835
|
-
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 };
|