@eslint-react/core 5.16.0 → 5.17.0
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 +130 -131
- package/dist/index.js +425 -130
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -9,28 +9,124 @@ import { P, isMatching, match } from "ts-pattern";
|
|
|
9
9
|
|
|
10
10
|
//#region ../../.pkgs/eff/dist/index.js
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Applies a `pipe` method's variadic arguments to an initial value from left
|
|
13
|
+
* to right.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* or a predicate that determines if the function is being used in a data-first
|
|
17
|
-
* or data-last style.
|
|
15
|
+
* **When to use**
|
|
18
16
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* takes an optional argument, you can use a predicate to determine if the
|
|
22
|
-
* function is being used in a data-first or data-last style.
|
|
17
|
+
* Use to implement a custom `.pipe(...)` method from JavaScript's `arguments`
|
|
18
|
+
* object.
|
|
23
19
|
*
|
|
24
|
-
*
|
|
25
|
-
* which determines if the function is being used in a data-first or
|
|
26
|
-
* data-last style.
|
|
20
|
+
* **Details**
|
|
27
21
|
*
|
|
28
|
-
*
|
|
22
|
+
* This helper is intended for implementing `Pipeable.pipe` methods that
|
|
23
|
+
* receive JavaScript's `arguments` object. With no functions it returns the
|
|
24
|
+
* original value; otherwise it feeds each result into the next function.
|
|
25
|
+
*
|
|
26
|
+
* **Example** (Implementing a pipe method)
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { Pipeable } from "effect"
|
|
30
|
+
*
|
|
31
|
+
* class NumberBox {
|
|
32
|
+
* constructor(readonly value: number) {}
|
|
33
|
+
*
|
|
34
|
+
* pipe(..._fns: ReadonlyArray<(value: number) => number>): number {
|
|
35
|
+
* return Pipeable.pipeArguments(this.value, arguments) as number
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* const result = new NumberBox(5).pipe(
|
|
40
|
+
* (n) => n + 2,
|
|
41
|
+
* (n) => n * 3
|
|
42
|
+
* )
|
|
43
|
+
* console.log(result) // 21
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @category combinators
|
|
47
|
+
* @since 2.0.0
|
|
48
|
+
*/
|
|
49
|
+
const pipeArguments = (self, args) => {
|
|
50
|
+
switch (args.length) {
|
|
51
|
+
case 0: return self;
|
|
52
|
+
case 1: return args[0](self);
|
|
53
|
+
case 2: return args[1](args[0](self));
|
|
54
|
+
case 3: return args[2](args[1](args[0](self)));
|
|
55
|
+
case 4: return args[3](args[2](args[1](args[0](self))));
|
|
56
|
+
case 5: return args[4](args[3](args[2](args[1](args[0](self)))));
|
|
57
|
+
case 6: return args[5](args[4](args[3](args[2](args[1](args[0](self))))));
|
|
58
|
+
case 7: return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))));
|
|
59
|
+
case 8: return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))));
|
|
60
|
+
case 9: return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))));
|
|
61
|
+
default: {
|
|
62
|
+
let ret = self;
|
|
63
|
+
for (let i = 0, len = args.length; i < len; i++) ret = args[i](ret);
|
|
64
|
+
return ret;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Reusable prototype that implements `Pipeable.pipe`.
|
|
70
|
+
*
|
|
71
|
+
* **When to use**
|
|
72
|
+
*
|
|
73
|
+
* Use when classes or object prototypes can reuse this value when they need the
|
|
74
|
+
* standard pipe implementation backed by `pipeArguments`.
|
|
75
|
+
*
|
|
76
|
+
* @category prototypes
|
|
77
|
+
* @since 3.15.0
|
|
78
|
+
*/
|
|
79
|
+
const Prototype = { pipe() {
|
|
80
|
+
return pipeArguments(this, arguments);
|
|
81
|
+
} };
|
|
82
|
+
/**
|
|
83
|
+
* Provides a base constructor whose instances implement the standard `Pipeable.pipe`
|
|
84
|
+
* method.
|
|
85
|
+
*
|
|
86
|
+
* **When to use**
|
|
87
|
+
*
|
|
88
|
+
* Use when you need to define a class that supports Effect-style method
|
|
89
|
+
* chaining through `.pipe(...)`.
|
|
90
|
+
*
|
|
91
|
+
* @category constructors
|
|
92
|
+
* @since 3.15.0
|
|
93
|
+
*/
|
|
94
|
+
const Class = (function() {
|
|
95
|
+
function PipeableBase() {}
|
|
96
|
+
PipeableBase.prototype = Prototype;
|
|
97
|
+
return PipeableBase;
|
|
98
|
+
})();
|
|
99
|
+
/**
|
|
100
|
+
* Provides small helpers for defining and reusing TypeScript functions.
|
|
101
|
+
*
|
|
102
|
+
* The main helpers are `pipe` and `flow` for left-to-right composition and
|
|
103
|
+
* `dual` for APIs that support both direct and pipe-friendly call styles. The
|
|
104
|
+
* module also contains small identity, constant, tuple, type-level, and
|
|
105
|
+
* memoization helpers used across the library.
|
|
106
|
+
*
|
|
107
|
+
* @since 2.0.0
|
|
108
|
+
*/
|
|
109
|
+
/**
|
|
110
|
+
* Creates a function that can be called in data-first style or data-last
|
|
111
|
+
* (`pipe`-friendly) style.
|
|
112
|
+
*
|
|
113
|
+
* **When to use**
|
|
114
|
+
*
|
|
115
|
+
* Use to expose one implementation through both direct and `pipe`-friendly
|
|
116
|
+
* call styles.
|
|
117
|
+
*
|
|
118
|
+
* **Details**
|
|
119
|
+
*
|
|
120
|
+
* Pass either the arity of the uncurried function or a predicate that decides
|
|
121
|
+
* whether the current call is data-first. Arity is the common case. Use a
|
|
122
|
+
* predicate when optional arguments make arity ambiguous.
|
|
123
|
+
*
|
|
124
|
+
* **Example** (Selecting data-first or data-last style by arity)
|
|
29
125
|
*
|
|
30
126
|
* ```ts
|
|
31
|
-
* import {
|
|
127
|
+
* import { Function, pipe } from "effect"
|
|
32
128
|
*
|
|
33
|
-
* const sum = dual<
|
|
129
|
+
* const sum = Function.dual<
|
|
34
130
|
* (that: number) => (self: number) => number,
|
|
35
131
|
* (self: number, that: number) => number
|
|
36
132
|
* >(2, (self, that) => self + that)
|
|
@@ -39,26 +135,26 @@ import { P, isMatching, match } from "ts-pattern";
|
|
|
39
135
|
* console.log(pipe(2, sum(3))) // 5
|
|
40
136
|
* ```
|
|
41
137
|
*
|
|
42
|
-
* **Example** (
|
|
138
|
+
* **Example** (Defining overloads with call signatures)
|
|
43
139
|
*
|
|
44
140
|
* ```ts
|
|
45
|
-
* import {
|
|
141
|
+
* import { Function, pipe } from "effect"
|
|
46
142
|
*
|
|
47
143
|
* const sum: {
|
|
48
144
|
* (that: number): (self: number) => number
|
|
49
145
|
* (self: number, that: number): number
|
|
50
|
-
* } = dual(2, (self: number, that: number): number => self + that)
|
|
146
|
+
* } = Function.dual(2, (self: number, that: number): number => self + that)
|
|
51
147
|
*
|
|
52
148
|
* console.log(sum(2, 3)) // 5
|
|
53
149
|
* console.log(pipe(2, sum(3))) // 5
|
|
54
150
|
* ```
|
|
55
151
|
*
|
|
56
|
-
* **Example** (
|
|
152
|
+
* **Example** (Selecting data-first or data-last style with a predicate)
|
|
57
153
|
*
|
|
58
154
|
* ```ts
|
|
59
|
-
* import {
|
|
155
|
+
* import { Function, pipe } from "effect"
|
|
60
156
|
*
|
|
61
|
-
* const sum = dual<
|
|
157
|
+
* const sum = Function.dual<
|
|
62
158
|
* (that: number) => (self: number) => number,
|
|
63
159
|
* (self: number, that: number) => number
|
|
64
160
|
* >(
|
|
@@ -70,9 +166,8 @@ import { P, isMatching, match } from "ts-pattern";
|
|
|
70
166
|
* console.log(pipe(2, sum(3))) // 5
|
|
71
167
|
* ```
|
|
72
168
|
*
|
|
73
|
-
* @
|
|
74
|
-
* @
|
|
75
|
-
* @since 1.0.0
|
|
169
|
+
* @category combinators
|
|
170
|
+
* @since 2.0.0
|
|
76
171
|
*/
|
|
77
172
|
const dual = function(arity, body) {
|
|
78
173
|
if (typeof arity === "function") return function() {
|
|
@@ -103,41 +198,242 @@ const dual = function(arity, body) {
|
|
|
103
198
|
}
|
|
104
199
|
};
|
|
105
200
|
/**
|
|
106
|
-
*
|
|
201
|
+
* Returns its input argument unchanged.
|
|
107
202
|
*
|
|
108
|
-
*
|
|
203
|
+
* **When to use**
|
|
204
|
+
*
|
|
205
|
+
* Use to return a value unchanged where a function is required.
|
|
206
|
+
*
|
|
207
|
+
* **Example** (Returning the same value)
|
|
208
|
+
*
|
|
209
|
+
* ```ts
|
|
210
|
+
* import { identity } from "effect"
|
|
211
|
+
* import * as assert from "node:assert"
|
|
212
|
+
*
|
|
213
|
+
* assert.deepStrictEqual(identity(5), 5)
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* @category combinators
|
|
217
|
+
* @since 2.0.0
|
|
109
218
|
*/
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
219
|
+
const identity = (a) => a;
|
|
220
|
+
/**
|
|
221
|
+
* Returns the input value with a different static type.
|
|
222
|
+
*
|
|
223
|
+
* **When to use**
|
|
224
|
+
*
|
|
225
|
+
* Use when you need an explicit type-level cast and accept that the value is
|
|
226
|
+
* returned unchanged at runtime.
|
|
227
|
+
*
|
|
228
|
+
* **Gotchas**
|
|
229
|
+
*
|
|
230
|
+
* This is a type-level cast only; it performs no runtime validation or
|
|
231
|
+
* conversion.
|
|
232
|
+
*
|
|
233
|
+
* @see {@link satisfies} for checking assignability without changing the resulting type
|
|
234
|
+
*
|
|
235
|
+
* @category utility types
|
|
236
|
+
* @since 4.0.0
|
|
237
|
+
*/
|
|
238
|
+
const cast = identity;
|
|
239
|
+
/**
|
|
240
|
+
* Creates a zero-argument function that always returns the provided value.
|
|
241
|
+
*
|
|
242
|
+
* **When to use**
|
|
243
|
+
*
|
|
244
|
+
* Use when you need a thunk or callback that returns the same value on every
|
|
245
|
+
* invocation.
|
|
246
|
+
*
|
|
247
|
+
* **Example** (Creating a constant thunk)
|
|
248
|
+
*
|
|
249
|
+
* ```ts
|
|
250
|
+
* import { Function } from "effect"
|
|
251
|
+
* import * as assert from "node:assert"
|
|
252
|
+
*
|
|
253
|
+
* const constNull = Function.constant(null)
|
|
254
|
+
*
|
|
255
|
+
* assert.deepStrictEqual(constNull(), null)
|
|
256
|
+
* assert.deepStrictEqual(constNull(), null)
|
|
257
|
+
* ```
|
|
258
|
+
*
|
|
259
|
+
* @category constructors
|
|
260
|
+
* @since 2.0.0
|
|
261
|
+
*/
|
|
262
|
+
const constant = (value) => () => value;
|
|
263
|
+
/**
|
|
264
|
+
* Returns `true` when called.
|
|
265
|
+
*
|
|
266
|
+
* **When to use**
|
|
267
|
+
*
|
|
268
|
+
* Use when you need a thunk that returns `true` on every invocation.
|
|
269
|
+
*
|
|
270
|
+
* **Example** (Returning true from a thunk)
|
|
271
|
+
*
|
|
272
|
+
* ```ts
|
|
273
|
+
* import { Function } from "effect"
|
|
274
|
+
* import * as assert from "node:assert"
|
|
275
|
+
*
|
|
276
|
+
* assert.deepStrictEqual(Function.constTrue(), true)
|
|
277
|
+
* ```
|
|
278
|
+
*
|
|
279
|
+
* @category constants
|
|
280
|
+
* @since 2.0.0
|
|
281
|
+
*/
|
|
282
|
+
const constTrue = constant(true);
|
|
283
|
+
/**
|
|
284
|
+
* Returns `false` when called.
|
|
285
|
+
*
|
|
286
|
+
* **When to use**
|
|
287
|
+
*
|
|
288
|
+
* Use when you need a thunk that returns `false` on every invocation.
|
|
289
|
+
*
|
|
290
|
+
* **Example** (Returning false from a thunk)
|
|
291
|
+
*
|
|
292
|
+
* ```ts
|
|
293
|
+
* import { Function } from "effect"
|
|
294
|
+
* import * as assert from "node:assert"
|
|
295
|
+
*
|
|
296
|
+
* assert.deepStrictEqual(Function.constFalse(), false)
|
|
297
|
+
* ```
|
|
298
|
+
*
|
|
299
|
+
* @category constants
|
|
300
|
+
* @since 2.0.0
|
|
301
|
+
*/
|
|
302
|
+
const constFalse = constant(false);
|
|
303
|
+
/**
|
|
304
|
+
* Returns `null` when called.
|
|
305
|
+
*
|
|
306
|
+
* **When to use**
|
|
307
|
+
*
|
|
308
|
+
* Use when you need a thunk that returns `null` on every invocation.
|
|
309
|
+
*
|
|
310
|
+
* **Example** (Returning null from a thunk)
|
|
311
|
+
*
|
|
312
|
+
* ```ts
|
|
313
|
+
* import { Function } from "effect"
|
|
314
|
+
* import * as assert from "node:assert"
|
|
315
|
+
*
|
|
316
|
+
* assert.deepStrictEqual(Function.constNull(), null)
|
|
317
|
+
* ```
|
|
318
|
+
*
|
|
319
|
+
* @category constants
|
|
320
|
+
* @since 2.0.0
|
|
321
|
+
*/
|
|
322
|
+
const constNull = constant(null);
|
|
323
|
+
/**
|
|
324
|
+
* Returns `undefined` when called.
|
|
325
|
+
*
|
|
326
|
+
* **When to use**
|
|
327
|
+
*
|
|
328
|
+
* Use when you need a thunk that returns `undefined` on every invocation.
|
|
329
|
+
*
|
|
330
|
+
* **Example** (Returning undefined from a thunk)
|
|
331
|
+
*
|
|
332
|
+
* ```ts
|
|
333
|
+
* import { Function } from "effect"
|
|
334
|
+
* import * as assert from "node:assert"
|
|
335
|
+
*
|
|
336
|
+
* assert.deepStrictEqual(Function.constUndefined(), undefined)
|
|
337
|
+
* ```
|
|
338
|
+
*
|
|
339
|
+
* @category constants
|
|
340
|
+
* @since 2.0.0
|
|
341
|
+
*/
|
|
342
|
+
const constUndefined = constant(void 0);
|
|
113
343
|
/**
|
|
114
344
|
* 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`.
|
|
115
345
|
* The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`.
|
|
116
346
|
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
347
|
+
* **When to use**
|
|
348
|
+
*
|
|
349
|
+
* Use to compose exactly two unary functions into a reusable unary function.
|
|
350
|
+
*
|
|
351
|
+
* **Example** (Composing two functions)
|
|
352
|
+
*
|
|
121
353
|
* ```ts
|
|
354
|
+
* import { Function } from "effect"
|
|
122
355
|
* import * as assert from "node:assert"
|
|
123
|
-
* import { compose } from "effect/Function"
|
|
124
356
|
*
|
|
125
|
-
* const increment = (n: number) => n + 1
|
|
126
|
-
* const square = (n: number) => n * n
|
|
357
|
+
* const increment = (n: number) => n + 1
|
|
358
|
+
* const square = (n: number) => n * n
|
|
127
359
|
*
|
|
128
|
-
* assert.strictEqual(compose(increment, square)(2), 9)
|
|
360
|
+
* assert.strictEqual(Function.compose(increment, square)(2), 9)
|
|
129
361
|
* ```
|
|
130
362
|
*
|
|
131
|
-
* @
|
|
363
|
+
* @see {@link flow} for composing a left-to-right sequence of functions
|
|
364
|
+
* @see {@link pipe} for applying a value through a left-to-right sequence immediately
|
|
365
|
+
*
|
|
366
|
+
* @category combinators
|
|
367
|
+
* @since 2.0.0
|
|
132
368
|
*/
|
|
133
369
|
const compose = dual(2, (ab, bc) => (a) => bc(ab(a)));
|
|
370
|
+
/**
|
|
371
|
+
* Marks an impossible branch by accepting a `never` value and returning any
|
|
372
|
+
* type.
|
|
373
|
+
*
|
|
374
|
+
* **When to use**
|
|
375
|
+
*
|
|
376
|
+
* Use when you need a return value in a branch that exhaustive checks prove
|
|
377
|
+
* cannot be reached.
|
|
378
|
+
*
|
|
379
|
+
* **Gotchas**
|
|
380
|
+
*
|
|
381
|
+
* Calling `absurd` throws, because a value of type `never` should be
|
|
382
|
+
* impossible at runtime.
|
|
383
|
+
*
|
|
384
|
+
* **Example** (Handling impossible values)
|
|
385
|
+
*
|
|
386
|
+
* ```ts
|
|
387
|
+
* import { absurd } from "effect"
|
|
388
|
+
*
|
|
389
|
+
* const handleNever = (value: never) => {
|
|
390
|
+
* return absurd(value) // This will throw an error if called
|
|
391
|
+
* }
|
|
392
|
+
* ```
|
|
393
|
+
*
|
|
394
|
+
* @category utility types
|
|
395
|
+
* @since 2.0.0
|
|
396
|
+
*/
|
|
397
|
+
const absurd = (_) => {
|
|
398
|
+
throw new Error("Called `absurd` function which should be uncallable");
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* Creates a compile-time placeholder for a value of any type.
|
|
402
|
+
*
|
|
403
|
+
* **When to use**
|
|
404
|
+
*
|
|
405
|
+
* Use as a temporary typed placeholder while developing incomplete code.
|
|
406
|
+
*
|
|
407
|
+
* **Gotchas**
|
|
408
|
+
*
|
|
409
|
+
* `hole` is intended for temporary development use. If the placeholder is
|
|
410
|
+
* evaluated at runtime, it throws.
|
|
411
|
+
*
|
|
412
|
+
* **Example** (Creating a development placeholder)
|
|
413
|
+
*
|
|
414
|
+
* ```ts
|
|
415
|
+
* import { hole } from "effect"
|
|
416
|
+
*
|
|
417
|
+
* // Intentionally not called: `hole` throws if the placeholder is evaluated.
|
|
418
|
+
* const buildUser = (id: number): { readonly id: number; readonly name: string } => ({
|
|
419
|
+
* id,
|
|
420
|
+
* name: hole<string>()
|
|
421
|
+
* })
|
|
422
|
+
*
|
|
423
|
+
* console.log(typeof buildUser) // "function"
|
|
424
|
+
* ```
|
|
425
|
+
*
|
|
426
|
+
* @category utility types
|
|
427
|
+
* @since 2.0.0
|
|
428
|
+
*/
|
|
429
|
+
const hole = cast(absurd);
|
|
134
430
|
|
|
135
431
|
//#endregion
|
|
136
432
|
//#region src/api.ts
|
|
137
433
|
/**
|
|
138
|
-
* Check if the node is a React API identifier or member expression
|
|
139
|
-
* @param api The React API name to check against (ex: "useState", "React.memo")
|
|
140
|
-
* @returns A predicate function to check if a node matches the API
|
|
434
|
+
* Check if the node is a React API identifier or member expression.
|
|
435
|
+
* @param api The React API name to check against (ex: "useState", "React.memo").
|
|
436
|
+
* @returns A predicate function to check if a node matches the API.
|
|
141
437
|
*/
|
|
142
438
|
function isAPI(api) {
|
|
143
439
|
const func = (context, node) => {
|
|
@@ -152,9 +448,9 @@ function isAPI(api) {
|
|
|
152
448
|
return dual(2, func);
|
|
153
449
|
}
|
|
154
450
|
/**
|
|
155
|
-
* Check if the node is a call expression to a specific React API
|
|
156
|
-
* @param api The React API name to check against
|
|
157
|
-
* @returns A predicate function to check if a node is a call to the API
|
|
451
|
+
* Check if the node is a call expression to a specific React API.
|
|
452
|
+
* @param api The React API name to check against.
|
|
453
|
+
* @returns A predicate function to check if a node is a call to the API.
|
|
158
454
|
*/
|
|
159
455
|
function isAPICall(api) {
|
|
160
456
|
const func = (context, node) => {
|
|
@@ -232,9 +528,9 @@ const isUseTransitionCall = isAPICall("useTransition");
|
|
|
232
528
|
//#endregion
|
|
233
529
|
//#region src/class.ts
|
|
234
530
|
/**
|
|
235
|
-
* Get the class identifier of a class node
|
|
236
|
-
* @param node The class node to get the identifier from
|
|
237
|
-
* @returns The class identifier or null if not found
|
|
531
|
+
* Get the class identifier of a class node.
|
|
532
|
+
* @param node The class node to get the identifier from.
|
|
533
|
+
* @returns The class identifier or null if not found.
|
|
238
534
|
*/
|
|
239
535
|
function getClassId(node) {
|
|
240
536
|
if (node.id != null) return node.id;
|
|
@@ -393,7 +689,7 @@ function getClassComponentCollector(context) {
|
|
|
393
689
|
*
|
|
394
690
|
* Ported from {@link https://github.com/facebook/react/blob/bb8a76c6cc77ea2976d690ea09f5a1b3d9b1792a/packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts#L860 | RulesOfHooks.ts}
|
|
395
691
|
*
|
|
396
|
-
* @param node
|
|
692
|
+
* @param node The function node to analyze.
|
|
397
693
|
* @returns The identifier node if found, `null` otherwise.
|
|
398
694
|
*/
|
|
399
695
|
function getFunctionId(node) {
|
|
@@ -412,7 +708,7 @@ function getFunctionId(node) {
|
|
|
412
708
|
/**
|
|
413
709
|
* Identifies the initialization path of a function node in the AST.
|
|
414
710
|
*
|
|
415
|
-
* @param node
|
|
711
|
+
* @param node The function node to analyze.
|
|
416
712
|
* @returns The function initialization path or `null` if not identifiable.
|
|
417
713
|
*/
|
|
418
714
|
function getFunctionInitPath(node) {
|
|
@@ -463,8 +759,8 @@ function getFunctionInitPath(node) {
|
|
|
463
759
|
/**
|
|
464
760
|
* Checks if a specific function call exists in the function initialization path.
|
|
465
761
|
*
|
|
466
|
-
* @param callName
|
|
467
|
-
* @param initPath
|
|
762
|
+
* @param callName The name of the call to check for (e.g., "memo", "forwardRef").
|
|
763
|
+
* @param initPath The function initialization path to search in.
|
|
468
764
|
* @returns `true` if the call exists in the path, `false` otherwise.
|
|
469
765
|
*/
|
|
470
766
|
function isFunctionHasCallInInitPath(callName, initPath) {
|
|
@@ -479,7 +775,7 @@ function isFunctionHasCallInInitPath(callName, initPath) {
|
|
|
479
775
|
/**
|
|
480
776
|
* Checks if a function is empty.
|
|
481
777
|
*
|
|
482
|
-
* @param node
|
|
778
|
+
* @param node The function node to check.
|
|
483
779
|
* @returns `true` if the function is empty, `false` otherwise.
|
|
484
780
|
*/
|
|
485
781
|
function isFunctionEmpty(node) {
|
|
@@ -500,8 +796,8 @@ function getFunctionDirectives(node) {
|
|
|
500
796
|
/**
|
|
501
797
|
* Checks if a directive with the given name exists in the function directives.
|
|
502
798
|
*
|
|
503
|
-
* @param node
|
|
504
|
-
* @param name
|
|
799
|
+
* @param node The function AST node.
|
|
800
|
+
* @param name The directive name to check (e.g., "use memo", "use no memo").
|
|
505
801
|
* @returns `true` if the directive exists, `false` otherwise.
|
|
506
802
|
*/
|
|
507
803
|
function isFunctionHasDirective(node, name) {
|
|
@@ -517,24 +813,24 @@ const SEL_FUNCTION_DISPLAY_NAME_ASSIGNMENT = [
|
|
|
517
813
|
//#endregion
|
|
518
814
|
//#region src/function-component.ts
|
|
519
815
|
/**
|
|
520
|
-
* Component flag constants
|
|
816
|
+
* Component flag constants.
|
|
521
817
|
*/
|
|
522
818
|
const FunctionComponentFlag = {
|
|
523
|
-
/** No flags set */
|
|
819
|
+
/** No flags set. */
|
|
524
820
|
None: 0n,
|
|
525
|
-
/** Indicates the component is a pure component (ex: extends PureComponent) */
|
|
821
|
+
/** Indicates the component is a pure component (ex: extends PureComponent). */
|
|
526
822
|
PureComponent: 1n << 0n,
|
|
527
|
-
/** Indicates the component creates elements using `createElement` instead of JSX */
|
|
823
|
+
/** Indicates the component creates elements using `createElement` instead of JSX. */
|
|
528
824
|
CreateElement: 1n << 1n,
|
|
529
|
-
/** Indicates the component is memoized (ex: React.memo) */
|
|
825
|
+
/** Indicates the component is memoized (ex: React.memo). */
|
|
530
826
|
Memo: 1n << 2n,
|
|
531
|
-
/** Indicates the component forwards a ref (ex: React.forwardRef) */
|
|
827
|
+
/** Indicates the component forwards a ref (ex: React.forwardRef). */
|
|
532
828
|
ForwardRef: 1n << 3n
|
|
533
829
|
};
|
|
534
830
|
/**
|
|
535
|
-
* Get component flag from init path
|
|
536
|
-
* @param initPath The init path of the function component
|
|
537
|
-
* @returns The component flag
|
|
831
|
+
* Get component flag from init path.
|
|
832
|
+
* @param initPath The init path of the function component.
|
|
833
|
+
* @returns The component flag.
|
|
538
834
|
* @internal
|
|
539
835
|
*/
|
|
540
836
|
function getFunctionComponentFlagFromInitPath(initPath) {
|
|
@@ -544,20 +840,20 @@ function getFunctionComponentFlagFromInitPath(initPath) {
|
|
|
544
840
|
return flag;
|
|
545
841
|
}
|
|
546
842
|
/**
|
|
547
|
-
* Check if the node is a call expression for a component wrapper
|
|
548
|
-
* @param context The ESLint rule context
|
|
549
|
-
* @param node The node to check
|
|
550
|
-
* @returns `true` if the node is a call expression for a component wrapper
|
|
843
|
+
* Check if the node is a call expression for a component wrapper.
|
|
844
|
+
* @param context The ESLint rule context.
|
|
845
|
+
* @param node The node to check.
|
|
846
|
+
* @returns `true` if the node is a call expression for a component wrapper.
|
|
551
847
|
*/
|
|
552
848
|
function isFunctionComponentWrapperCall(context, node) {
|
|
553
849
|
if (node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
554
850
|
return isMemoCall(context, node) || isForwardRefCall(context, node);
|
|
555
851
|
}
|
|
556
852
|
/**
|
|
557
|
-
* Check if the node is a callback function passed to a component wrapper
|
|
558
|
-
* @param context The ESLint rule context
|
|
559
|
-
* @param node The node to check
|
|
560
|
-
* @returns `true` if the node is a callback function passed to a component wrapper
|
|
853
|
+
* Check if the node is a callback function passed to a component wrapper.
|
|
854
|
+
* @param context The ESLint rule context.
|
|
855
|
+
* @param node The node to check.
|
|
856
|
+
* @returns `true` if the node is a callback function passed to a component wrapper.
|
|
561
857
|
*/
|
|
562
858
|
function isFunctionComponentWrapperCallback(context, node) {
|
|
563
859
|
if (!Check.isFunction(node)) return false;
|
|
@@ -567,9 +863,9 @@ function isFunctionComponentWrapperCallback(context, node) {
|
|
|
567
863
|
return isFunctionComponentWrapperCall(context, parent);
|
|
568
864
|
}
|
|
569
865
|
/**
|
|
570
|
-
* Get function component identifier from `const Component = memo(() => {})
|
|
571
|
-
* @param context The rule context
|
|
572
|
-
* @param node The AST node to get the function component identifier from
|
|
866
|
+
* Get function component identifier from `const Component = memo(() => {});`.
|
|
867
|
+
* @param context The rule context.
|
|
868
|
+
* @param node The AST node to get the function component identifier from.
|
|
573
869
|
* @internal
|
|
574
870
|
*/
|
|
575
871
|
function getFunctionComponentId(context, node) {
|
|
@@ -584,25 +880,25 @@ function getFunctionComponentId(context, node) {
|
|
|
584
880
|
}
|
|
585
881
|
}
|
|
586
882
|
/**
|
|
587
|
-
* Check if a string matches the strict component name pattern
|
|
588
|
-
* @param name The name to check
|
|
883
|
+
* Check if a string matches the strict component name pattern.
|
|
884
|
+
* @param name The name to check.
|
|
589
885
|
*/
|
|
590
886
|
function isFunctionComponentName(name) {
|
|
591
887
|
return RE_COMPONENT_NAME.test(name);
|
|
592
888
|
}
|
|
593
889
|
/**
|
|
594
|
-
* Check if a string matches the loose component name pattern
|
|
595
|
-
* @param name The name to check
|
|
890
|
+
* Check if a string matches the loose component name pattern.
|
|
891
|
+
* @param name The name to check.
|
|
596
892
|
*/
|
|
597
893
|
function isFunctionComponentNameLoose(name) {
|
|
598
894
|
return RE_COMPONENT_NAME_LOOSE.test(name);
|
|
599
895
|
}
|
|
600
896
|
/**
|
|
601
|
-
* Check if a function has a loose component name
|
|
602
|
-
* @param context The rule context
|
|
603
|
-
* @param fn The function to check
|
|
604
|
-
* @param allowNone Whether to allow no name
|
|
605
|
-
* @returns Whether the function has a loose component name
|
|
897
|
+
* Check if a function has a loose component name.
|
|
898
|
+
* @param context The rule context.
|
|
899
|
+
* @param fn The function to check.
|
|
900
|
+
* @param allowNone Whether to allow no name.
|
|
901
|
+
* @returns Whether the function has a loose component name.
|
|
606
902
|
*/
|
|
607
903
|
function isFunctionWithLooseComponentName(context, fn, allowNone = false) {
|
|
608
904
|
const id = getFunctionComponentId(context, fn);
|
|
@@ -612,7 +908,7 @@ function isFunctionWithLooseComponentName(context, fn, allowNone = false) {
|
|
|
612
908
|
return false;
|
|
613
909
|
}
|
|
614
910
|
/**
|
|
615
|
-
* Hints for component collector
|
|
911
|
+
* Hints for component collector.
|
|
616
912
|
*/
|
|
617
913
|
const FunctionComponentDetectionHint = {
|
|
618
914
|
...JsxDetectionHint,
|
|
@@ -626,16 +922,16 @@ const FunctionComponentDetectionHint = {
|
|
|
626
922
|
DoNotIncludeFunctionDefinedAsArbitraryCallExpressionCallback: 1n << 18n
|
|
627
923
|
};
|
|
628
924
|
/**
|
|
629
|
-
* Default component detection hint
|
|
925
|
+
* Default component detection hint.
|
|
630
926
|
*/
|
|
631
927
|
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;
|
|
632
928
|
/**
|
|
633
|
-
* Determine if a function node represents a valid React component definition
|
|
929
|
+
* Determine if a function node represents a valid React component definition.
|
|
634
930
|
*
|
|
635
|
-
* @param context The rule context
|
|
636
|
-
* @param node The function node to analyze
|
|
637
|
-
* @param hint Component detection hints (bit flags) to customize detection logic
|
|
638
|
-
* @returns `true` if the node is considered a component definition
|
|
931
|
+
* @param context The rule context.
|
|
932
|
+
* @param node The function node to analyze.
|
|
933
|
+
* @param hint Component detection hints (bit flags) to customize detection logic.
|
|
934
|
+
* @returns `true` if the node is considered a component definition.
|
|
639
935
|
*/
|
|
640
936
|
function isFunctionComponentDefinition(context, node, hint) {
|
|
641
937
|
if (!isFunctionWithLooseComponentName(context, node, true)) return false;
|
|
@@ -724,9 +1020,9 @@ function isHookName(name) {
|
|
|
724
1020
|
return name === "use" || /^use[A-Z0-9]/.test(name);
|
|
725
1021
|
}
|
|
726
1022
|
/**
|
|
727
|
-
* Checks if the given node is a hook identifier
|
|
728
|
-
* @param id The AST node to check
|
|
729
|
-
* @returns `true` if the node is a hook identifier or member expression with hook name, `false` otherwise
|
|
1023
|
+
* Checks if the given node is a hook identifier.
|
|
1024
|
+
* @param id The AST node to check.
|
|
1025
|
+
* @returns `true` if the node is a hook identifier or member expression with hook name, `false` otherwise.
|
|
730
1026
|
*/
|
|
731
1027
|
function isHookId(id) {
|
|
732
1028
|
switch (id.type) {
|
|
@@ -737,8 +1033,8 @@ function isHookId(id) {
|
|
|
737
1033
|
}
|
|
738
1034
|
/**
|
|
739
1035
|
* Checks if the given expression is a hook tag (callee / tagged template tag).
|
|
740
|
-
* @param tag The expression node to check
|
|
741
|
-
* @returns `true` if the expression is a hook identifier or member expression with hook name, `false` otherwise
|
|
1036
|
+
* @param tag The expression node to check.
|
|
1037
|
+
* @returns `true` if the expression is a hook identifier or member expression with hook name, `false` otherwise.
|
|
742
1038
|
*/
|
|
743
1039
|
function isHookTag(tag) {
|
|
744
1040
|
if (tag == null) return false;
|
|
@@ -746,8 +1042,8 @@ function isHookTag(tag) {
|
|
|
746
1042
|
}
|
|
747
1043
|
/**
|
|
748
1044
|
* Determine if a function node is a React Hook based on its name.
|
|
749
|
-
* @param node The function node to check
|
|
750
|
-
* @returns True if the function is a React Hook, false otherwise
|
|
1045
|
+
* @param node The function node to check.
|
|
1046
|
+
* @returns True if the function is a React Hook, false otherwise.
|
|
751
1047
|
*/
|
|
752
1048
|
function isHookDefinition(node) {
|
|
753
1049
|
if (node == null) return false;
|
|
@@ -771,10 +1067,10 @@ function isHookCall(node) {
|
|
|
771
1067
|
return isHookName(name);
|
|
772
1068
|
}
|
|
773
1069
|
/**
|
|
774
|
-
* Detect useEffect calls and variations (useLayoutEffect, etc.) using a regex pattern
|
|
775
|
-
* @param node The AST node to check
|
|
776
|
-
* @param additionalEffectHooks Regex pattern matching custom hooks that should be treated as effect hooks
|
|
777
|
-
* @returns True if the node is a useEffect-like call
|
|
1070
|
+
* Detect useEffect calls and variations (useLayoutEffect, etc.) using a regex pattern.
|
|
1071
|
+
* @param node The AST node to check.
|
|
1072
|
+
* @param additionalEffectHooks Regex pattern matching custom hooks that should be treated as effect hooks.
|
|
1073
|
+
* @returns True if the node is a useEffect-like call.
|
|
778
1074
|
*/
|
|
779
1075
|
function isUseEffectLikeCall(node, additionalEffectHooks = { test: constFalse }) {
|
|
780
1076
|
if (node == null) return false;
|
|
@@ -784,10 +1080,10 @@ function isUseEffectLikeCall(node, additionalEffectHooks = { test: constFalse })
|
|
|
784
1080
|
return /^use\w*Effect$/u.test(name) || additionalEffectHooks.test(name);
|
|
785
1081
|
}
|
|
786
1082
|
/**
|
|
787
|
-
* Detect useState calls and variations using a regex pattern
|
|
788
|
-
* @param node The AST node to check
|
|
789
|
-
* @param additionalStateHooks Regex pattern matching custom hooks that should be treated as state hooks
|
|
790
|
-
* @returns True if the node is a useState-like call
|
|
1083
|
+
* Detect useState calls and variations using a regex pattern.
|
|
1084
|
+
* @param node The AST node to check.
|
|
1085
|
+
* @param additionalStateHooks Regex pattern matching custom hooks that should be treated as state hooks.
|
|
1086
|
+
* @returns True if the node is a useState-like call.
|
|
791
1087
|
*/
|
|
792
1088
|
function isUseStateLikeCall(node, additionalStateHooks = { test: constFalse }) {
|
|
793
1089
|
if (node == null) return false;
|
|
@@ -797,8 +1093,8 @@ function isUseStateLikeCall(node, additionalStateHooks = { test: constFalse }) {
|
|
|
797
1093
|
return name === "useState" || additionalStateHooks.test(name);
|
|
798
1094
|
}
|
|
799
1095
|
/**
|
|
800
|
-
* Determine if a node is the setup function passed to a useEffect-like hook
|
|
801
|
-
* @param node The AST node to check
|
|
1096
|
+
* Determine if a node is the setup function passed to a useEffect-like hook.
|
|
1097
|
+
* @param node The AST node to check.
|
|
802
1098
|
*/
|
|
803
1099
|
function isUseEffectSetupCallback(node) {
|
|
804
1100
|
if (node == null) return false;
|
|
@@ -806,8 +1102,8 @@ function isUseEffectSetupCallback(node) {
|
|
|
806
1102
|
return expr.parent?.type === AST_NODE_TYPES.CallExpression && expr.parent.arguments.at(0) === expr && isUseEffectLikeCall(expr.parent);
|
|
807
1103
|
}
|
|
808
1104
|
/**
|
|
809
|
-
* Determine if a node is the cleanup function returned by a useEffect-like hook's setup function
|
|
810
|
-
* @param node The AST node to check
|
|
1105
|
+
* Determine if a node is the cleanup function returned by a useEffect-like hook's setup function.
|
|
1106
|
+
* @param node The AST node to check.
|
|
811
1107
|
*/
|
|
812
1108
|
function isUseEffectCleanupCallback(node) {
|
|
813
1109
|
if (node == null) return false;
|
|
@@ -830,10 +1126,9 @@ function isUseEffectCleanupCallback(node) {
|
|
|
830
1126
|
* circular definitions (e.g. `var a = b; var b = a;`) are detected and
|
|
831
1127
|
* treated as not JSX-like instead of recursing indefinitely.
|
|
832
1128
|
*
|
|
833
|
-
* @param context
|
|
834
|
-
* @param node
|
|
835
|
-
* @param hint
|
|
836
|
-
* Defaults to {@link DEFAULT_JSX_DETECTION_HINT}.
|
|
1129
|
+
* @param context The ESLint rule context (needed for variable resolution).
|
|
1130
|
+
* @param node The AST node to analyse.
|
|
1131
|
+
* @param hint Optional bit-flags to adjust detection behaviour. Defaults to {@link DEFAULT_JSX_DETECTION_HINT}.
|
|
837
1132
|
* @returns Whether the node is considered JSX-like.
|
|
838
1133
|
*
|
|
839
1134
|
* @example
|
|
@@ -887,10 +1182,10 @@ function isJsxLike(context, node, hint = DEFAULT_JSX_DETECTION_HINT) {
|
|
|
887
1182
|
//#endregion
|
|
888
1183
|
//#region src/function-component-collector.ts
|
|
889
1184
|
/**
|
|
890
|
-
* Get an api and visitor object for the rule to collect function components
|
|
891
|
-
* @param context The ESLint rule context
|
|
892
|
-
* @param options The options to use
|
|
893
|
-
* @returns The api and visitor of the collector
|
|
1185
|
+
* Get an api and visitor object for the rule to collect function components.
|
|
1186
|
+
* @param context The ESLint rule context.
|
|
1187
|
+
* @param options The options to use.
|
|
1188
|
+
* @returns The api and visitor of the collector.
|
|
894
1189
|
*/
|
|
895
1190
|
function getFunctionComponentCollector(context, options = {}) {
|
|
896
1191
|
const { collectDisplayName = false, hint = DEFAULT_COMPONENT_DETECTION_HINT } = options;
|
|
@@ -988,9 +1283,9 @@ function getFunctionComponentCollector(context, options = {}) {
|
|
|
988
1283
|
//#endregion
|
|
989
1284
|
//#region src/hook-collector.ts
|
|
990
1285
|
/**
|
|
991
|
-
* Get an api and visitor object for the rule to collect hooks
|
|
992
|
-
* @param context The ESLint rule context
|
|
993
|
-
* @returns The api and visitor of the collector
|
|
1286
|
+
* Get an api and visitor object for the rule to collect hooks.
|
|
1287
|
+
* @param context The ESLint rule context.
|
|
1288
|
+
* @returns The api and visitor of the collector.
|
|
994
1289
|
*/
|
|
995
1290
|
function getHookCollector(context) {
|
|
996
1291
|
const hooks = /* @__PURE__ */ new Map();
|
|
@@ -1073,7 +1368,7 @@ const mergedCache = /* @__PURE__ */ new WeakMap();
|
|
|
1073
1368
|
* Falls back to sensible React defaults when no compiler options are
|
|
1074
1369
|
* available (e.g. when the file is parsed without type information).
|
|
1075
1370
|
*
|
|
1076
|
-
* @param context
|
|
1371
|
+
* @param context The ESLint rule context.
|
|
1077
1372
|
* @returns Fully‑populated `JsxConfig` derived from compiler options.
|
|
1078
1373
|
*/
|
|
1079
1374
|
function getJsxConfigFromCompilerOptions(context) {
|
|
@@ -1092,7 +1387,7 @@ function getJsxConfigFromCompilerOptions(context) {
|
|
|
1092
1387
|
* The result is cached per `sourceCode` instance via a `WeakMap` so that
|
|
1093
1388
|
* repeated calls from different rules analysing the same file are free.
|
|
1094
1389
|
*
|
|
1095
|
-
* @param context
|
|
1390
|
+
* @param context The ESLint rule context.
|
|
1096
1391
|
* @returns Partial `JsxConfig` containing only the values found in pragmas.
|
|
1097
1392
|
*/
|
|
1098
1393
|
function getJsxConfigFromAnnotation(context) {
|
|
@@ -1126,7 +1421,7 @@ function getJsxConfigFromAnnotation(context) {
|
|
|
1126
1421
|
*
|
|
1127
1422
|
* This is the main entry‑point most consumers should use.
|
|
1128
1423
|
*
|
|
1129
|
-
* @param context
|
|
1424
|
+
* @param context The ESLint rule context.
|
|
1130
1425
|
* @returns Fully‑populated, merged `JsxConfig`.
|
|
1131
1426
|
*/
|
|
1132
1427
|
function getJsxConfig(context) {
|
|
@@ -1192,10 +1487,10 @@ const isUnknownType = (type) => isTypeFlagSet(type, ts.TypeFlags.Unknown);
|
|
|
1192
1487
|
//#endregion
|
|
1193
1488
|
//#region src/type-name.ts
|
|
1194
1489
|
/**
|
|
1195
|
-
* An enhanced version of getFullyQualifiedName that handles cases that original function does not handle
|
|
1196
|
-
* @param checker TypeScript type checker
|
|
1197
|
-
* @param symbol
|
|
1198
|
-
* @returns
|
|
1490
|
+
* An enhanced version of getFullyQualifiedName that handles cases that original function does not handle.
|
|
1491
|
+
* @param checker The TypeScript type checker.
|
|
1492
|
+
* @param symbol The symbol to get fully qualified name for.
|
|
1493
|
+
* @returns The fully qualified name of the symbol.
|
|
1199
1494
|
*/
|
|
1200
1495
|
function getFullyQualifiedNameEx(checker, symbol) {
|
|
1201
1496
|
let name = symbol.name;
|
|
@@ -1245,10 +1540,10 @@ function getFullyQualifiedNameEx(checker, symbol) {
|
|
|
1245
1540
|
//#endregion
|
|
1246
1541
|
//#region src/type-variant.ts
|
|
1247
1542
|
/**
|
|
1248
|
-
* Ported from https://github.com/typescript-eslint/typescript-eslint/blob/eb736bbfc22554694400e6a4f97051d845d32e0b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts#L826 with some enhancements
|
|
1543
|
+
* Ported from https://github.com/typescript-eslint/typescript-eslint/blob/eb736bbfc22554694400e6a4f97051d845d32e0b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts#L826 with some enhancements.
|
|
1249
1544
|
* Get the variants of an array of types.
|
|
1250
|
-
* @param types The types to get the variants of
|
|
1251
|
-
* @returns The variants of the types
|
|
1545
|
+
* @param types The types to get the variants of.
|
|
1546
|
+
* @returns The variants of the types.
|
|
1252
1547
|
* @internal
|
|
1253
1548
|
*/
|
|
1254
1549
|
function getTypeVariants(types) {
|