eslint-plugin-react-web-api 1.23.3-next.8 → 1.24.0-next.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.js +110 -116
- package/dist/index.mjs +111 -117
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -34,24 +34,24 @@ var VAR2__namespace = /*#__PURE__*/_interopNamespace(VAR2);
|
|
|
34
34
|
|
|
35
35
|
// package.json
|
|
36
36
|
var name = "eslint-plugin-react-web-api";
|
|
37
|
-
var version = "1.
|
|
37
|
+
var version = "1.24.0-next.0";
|
|
38
38
|
var createRule = shared.createRuleForPlugin("web-api");
|
|
39
39
|
function getInstanceID(node, prev) {
|
|
40
40
|
switch (true) {
|
|
41
41
|
case (node.type === types.AST_NODE_TYPES.VariableDeclarator && node.init === prev):
|
|
42
|
-
return
|
|
42
|
+
return node.id;
|
|
43
43
|
case (node.type === types.AST_NODE_TYPES.AssignmentExpression && node.right === prev):
|
|
44
|
-
return
|
|
44
|
+
return node.left;
|
|
45
45
|
case (node.type === types.AST_NODE_TYPES.PropertyDefinition && node.value === prev):
|
|
46
|
-
return
|
|
46
|
+
return node.key;
|
|
47
47
|
case (node.type === types.AST_NODE_TYPES.BlockStatement || node.type === types.AST_NODE_TYPES.Program || node.parent === node):
|
|
48
|
-
return eff.
|
|
48
|
+
return eff._;
|
|
49
49
|
default:
|
|
50
50
|
return getInstanceID(node.parent, node);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
function getPhaseKindOfFunction(node) {
|
|
54
|
-
return tsPattern.match(node).when(core.isSetupFunction, () =>
|
|
54
|
+
return tsPattern.match(node).when(core.isSetupFunction, () => "setup").when(core.isCleanupFunction, () => "cleanup").when(core.isComponentDidMountFunction, () => "mount").when(core.isComponentWillUnmountFunction, () => "unmount").otherwise(() => eff._);
|
|
55
55
|
}
|
|
56
56
|
function isInstanceIDEqual(a, b, context) {
|
|
57
57
|
return AST2__namespace.isNodeEqual(a, b) || VAR2__namespace.isNodeValueEqual(a, b, [
|
|
@@ -66,9 +66,9 @@ var RULE_FEATURES = [
|
|
|
66
66
|
"CHK"
|
|
67
67
|
];
|
|
68
68
|
var defaultOptions = {
|
|
69
|
-
capture:
|
|
70
|
-
once:
|
|
71
|
-
signal: eff.
|
|
69
|
+
capture: false,
|
|
70
|
+
// once: false,
|
|
71
|
+
signal: eff._
|
|
72
72
|
};
|
|
73
73
|
function getCallKind(node) {
|
|
74
74
|
switch (true) {
|
|
@@ -81,68 +81,59 @@ function getCallKind(node) {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
function getFunctionKind(node) {
|
|
84
|
-
return
|
|
84
|
+
return getPhaseKindOfFunction(node) ?? "other";
|
|
85
85
|
}
|
|
86
86
|
function getSignalValueExpression(node, initialScope) {
|
|
87
|
+
if (node === eff._) return eff._;
|
|
87
88
|
switch (node.type) {
|
|
88
|
-
case utils.AST_NODE_TYPES.Identifier:
|
|
89
|
-
return
|
|
90
|
-
|
|
91
|
-
eff.O.flatMap(VAR2__namespace.getVariableNode(0)),
|
|
92
|
-
eff.O.flatMap((n) => getSignalValueExpression(n, initialScope))
|
|
93
|
-
);
|
|
89
|
+
case utils.AST_NODE_TYPES.Identifier: {
|
|
90
|
+
return getSignalValueExpression(VAR2__namespace.getVariableNode(VAR2__namespace.findVariable(node, initialScope), 0), initialScope);
|
|
91
|
+
}
|
|
94
92
|
case utils.AST_NODE_TYPES.MemberExpression:
|
|
95
|
-
return
|
|
93
|
+
return node;
|
|
96
94
|
default:
|
|
97
|
-
return eff.
|
|
95
|
+
return eff._;
|
|
98
96
|
}
|
|
99
97
|
}
|
|
100
98
|
function getOptions(node, initialScope) {
|
|
101
|
-
|
|
102
|
-
return JSX__namespace.findPropInProperties(properties, initialScope)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (prop
|
|
106
|
-
return eff.O.none();
|
|
107
|
-
}
|
|
99
|
+
function findProp(properties, propName) {
|
|
100
|
+
return JSX__namespace.findPropInProperties(propName, properties, initialScope);
|
|
101
|
+
}
|
|
102
|
+
function getPropValue(prop, filter = (_6) => true) {
|
|
103
|
+
if (prop?.type !== utils.AST_NODE_TYPES.Property) return eff._;
|
|
108
104
|
const { value } = prop;
|
|
105
|
+
let v = value;
|
|
109
106
|
switch (value.type) {
|
|
110
107
|
case utils.AST_NODE_TYPES.Literal: {
|
|
111
|
-
|
|
108
|
+
v = value.value;
|
|
109
|
+
break;
|
|
112
110
|
}
|
|
113
111
|
default: {
|
|
114
|
-
|
|
112
|
+
v = VAR2__namespace.toResolved({ kind: "lazy", node: value, initialScope }).value;
|
|
113
|
+
break;
|
|
115
114
|
}
|
|
116
115
|
}
|
|
117
|
-
|
|
116
|
+
return filter(v) ? v : eff._;
|
|
117
|
+
}
|
|
118
118
|
function getOpts(node2) {
|
|
119
119
|
switch (node2.type) {
|
|
120
120
|
case utils.AST_NODE_TYPES.Identifier: {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
);
|
|
121
|
+
const variable = VAR2__namespace.findVariable(node2, initialScope);
|
|
122
|
+
const variableNode = VAR2__namespace.getVariableNode(variable, 0);
|
|
123
|
+
if (variableNode?.type === utils.AST_NODE_TYPES.ObjectExpression) {
|
|
124
|
+
return getOpts(variableNode);
|
|
125
|
+
}
|
|
126
|
+
return defaultOptions;
|
|
128
127
|
}
|
|
129
128
|
case utils.AST_NODE_TYPES.Literal: {
|
|
130
|
-
return { ...defaultOptions, capture:
|
|
129
|
+
return { ...defaultOptions, capture: Boolean(node2.value) };
|
|
131
130
|
}
|
|
132
131
|
case utils.AST_NODE_TYPES.ObjectExpression: {
|
|
133
|
-
const pOnce = findProp(node2.properties, "once");
|
|
134
|
-
const vOnce = eff.O.flatMap(pOnce, getPropValue).pipe(eff.O.filter(eff.isBoolean));
|
|
135
132
|
const pCapture = findProp(node2.properties, "capture");
|
|
136
|
-
const vCapture =
|
|
133
|
+
const vCapture = !!getPropValue(pCapture);
|
|
137
134
|
const pSignal = findProp(node2.properties, "signal");
|
|
138
|
-
const vSignal =
|
|
139
|
-
|
|
140
|
-
return eff.O.none();
|
|
141
|
-
}
|
|
142
|
-
const { value } = prop;
|
|
143
|
-
return getSignalValueExpression(value, initialScope);
|
|
144
|
-
});
|
|
145
|
-
return { capture: vCapture, once: vOnce, signal: vSignal };
|
|
135
|
+
const vSignal = pSignal?.type === utils.AST_NODE_TYPES.Property ? getSignalValueExpression(pSignal.value, initialScope) : eff._;
|
|
136
|
+
return { capture: vCapture, signal: vSignal };
|
|
146
137
|
}
|
|
147
138
|
default: {
|
|
148
139
|
return defaultOptions;
|
|
@@ -173,7 +164,7 @@ var no_leaked_event_listener_default = createRule({
|
|
|
173
164
|
if (!/use\w*Effect|componentDidMount|componentWillUnmount/u.test(context.sourceCode.text)) {
|
|
174
165
|
return {};
|
|
175
166
|
}
|
|
176
|
-
const
|
|
167
|
+
const fEntries = [];
|
|
177
168
|
const aEntries = [];
|
|
178
169
|
const rEntries = [];
|
|
179
170
|
const abortedSignals = [];
|
|
@@ -195,17 +186,17 @@ var no_leaked_event_listener_default = createRule({
|
|
|
195
186
|
return isSameObject(aCallee, rCallee) && AST2__namespace.isNodeEqual(aListener, rListener) && VAR2__namespace.isNodeValueEqual(aType, rType, [
|
|
196
187
|
context.sourceCode.getScope(aType),
|
|
197
188
|
context.sourceCode.getScope(rType)
|
|
198
|
-
]) &&
|
|
189
|
+
]) && aCapture === rCapture;
|
|
199
190
|
}
|
|
200
191
|
function checkInlineFunction(node, callKind, options) {
|
|
201
|
-
const
|
|
192
|
+
const listener = node.arguments.at(1);
|
|
202
193
|
if (!AST2__namespace.isFunction(listener)) {
|
|
203
|
-
return
|
|
194
|
+
return;
|
|
204
195
|
}
|
|
205
|
-
if (
|
|
206
|
-
return
|
|
196
|
+
if (options.signal !== eff._) {
|
|
197
|
+
return;
|
|
207
198
|
}
|
|
208
|
-
|
|
199
|
+
context.report({
|
|
209
200
|
messageId: "noLeakedEventListenerOfInlineFunction",
|
|
210
201
|
node: listener,
|
|
211
202
|
data: { eventMethodKind: callKind }
|
|
@@ -213,15 +204,15 @@ var no_leaked_event_listener_default = createRule({
|
|
|
213
204
|
}
|
|
214
205
|
return {
|
|
215
206
|
[":function"](node) {
|
|
216
|
-
const
|
|
217
|
-
|
|
207
|
+
const kind = getFunctionKind(node);
|
|
208
|
+
fEntries.push({ kind, node });
|
|
218
209
|
},
|
|
219
210
|
[":function:exit"]() {
|
|
220
|
-
|
|
211
|
+
fEntries.pop();
|
|
221
212
|
},
|
|
222
213
|
["CallExpression"](node) {
|
|
223
|
-
const
|
|
224
|
-
if (
|
|
214
|
+
const fKind = fEntries.findLast((x) => x.kind !== "other")?.kind;
|
|
215
|
+
if (fKind === eff._) {
|
|
225
216
|
return;
|
|
226
217
|
}
|
|
227
218
|
if (!core.ERPhaseRelevance.has(fKind)) {
|
|
@@ -234,7 +225,7 @@ var no_leaked_event_listener_default = createRule({
|
|
|
234
225
|
}
|
|
235
226
|
const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
|
|
236
227
|
const { callee } = node;
|
|
237
|
-
|
|
228
|
+
checkInlineFunction(node, callKind, opts);
|
|
238
229
|
aEntries.push({
|
|
239
230
|
...opts,
|
|
240
231
|
kind: "addEventListener",
|
|
@@ -251,7 +242,7 @@ var no_leaked_event_listener_default = createRule({
|
|
|
251
242
|
}
|
|
252
243
|
const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
|
|
253
244
|
const { callee } = node;
|
|
254
|
-
|
|
245
|
+
checkInlineFunction(node, callKind, opts);
|
|
255
246
|
rEntries.push({
|
|
256
247
|
...opts,
|
|
257
248
|
kind: "removeEventListener",
|
|
@@ -263,11 +254,12 @@ var no_leaked_event_listener_default = createRule({
|
|
|
263
254
|
});
|
|
264
255
|
}).with("abort", () => {
|
|
265
256
|
abortedSignals.push(node.callee);
|
|
266
|
-
}).otherwise(eff.
|
|
257
|
+
}).otherwise(() => eff._);
|
|
267
258
|
},
|
|
268
259
|
["Program:exit"]() {
|
|
269
260
|
for (const aEntry of aEntries) {
|
|
270
|
-
|
|
261
|
+
const signal = aEntry.signal;
|
|
262
|
+
if (signal !== eff._ && abortedSignals.some((a) => isSameObject(a, signal))) {
|
|
271
263
|
continue;
|
|
272
264
|
}
|
|
273
265
|
if (rEntries.some((rEntry) => isInverseEntry(aEntry, rEntry))) {
|
|
@@ -331,31 +323,31 @@ var no_leaked_interval_default = createRule({
|
|
|
331
323
|
if (!context.sourceCode.text.includes("setInterval")) {
|
|
332
324
|
return {};
|
|
333
325
|
}
|
|
334
|
-
const
|
|
326
|
+
const fEntries = [];
|
|
335
327
|
const sEntries = [];
|
|
336
328
|
const cEntries = [];
|
|
337
329
|
function isInverseEntry(a, b) {
|
|
338
|
-
return isInstanceIDEqual(a.
|
|
330
|
+
return isInstanceIDEqual(a.timerId, b.timerId, context);
|
|
339
331
|
}
|
|
340
332
|
return {
|
|
341
333
|
[":function"](node) {
|
|
342
|
-
const
|
|
343
|
-
|
|
334
|
+
const kind = getPhaseKindOfFunction(node) ?? "other";
|
|
335
|
+
fEntries.push({ kind, node });
|
|
344
336
|
},
|
|
345
337
|
[":function:exit"]() {
|
|
346
|
-
|
|
338
|
+
fEntries.pop();
|
|
347
339
|
},
|
|
348
340
|
["CallExpression"](node) {
|
|
349
341
|
switch (getCallKind2(node)) {
|
|
350
342
|
case "setInterval": {
|
|
351
|
-
const
|
|
352
|
-
if (
|
|
343
|
+
const fEntry = fEntries.findLast((x) => x.kind !== "other");
|
|
344
|
+
if (fEntry === eff._) {
|
|
353
345
|
break;
|
|
354
346
|
}
|
|
355
|
-
if (!core.ERPhaseRelevance.has(
|
|
347
|
+
if (!core.ERPhaseRelevance.has(fEntry.kind)) {
|
|
356
348
|
break;
|
|
357
349
|
}
|
|
358
|
-
const intervalIdNode =
|
|
350
|
+
const intervalIdNode = VAR2__namespace.getVariableDeclaratorId(node);
|
|
359
351
|
if (intervalIdNode == null) {
|
|
360
352
|
context.report({
|
|
361
353
|
messageId: "noLeakedIntervalNoIntervalId",
|
|
@@ -367,17 +359,17 @@ var no_leaked_interval_default = createRule({
|
|
|
367
359
|
kind: "interval",
|
|
368
360
|
node,
|
|
369
361
|
callee: node.callee,
|
|
370
|
-
phase:
|
|
371
|
-
|
|
362
|
+
phase: fEntry.kind,
|
|
363
|
+
timerId: intervalIdNode
|
|
372
364
|
});
|
|
373
365
|
break;
|
|
374
366
|
}
|
|
375
367
|
case "clearInterval": {
|
|
376
|
-
const
|
|
377
|
-
if (
|
|
368
|
+
const fEntry = fEntries.findLast((x) => x.kind !== "other");
|
|
369
|
+
if (fEntry === eff._) {
|
|
378
370
|
break;
|
|
379
371
|
}
|
|
380
|
-
if (!core.ERPhaseRelevance.has(
|
|
372
|
+
if (!core.ERPhaseRelevance.has(fEntry.kind)) {
|
|
381
373
|
break;
|
|
382
374
|
}
|
|
383
375
|
const [intervalIdNode] = node.arguments;
|
|
@@ -388,8 +380,8 @@ var no_leaked_interval_default = createRule({
|
|
|
388
380
|
kind: "interval",
|
|
389
381
|
node,
|
|
390
382
|
callee: node.callee,
|
|
391
|
-
phase:
|
|
392
|
-
|
|
383
|
+
phase: fEntry.kind,
|
|
384
|
+
timerId: intervalIdNode
|
|
393
385
|
});
|
|
394
386
|
break;
|
|
395
387
|
}
|
|
@@ -433,16 +425,15 @@ var RULE_FEATURES3 = [
|
|
|
433
425
|
"CHK"
|
|
434
426
|
];
|
|
435
427
|
function isNewResizeObserver(node) {
|
|
436
|
-
return node
|
|
428
|
+
return node?.type === utils.AST_NODE_TYPES.NewExpression && node.callee.type === utils.AST_NODE_TYPES.Identifier && node.callee.name === "ResizeObserver";
|
|
437
429
|
}
|
|
438
430
|
function isFromObserver(node, context) {
|
|
439
431
|
switch (true) {
|
|
440
|
-
case node.type === utils.AST_NODE_TYPES.Identifier:
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
);
|
|
432
|
+
case node.type === utils.AST_NODE_TYPES.Identifier: {
|
|
433
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
434
|
+
const object = VAR2__namespace.getVariableNode(VAR2__namespace.findVariable(node, initialScope), 0);
|
|
435
|
+
return isNewResizeObserver(object);
|
|
436
|
+
}
|
|
446
437
|
case node.type === utils.AST_NODE_TYPES.MemberExpression:
|
|
447
438
|
return isFromObserver(node.object, context);
|
|
448
439
|
default:
|
|
@@ -460,7 +451,7 @@ function getCallKind3(node, context) {
|
|
|
460
451
|
}
|
|
461
452
|
}
|
|
462
453
|
function getFunctionKind2(node) {
|
|
463
|
-
return
|
|
454
|
+
return getPhaseKindOfFunction(node) ?? "other";
|
|
464
455
|
}
|
|
465
456
|
var no_leaked_resize_observer_default = createRule({
|
|
466
457
|
meta: {
|
|
@@ -481,25 +472,25 @@ var no_leaked_resize_observer_default = createRule({
|
|
|
481
472
|
if (!context.sourceCode.text.includes("ResizeObserver")) {
|
|
482
473
|
return {};
|
|
483
474
|
}
|
|
484
|
-
const
|
|
475
|
+
const fEntries = [];
|
|
485
476
|
const observers = [];
|
|
486
477
|
const oEntries = [];
|
|
487
478
|
const uEntries = [];
|
|
488
479
|
const dEntries = [];
|
|
489
480
|
return {
|
|
490
481
|
[":function"](node) {
|
|
491
|
-
const
|
|
492
|
-
|
|
482
|
+
const kind = getFunctionKind2(node);
|
|
483
|
+
fEntries.push({ kind, node });
|
|
493
484
|
},
|
|
494
485
|
[":function:exit"]() {
|
|
495
|
-
|
|
486
|
+
fEntries.pop();
|
|
496
487
|
},
|
|
497
488
|
["CallExpression"](node) {
|
|
498
|
-
const [_, fKind] = fStack.findLast((f) => f.at(1) !== "other") ?? [];
|
|
499
489
|
if (node.callee.type !== utils.AST_NODE_TYPES.MemberExpression) {
|
|
500
490
|
return;
|
|
501
491
|
}
|
|
502
|
-
|
|
492
|
+
const fKind = fEntries.findLast((x) => x.kind !== "other")?.kind;
|
|
493
|
+
if (fKind === eff._ || !core.ERPhaseRelevance.has(fKind)) {
|
|
503
494
|
return;
|
|
504
495
|
}
|
|
505
496
|
const { object } = node.callee;
|
|
@@ -540,36 +531,42 @@ var no_leaked_resize_observer_default = createRule({
|
|
|
540
531
|
observerKind: "ResizeObserver",
|
|
541
532
|
phase: fKind
|
|
542
533
|
});
|
|
543
|
-
}).otherwise(eff.
|
|
534
|
+
}).otherwise(() => eff._);
|
|
544
535
|
},
|
|
545
536
|
["NewExpression"](node) {
|
|
546
|
-
const
|
|
547
|
-
if (
|
|
537
|
+
const fEntry = fEntries.findLast((x) => x.kind !== "other");
|
|
538
|
+
if (fEntry === eff._) return;
|
|
539
|
+
if (!core.ERPhaseRelevance.has(fEntry.kind)) {
|
|
548
540
|
return;
|
|
549
541
|
}
|
|
550
542
|
if (!isNewResizeObserver(node)) {
|
|
551
543
|
return;
|
|
552
544
|
}
|
|
553
545
|
const id = getInstanceID(node);
|
|
554
|
-
if (eff.
|
|
546
|
+
if (id === eff._) {
|
|
555
547
|
context.report({
|
|
556
548
|
messageId: "noLeakedResizeObserverNoFloatingInstance",
|
|
557
549
|
node
|
|
558
550
|
});
|
|
559
551
|
return;
|
|
560
552
|
}
|
|
561
|
-
observers.push(
|
|
553
|
+
observers.push({
|
|
554
|
+
id,
|
|
555
|
+
node,
|
|
556
|
+
phase: fEntry.kind,
|
|
557
|
+
phaseNode: fEntry.node
|
|
558
|
+
});
|
|
562
559
|
},
|
|
563
560
|
["Program:exit"]() {
|
|
564
|
-
for (const
|
|
561
|
+
for (const { id, node, phaseNode } of observers) {
|
|
565
562
|
if (dEntries.some((e) => isInstanceIDEqual(e.observer, id, context))) {
|
|
566
563
|
continue;
|
|
567
564
|
}
|
|
568
565
|
const oentries = oEntries.filter((e) => isInstanceIDEqual(e.observer, id, context));
|
|
569
566
|
const uentries = uEntries.filter((e) => isInstanceIDEqual(e.observer, id, context));
|
|
570
|
-
const isDynamic = (node2) => node2
|
|
567
|
+
const isDynamic = (node2) => node2?.type === utils.AST_NODE_TYPES.CallExpression || AST2__namespace.isConditional(node2);
|
|
571
568
|
const isPhaseNode = (node2) => node2 === phaseNode;
|
|
572
|
-
const hasDynamicallyAdded = oentries.some((e) =>
|
|
569
|
+
const hasDynamicallyAdded = oentries.some((e) => !isPhaseNode(AST2__namespace.findParentNode(e.node, eff.or(isDynamic, isPhaseNode))));
|
|
573
570
|
if (hasDynamicallyAdded) {
|
|
574
571
|
context.report({ messageId: "noLeakedResizeObserverInControlFlow", node });
|
|
575
572
|
continue;
|
|
@@ -619,31 +616,28 @@ var no_leaked_timeout_default = createRule({
|
|
|
619
616
|
if (!context.sourceCode.text.includes("setTimeout")) {
|
|
620
617
|
return {};
|
|
621
618
|
}
|
|
622
|
-
const
|
|
619
|
+
const fEntries = [];
|
|
623
620
|
const sEntries = [];
|
|
624
621
|
const rEntries = [];
|
|
625
622
|
function isInverseEntry(a, b) {
|
|
626
|
-
return isInstanceIDEqual(a.
|
|
623
|
+
return isInstanceIDEqual(a.timerId, b.timerId, context);
|
|
627
624
|
}
|
|
628
625
|
return {
|
|
629
626
|
[":function"](node) {
|
|
630
|
-
const
|
|
631
|
-
|
|
627
|
+
const kind = getPhaseKindOfFunction(node) ?? "other";
|
|
628
|
+
fEntries.push({ kind, node });
|
|
632
629
|
},
|
|
633
630
|
[":function:exit"]() {
|
|
634
|
-
|
|
631
|
+
fEntries.pop();
|
|
635
632
|
},
|
|
636
633
|
["CallExpression"](node) {
|
|
637
|
-
const
|
|
638
|
-
if (
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
if (!core.ERPhaseRelevance.has(fKind)) {
|
|
634
|
+
const fEntry = fEntries.findLast((f) => f.kind !== "other");
|
|
635
|
+
if (!core.ERPhaseRelevance.has(fEntry?.kind)) {
|
|
642
636
|
return;
|
|
643
637
|
}
|
|
644
638
|
switch (getCallKind4(node)) {
|
|
645
639
|
case "setTimeout": {
|
|
646
|
-
const timeoutIdNode =
|
|
640
|
+
const timeoutIdNode = VAR2__namespace.getVariableDeclaratorId(node);
|
|
647
641
|
if (timeoutIdNode == null) {
|
|
648
642
|
context.report({
|
|
649
643
|
messageId: "noLeakedTimeoutNoTimeoutId",
|
|
@@ -655,8 +649,8 @@ var no_leaked_timeout_default = createRule({
|
|
|
655
649
|
kind: "timeout",
|
|
656
650
|
node,
|
|
657
651
|
callee: node.callee,
|
|
658
|
-
phase:
|
|
659
|
-
|
|
652
|
+
phase: fEntry.kind,
|
|
653
|
+
timerId: timeoutIdNode
|
|
660
654
|
});
|
|
661
655
|
break;
|
|
662
656
|
}
|
|
@@ -669,8 +663,8 @@ var no_leaked_timeout_default = createRule({
|
|
|
669
663
|
kind: "timeout",
|
|
670
664
|
node,
|
|
671
665
|
callee: node.callee,
|
|
672
|
-
phase:
|
|
673
|
-
|
|
666
|
+
phase: fEntry.kind,
|
|
667
|
+
timerId: timeoutIdNode
|
|
674
668
|
});
|
|
675
669
|
break;
|
|
676
670
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as AST2 from '@eslint-react/ast';
|
|
2
2
|
import { ERPhaseRelevance, isSetupFunction, isCleanupFunction, isComponentDidMountFunction, isComponentWillUnmountFunction, isInversePhase } from '@eslint-react/core';
|
|
3
|
-
import {
|
|
3
|
+
import { _, or } from '@eslint-react/eff';
|
|
4
4
|
import * as JSX from '@eslint-react/jsx';
|
|
5
5
|
import * as VAR2 from '@eslint-react/var';
|
|
6
6
|
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
@@ -10,24 +10,24 @@ import { AST_NODE_TYPES as AST_NODE_TYPES$1 } from '@typescript-eslint/types';
|
|
|
10
10
|
|
|
11
11
|
// package.json
|
|
12
12
|
var name = "eslint-plugin-react-web-api";
|
|
13
|
-
var version = "1.
|
|
13
|
+
var version = "1.24.0-next.0";
|
|
14
14
|
var createRule = createRuleForPlugin("web-api");
|
|
15
15
|
function getInstanceID(node, prev) {
|
|
16
16
|
switch (true) {
|
|
17
17
|
case (node.type === AST_NODE_TYPES$1.VariableDeclarator && node.init === prev):
|
|
18
|
-
return
|
|
18
|
+
return node.id;
|
|
19
19
|
case (node.type === AST_NODE_TYPES$1.AssignmentExpression && node.right === prev):
|
|
20
|
-
return
|
|
20
|
+
return node.left;
|
|
21
21
|
case (node.type === AST_NODE_TYPES$1.PropertyDefinition && node.value === prev):
|
|
22
|
-
return
|
|
22
|
+
return node.key;
|
|
23
23
|
case (node.type === AST_NODE_TYPES$1.BlockStatement || node.type === AST_NODE_TYPES$1.Program || node.parent === node):
|
|
24
|
-
return
|
|
24
|
+
return _;
|
|
25
25
|
default:
|
|
26
26
|
return getInstanceID(node.parent, node);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
function getPhaseKindOfFunction(node) {
|
|
30
|
-
return match(node).when(isSetupFunction, () =>
|
|
30
|
+
return match(node).when(isSetupFunction, () => "setup").when(isCleanupFunction, () => "cleanup").when(isComponentDidMountFunction, () => "mount").when(isComponentWillUnmountFunction, () => "unmount").otherwise(() => _);
|
|
31
31
|
}
|
|
32
32
|
function isInstanceIDEqual(a, b, context) {
|
|
33
33
|
return AST2.isNodeEqual(a, b) || VAR2.isNodeValueEqual(a, b, [
|
|
@@ -42,9 +42,9 @@ var RULE_FEATURES = [
|
|
|
42
42
|
"CHK"
|
|
43
43
|
];
|
|
44
44
|
var defaultOptions = {
|
|
45
|
-
capture:
|
|
46
|
-
once:
|
|
47
|
-
signal:
|
|
45
|
+
capture: false,
|
|
46
|
+
// once: false,
|
|
47
|
+
signal: _
|
|
48
48
|
};
|
|
49
49
|
function getCallKind(node) {
|
|
50
50
|
switch (true) {
|
|
@@ -57,68 +57,59 @@ function getCallKind(node) {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
function getFunctionKind(node) {
|
|
60
|
-
return
|
|
60
|
+
return getPhaseKindOfFunction(node) ?? "other";
|
|
61
61
|
}
|
|
62
62
|
function getSignalValueExpression(node, initialScope) {
|
|
63
|
+
if (node === _) return _;
|
|
63
64
|
switch (node.type) {
|
|
64
|
-
case AST_NODE_TYPES.Identifier:
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
O.flatMap(VAR2.getVariableNode(0)),
|
|
68
|
-
O.flatMap((n) => getSignalValueExpression(n, initialScope))
|
|
69
|
-
);
|
|
65
|
+
case AST_NODE_TYPES.Identifier: {
|
|
66
|
+
return getSignalValueExpression(VAR2.getVariableNode(VAR2.findVariable(node, initialScope), 0), initialScope);
|
|
67
|
+
}
|
|
70
68
|
case AST_NODE_TYPES.MemberExpression:
|
|
71
|
-
return
|
|
69
|
+
return node;
|
|
72
70
|
default:
|
|
73
|
-
return
|
|
71
|
+
return _;
|
|
74
72
|
}
|
|
75
73
|
}
|
|
76
74
|
function getOptions(node, initialScope) {
|
|
77
|
-
|
|
78
|
-
return JSX.findPropInProperties(properties, initialScope)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (prop
|
|
82
|
-
return O.none();
|
|
83
|
-
}
|
|
75
|
+
function findProp(properties, propName) {
|
|
76
|
+
return JSX.findPropInProperties(propName, properties, initialScope);
|
|
77
|
+
}
|
|
78
|
+
function getPropValue(prop, filter = (_6) => true) {
|
|
79
|
+
if (prop?.type !== AST_NODE_TYPES.Property) return _;
|
|
84
80
|
const { value } = prop;
|
|
81
|
+
let v = value;
|
|
85
82
|
switch (value.type) {
|
|
86
83
|
case AST_NODE_TYPES.Literal: {
|
|
87
|
-
|
|
84
|
+
v = value.value;
|
|
85
|
+
break;
|
|
88
86
|
}
|
|
89
87
|
default: {
|
|
90
|
-
|
|
88
|
+
v = VAR2.toResolved({ kind: "lazy", node: value, initialScope }).value;
|
|
89
|
+
break;
|
|
91
90
|
}
|
|
92
91
|
}
|
|
93
|
-
|
|
92
|
+
return filter(v) ? v : _;
|
|
93
|
+
}
|
|
94
94
|
function getOpts(node2) {
|
|
95
95
|
switch (node2.type) {
|
|
96
96
|
case AST_NODE_TYPES.Identifier: {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
);
|
|
97
|
+
const variable = VAR2.findVariable(node2, initialScope);
|
|
98
|
+
const variableNode = VAR2.getVariableNode(variable, 0);
|
|
99
|
+
if (variableNode?.type === AST_NODE_TYPES.ObjectExpression) {
|
|
100
|
+
return getOpts(variableNode);
|
|
101
|
+
}
|
|
102
|
+
return defaultOptions;
|
|
104
103
|
}
|
|
105
104
|
case AST_NODE_TYPES.Literal: {
|
|
106
|
-
return { ...defaultOptions, capture:
|
|
105
|
+
return { ...defaultOptions, capture: Boolean(node2.value) };
|
|
107
106
|
}
|
|
108
107
|
case AST_NODE_TYPES.ObjectExpression: {
|
|
109
|
-
const pOnce = findProp(node2.properties, "once");
|
|
110
|
-
const vOnce = O.flatMap(pOnce, getPropValue).pipe(O.filter(isBoolean));
|
|
111
108
|
const pCapture = findProp(node2.properties, "capture");
|
|
112
|
-
const vCapture =
|
|
109
|
+
const vCapture = !!getPropValue(pCapture);
|
|
113
110
|
const pSignal = findProp(node2.properties, "signal");
|
|
114
|
-
const vSignal =
|
|
115
|
-
|
|
116
|
-
return O.none();
|
|
117
|
-
}
|
|
118
|
-
const { value } = prop;
|
|
119
|
-
return getSignalValueExpression(value, initialScope);
|
|
120
|
-
});
|
|
121
|
-
return { capture: vCapture, once: vOnce, signal: vSignal };
|
|
111
|
+
const vSignal = pSignal?.type === AST_NODE_TYPES.Property ? getSignalValueExpression(pSignal.value, initialScope) : _;
|
|
112
|
+
return { capture: vCapture, signal: vSignal };
|
|
122
113
|
}
|
|
123
114
|
default: {
|
|
124
115
|
return defaultOptions;
|
|
@@ -149,7 +140,7 @@ var no_leaked_event_listener_default = createRule({
|
|
|
149
140
|
if (!/use\w*Effect|componentDidMount|componentWillUnmount/u.test(context.sourceCode.text)) {
|
|
150
141
|
return {};
|
|
151
142
|
}
|
|
152
|
-
const
|
|
143
|
+
const fEntries = [];
|
|
153
144
|
const aEntries = [];
|
|
154
145
|
const rEntries = [];
|
|
155
146
|
const abortedSignals = [];
|
|
@@ -171,17 +162,17 @@ var no_leaked_event_listener_default = createRule({
|
|
|
171
162
|
return isSameObject(aCallee, rCallee) && AST2.isNodeEqual(aListener, rListener) && VAR2.isNodeValueEqual(aType, rType, [
|
|
172
163
|
context.sourceCode.getScope(aType),
|
|
173
164
|
context.sourceCode.getScope(rType)
|
|
174
|
-
]) &&
|
|
165
|
+
]) && aCapture === rCapture;
|
|
175
166
|
}
|
|
176
167
|
function checkInlineFunction(node, callKind, options) {
|
|
177
|
-
const
|
|
168
|
+
const listener = node.arguments.at(1);
|
|
178
169
|
if (!AST2.isFunction(listener)) {
|
|
179
|
-
return
|
|
170
|
+
return;
|
|
180
171
|
}
|
|
181
|
-
if (
|
|
182
|
-
return
|
|
172
|
+
if (options.signal !== _) {
|
|
173
|
+
return;
|
|
183
174
|
}
|
|
184
|
-
|
|
175
|
+
context.report({
|
|
185
176
|
messageId: "noLeakedEventListenerOfInlineFunction",
|
|
186
177
|
node: listener,
|
|
187
178
|
data: { eventMethodKind: callKind }
|
|
@@ -189,15 +180,15 @@ var no_leaked_event_listener_default = createRule({
|
|
|
189
180
|
}
|
|
190
181
|
return {
|
|
191
182
|
[":function"](node) {
|
|
192
|
-
const
|
|
193
|
-
|
|
183
|
+
const kind = getFunctionKind(node);
|
|
184
|
+
fEntries.push({ kind, node });
|
|
194
185
|
},
|
|
195
186
|
[":function:exit"]() {
|
|
196
|
-
|
|
187
|
+
fEntries.pop();
|
|
197
188
|
},
|
|
198
189
|
["CallExpression"](node) {
|
|
199
|
-
const
|
|
200
|
-
if (
|
|
190
|
+
const fKind = fEntries.findLast((x) => x.kind !== "other")?.kind;
|
|
191
|
+
if (fKind === _) {
|
|
201
192
|
return;
|
|
202
193
|
}
|
|
203
194
|
if (!ERPhaseRelevance.has(fKind)) {
|
|
@@ -210,7 +201,7 @@ var no_leaked_event_listener_default = createRule({
|
|
|
210
201
|
}
|
|
211
202
|
const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
|
|
212
203
|
const { callee } = node;
|
|
213
|
-
|
|
204
|
+
checkInlineFunction(node, callKind, opts);
|
|
214
205
|
aEntries.push({
|
|
215
206
|
...opts,
|
|
216
207
|
kind: "addEventListener",
|
|
@@ -227,7 +218,7 @@ var no_leaked_event_listener_default = createRule({
|
|
|
227
218
|
}
|
|
228
219
|
const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
|
|
229
220
|
const { callee } = node;
|
|
230
|
-
|
|
221
|
+
checkInlineFunction(node, callKind, opts);
|
|
231
222
|
rEntries.push({
|
|
232
223
|
...opts,
|
|
233
224
|
kind: "removeEventListener",
|
|
@@ -239,11 +230,12 @@ var no_leaked_event_listener_default = createRule({
|
|
|
239
230
|
});
|
|
240
231
|
}).with("abort", () => {
|
|
241
232
|
abortedSignals.push(node.callee);
|
|
242
|
-
}).otherwise(
|
|
233
|
+
}).otherwise(() => _);
|
|
243
234
|
},
|
|
244
235
|
["Program:exit"]() {
|
|
245
236
|
for (const aEntry of aEntries) {
|
|
246
|
-
|
|
237
|
+
const signal = aEntry.signal;
|
|
238
|
+
if (signal !== _ && abortedSignals.some((a) => isSameObject(a, signal))) {
|
|
247
239
|
continue;
|
|
248
240
|
}
|
|
249
241
|
if (rEntries.some((rEntry) => isInverseEntry(aEntry, rEntry))) {
|
|
@@ -307,31 +299,31 @@ var no_leaked_interval_default = createRule({
|
|
|
307
299
|
if (!context.sourceCode.text.includes("setInterval")) {
|
|
308
300
|
return {};
|
|
309
301
|
}
|
|
310
|
-
const
|
|
302
|
+
const fEntries = [];
|
|
311
303
|
const sEntries = [];
|
|
312
304
|
const cEntries = [];
|
|
313
305
|
function isInverseEntry(a, b) {
|
|
314
|
-
return isInstanceIDEqual(a.
|
|
306
|
+
return isInstanceIDEqual(a.timerId, b.timerId, context);
|
|
315
307
|
}
|
|
316
308
|
return {
|
|
317
309
|
[":function"](node) {
|
|
318
|
-
const
|
|
319
|
-
|
|
310
|
+
const kind = getPhaseKindOfFunction(node) ?? "other";
|
|
311
|
+
fEntries.push({ kind, node });
|
|
320
312
|
},
|
|
321
313
|
[":function:exit"]() {
|
|
322
|
-
|
|
314
|
+
fEntries.pop();
|
|
323
315
|
},
|
|
324
316
|
["CallExpression"](node) {
|
|
325
317
|
switch (getCallKind2(node)) {
|
|
326
318
|
case "setInterval": {
|
|
327
|
-
const
|
|
328
|
-
if (
|
|
319
|
+
const fEntry = fEntries.findLast((x) => x.kind !== "other");
|
|
320
|
+
if (fEntry === _) {
|
|
329
321
|
break;
|
|
330
322
|
}
|
|
331
|
-
if (!ERPhaseRelevance.has(
|
|
323
|
+
if (!ERPhaseRelevance.has(fEntry.kind)) {
|
|
332
324
|
break;
|
|
333
325
|
}
|
|
334
|
-
const intervalIdNode =
|
|
326
|
+
const intervalIdNode = VAR2.getVariableDeclaratorId(node);
|
|
335
327
|
if (intervalIdNode == null) {
|
|
336
328
|
context.report({
|
|
337
329
|
messageId: "noLeakedIntervalNoIntervalId",
|
|
@@ -343,17 +335,17 @@ var no_leaked_interval_default = createRule({
|
|
|
343
335
|
kind: "interval",
|
|
344
336
|
node,
|
|
345
337
|
callee: node.callee,
|
|
346
|
-
phase:
|
|
347
|
-
|
|
338
|
+
phase: fEntry.kind,
|
|
339
|
+
timerId: intervalIdNode
|
|
348
340
|
});
|
|
349
341
|
break;
|
|
350
342
|
}
|
|
351
343
|
case "clearInterval": {
|
|
352
|
-
const
|
|
353
|
-
if (
|
|
344
|
+
const fEntry = fEntries.findLast((x) => x.kind !== "other");
|
|
345
|
+
if (fEntry === _) {
|
|
354
346
|
break;
|
|
355
347
|
}
|
|
356
|
-
if (!ERPhaseRelevance.has(
|
|
348
|
+
if (!ERPhaseRelevance.has(fEntry.kind)) {
|
|
357
349
|
break;
|
|
358
350
|
}
|
|
359
351
|
const [intervalIdNode] = node.arguments;
|
|
@@ -364,8 +356,8 @@ var no_leaked_interval_default = createRule({
|
|
|
364
356
|
kind: "interval",
|
|
365
357
|
node,
|
|
366
358
|
callee: node.callee,
|
|
367
|
-
phase:
|
|
368
|
-
|
|
359
|
+
phase: fEntry.kind,
|
|
360
|
+
timerId: intervalIdNode
|
|
369
361
|
});
|
|
370
362
|
break;
|
|
371
363
|
}
|
|
@@ -409,16 +401,15 @@ var RULE_FEATURES3 = [
|
|
|
409
401
|
"CHK"
|
|
410
402
|
];
|
|
411
403
|
function isNewResizeObserver(node) {
|
|
412
|
-
return node
|
|
404
|
+
return node?.type === AST_NODE_TYPES.NewExpression && node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === "ResizeObserver";
|
|
413
405
|
}
|
|
414
406
|
function isFromObserver(node, context) {
|
|
415
407
|
switch (true) {
|
|
416
|
-
case node.type === AST_NODE_TYPES.Identifier:
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
);
|
|
408
|
+
case node.type === AST_NODE_TYPES.Identifier: {
|
|
409
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
410
|
+
const object = VAR2.getVariableNode(VAR2.findVariable(node, initialScope), 0);
|
|
411
|
+
return isNewResizeObserver(object);
|
|
412
|
+
}
|
|
422
413
|
case node.type === AST_NODE_TYPES.MemberExpression:
|
|
423
414
|
return isFromObserver(node.object, context);
|
|
424
415
|
default:
|
|
@@ -436,7 +427,7 @@ function getCallKind3(node, context) {
|
|
|
436
427
|
}
|
|
437
428
|
}
|
|
438
429
|
function getFunctionKind2(node) {
|
|
439
|
-
return
|
|
430
|
+
return getPhaseKindOfFunction(node) ?? "other";
|
|
440
431
|
}
|
|
441
432
|
var no_leaked_resize_observer_default = createRule({
|
|
442
433
|
meta: {
|
|
@@ -457,25 +448,25 @@ var no_leaked_resize_observer_default = createRule({
|
|
|
457
448
|
if (!context.sourceCode.text.includes("ResizeObserver")) {
|
|
458
449
|
return {};
|
|
459
450
|
}
|
|
460
|
-
const
|
|
451
|
+
const fEntries = [];
|
|
461
452
|
const observers = [];
|
|
462
453
|
const oEntries = [];
|
|
463
454
|
const uEntries = [];
|
|
464
455
|
const dEntries = [];
|
|
465
456
|
return {
|
|
466
457
|
[":function"](node) {
|
|
467
|
-
const
|
|
468
|
-
|
|
458
|
+
const kind = getFunctionKind2(node);
|
|
459
|
+
fEntries.push({ kind, node });
|
|
469
460
|
},
|
|
470
461
|
[":function:exit"]() {
|
|
471
|
-
|
|
462
|
+
fEntries.pop();
|
|
472
463
|
},
|
|
473
464
|
["CallExpression"](node) {
|
|
474
|
-
const [_, fKind] = fStack.findLast((f) => f.at(1) !== "other") ?? [];
|
|
475
465
|
if (node.callee.type !== AST_NODE_TYPES.MemberExpression) {
|
|
476
466
|
return;
|
|
477
467
|
}
|
|
478
|
-
|
|
468
|
+
const fKind = fEntries.findLast((x) => x.kind !== "other")?.kind;
|
|
469
|
+
if (fKind === _ || !ERPhaseRelevance.has(fKind)) {
|
|
479
470
|
return;
|
|
480
471
|
}
|
|
481
472
|
const { object } = node.callee;
|
|
@@ -516,36 +507,42 @@ var no_leaked_resize_observer_default = createRule({
|
|
|
516
507
|
observerKind: "ResizeObserver",
|
|
517
508
|
phase: fKind
|
|
518
509
|
});
|
|
519
|
-
}).otherwise(
|
|
510
|
+
}).otherwise(() => _);
|
|
520
511
|
},
|
|
521
512
|
["NewExpression"](node) {
|
|
522
|
-
const
|
|
523
|
-
if (
|
|
513
|
+
const fEntry = fEntries.findLast((x) => x.kind !== "other");
|
|
514
|
+
if (fEntry === _) return;
|
|
515
|
+
if (!ERPhaseRelevance.has(fEntry.kind)) {
|
|
524
516
|
return;
|
|
525
517
|
}
|
|
526
518
|
if (!isNewResizeObserver(node)) {
|
|
527
519
|
return;
|
|
528
520
|
}
|
|
529
521
|
const id = getInstanceID(node);
|
|
530
|
-
if (
|
|
522
|
+
if (id === _) {
|
|
531
523
|
context.report({
|
|
532
524
|
messageId: "noLeakedResizeObserverNoFloatingInstance",
|
|
533
525
|
node
|
|
534
526
|
});
|
|
535
527
|
return;
|
|
536
528
|
}
|
|
537
|
-
observers.push(
|
|
529
|
+
observers.push({
|
|
530
|
+
id,
|
|
531
|
+
node,
|
|
532
|
+
phase: fEntry.kind,
|
|
533
|
+
phaseNode: fEntry.node
|
|
534
|
+
});
|
|
538
535
|
},
|
|
539
536
|
["Program:exit"]() {
|
|
540
|
-
for (const
|
|
537
|
+
for (const { id, node, phaseNode } of observers) {
|
|
541
538
|
if (dEntries.some((e) => isInstanceIDEqual(e.observer, id, context))) {
|
|
542
539
|
continue;
|
|
543
540
|
}
|
|
544
541
|
const oentries = oEntries.filter((e) => isInstanceIDEqual(e.observer, id, context));
|
|
545
542
|
const uentries = uEntries.filter((e) => isInstanceIDEqual(e.observer, id, context));
|
|
546
|
-
const isDynamic = (node2) => node2
|
|
543
|
+
const isDynamic = (node2) => node2?.type === AST_NODE_TYPES.CallExpression || AST2.isConditional(node2);
|
|
547
544
|
const isPhaseNode = (node2) => node2 === phaseNode;
|
|
548
|
-
const hasDynamicallyAdded = oentries.some((e) =>
|
|
545
|
+
const hasDynamicallyAdded = oentries.some((e) => !isPhaseNode(AST2.findParentNode(e.node, or(isDynamic, isPhaseNode))));
|
|
549
546
|
if (hasDynamicallyAdded) {
|
|
550
547
|
context.report({ messageId: "noLeakedResizeObserverInControlFlow", node });
|
|
551
548
|
continue;
|
|
@@ -595,31 +592,28 @@ var no_leaked_timeout_default = createRule({
|
|
|
595
592
|
if (!context.sourceCode.text.includes("setTimeout")) {
|
|
596
593
|
return {};
|
|
597
594
|
}
|
|
598
|
-
const
|
|
595
|
+
const fEntries = [];
|
|
599
596
|
const sEntries = [];
|
|
600
597
|
const rEntries = [];
|
|
601
598
|
function isInverseEntry(a, b) {
|
|
602
|
-
return isInstanceIDEqual(a.
|
|
599
|
+
return isInstanceIDEqual(a.timerId, b.timerId, context);
|
|
603
600
|
}
|
|
604
601
|
return {
|
|
605
602
|
[":function"](node) {
|
|
606
|
-
const
|
|
607
|
-
|
|
603
|
+
const kind = getPhaseKindOfFunction(node) ?? "other";
|
|
604
|
+
fEntries.push({ kind, node });
|
|
608
605
|
},
|
|
609
606
|
[":function:exit"]() {
|
|
610
|
-
|
|
607
|
+
fEntries.pop();
|
|
611
608
|
},
|
|
612
609
|
["CallExpression"](node) {
|
|
613
|
-
const
|
|
614
|
-
if (
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
if (!ERPhaseRelevance.has(fKind)) {
|
|
610
|
+
const fEntry = fEntries.findLast((f) => f.kind !== "other");
|
|
611
|
+
if (!ERPhaseRelevance.has(fEntry?.kind)) {
|
|
618
612
|
return;
|
|
619
613
|
}
|
|
620
614
|
switch (getCallKind4(node)) {
|
|
621
615
|
case "setTimeout": {
|
|
622
|
-
const timeoutIdNode =
|
|
616
|
+
const timeoutIdNode = VAR2.getVariableDeclaratorId(node);
|
|
623
617
|
if (timeoutIdNode == null) {
|
|
624
618
|
context.report({
|
|
625
619
|
messageId: "noLeakedTimeoutNoTimeoutId",
|
|
@@ -631,8 +625,8 @@ var no_leaked_timeout_default = createRule({
|
|
|
631
625
|
kind: "timeout",
|
|
632
626
|
node,
|
|
633
627
|
callee: node.callee,
|
|
634
|
-
phase:
|
|
635
|
-
|
|
628
|
+
phase: fEntry.kind,
|
|
629
|
+
timerId: timeoutIdNode
|
|
636
630
|
});
|
|
637
631
|
break;
|
|
638
632
|
}
|
|
@@ -645,8 +639,8 @@ var no_leaked_timeout_default = createRule({
|
|
|
645
639
|
kind: "timeout",
|
|
646
640
|
node,
|
|
647
641
|
callee: node.callee,
|
|
648
|
-
phase:
|
|
649
|
-
|
|
642
|
+
phase: fEntry.kind,
|
|
643
|
+
timerId: timeoutIdNode
|
|
650
644
|
});
|
|
651
645
|
break;
|
|
652
646
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-web-api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0-next.0",
|
|
4
4
|
"description": "ESLint React's ESLint plugin for interacting with Web APIs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
"eslint-plugin",
|
|
11
11
|
"eslint-plugin-react-web-api"
|
|
12
12
|
],
|
|
13
|
-
"homepage": "https://github.com/
|
|
13
|
+
"homepage": "https://github.com/Rel1cx/eslint-react",
|
|
14
14
|
"bugs": {
|
|
15
|
-
"url": "https://github.com/
|
|
15
|
+
"url": "https://github.com/Rel1cx/eslint-react/issues"
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/
|
|
19
|
+
"url": "git+https://github.com/Rel1cx/eslint-react.git",
|
|
20
20
|
"directory": "packages/plugins/eslint-plugin-react-web-api"
|
|
21
21
|
},
|
|
22
22
|
"license": "MIT",
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
"@typescript-eslint/utils": "^8.19.1",
|
|
47
47
|
"string-ts": "^2.2.0",
|
|
48
48
|
"ts-pattern": "^5.6.0",
|
|
49
|
-
"@eslint-react/core": "1.
|
|
50
|
-
"@eslint-react/eff": "1.
|
|
51
|
-
"@eslint-react/jsx": "1.
|
|
52
|
-
"@eslint-react/shared": "1.
|
|
53
|
-
"@eslint-react/
|
|
54
|
-
"@eslint-react/
|
|
55
|
-
"@eslint-react/
|
|
49
|
+
"@eslint-react/core": "1.24.0-next.0",
|
|
50
|
+
"@eslint-react/eff": "1.24.0-next.0",
|
|
51
|
+
"@eslint-react/jsx": "1.24.0-next.0",
|
|
52
|
+
"@eslint-react/shared": "1.24.0-next.0",
|
|
53
|
+
"@eslint-react/var": "1.24.0-next.0",
|
|
54
|
+
"@eslint-react/types": "1.24.0-next.0",
|
|
55
|
+
"@eslint-react/ast": "1.24.0-next.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/react": "^19.0.4",
|