eslint-plugin-react-web-api 1.33.0 → 1.34.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +400 -396
  2. package/dist/index.mjs +400 -396
  3. package/package.json +7 -7
package/dist/index.mjs CHANGED
@@ -32,7 +32,7 @@ var settings = {
32
32
 
33
33
  // package.json
34
34
  var name2 = "eslint-plugin-react-web-api";
35
- var version = "1.33.0";
35
+ var version = "1.34.0-beta.1";
36
36
  var createRule = createRuleForPlugin("web-api");
37
37
  function getPhaseKindOfFunction(node) {
38
38
  return match(node).when(isFunctionOfUseEffectSetup, () => "setup").when(isFunctionOfUseEffectCleanup, () => "cleanup").when(isFunctionOfComponentDidMount, () => "mount").when(isFunctionOfComponentWillUnmount, () => "unmount").otherwise(() => _);
@@ -135,139 +135,140 @@ var no_leaked_event_listener_default = createRule({
135
135
  schema: []
136
136
  },
137
137
  name: RULE_NAME,
138
- create(context) {
139
- if (!context.sourceCode.text.includes("addEventListener")) {
140
- return {};
138
+ create,
139
+ defaultOptions: []
140
+ });
141
+ function create(context) {
142
+ if (!context.sourceCode.text.includes("addEventListener")) {
143
+ return {};
144
+ }
145
+ if (!/use\w*Effect|componentDidMount|componentWillUnmount/u.test(context.sourceCode.text)) {
146
+ return {};
147
+ }
148
+ const fEntries = [];
149
+ const aEntries = [];
150
+ const rEntries = [];
151
+ const abortedSignals = [];
152
+ function isSameObject(a, b) {
153
+ switch (true) {
154
+ case (a.type === AST_NODE_TYPES.MemberExpression && b.type === AST_NODE_TYPES.MemberExpression):
155
+ return AST.isNodeEqual(a.object, b.object);
156
+ // TODO: Maybe there other cases to consider here.
157
+ default:
158
+ return false;
141
159
  }
142
- if (!/use\w*Effect|componentDidMount|componentWillUnmount/u.test(context.sourceCode.text)) {
143
- return {};
160
+ }
161
+ function isInverseEntry(aEntry, rEntry) {
162
+ const { type: aType, callee: aCallee, capture: aCapture, listener: aListener, phase: aPhase } = aEntry;
163
+ const { type: rType, callee: rCallee, capture: rCapture, listener: rListener, phase: rPhase } = rEntry;
164
+ if (!isInversePhase(aPhase, rPhase)) {
165
+ return false;
144
166
  }
145
- const fEntries = [];
146
- const aEntries = [];
147
- const rEntries = [];
148
- const abortedSignals = [];
149
- function isSameObject(a, b) {
150
- switch (true) {
151
- case (a.type === AST_NODE_TYPES.MemberExpression && b.type === AST_NODE_TYPES.MemberExpression):
152
- return AST.isNodeEqual(a.object, b.object);
153
- // TODO: Maybe there other cases to consider here.
154
- default:
155
- return false;
156
- }
167
+ return isSameObject(aCallee, rCallee) && AST.isNodeEqual(aListener, rListener) && VAR.isNodeValueEqual(aType, rType, [
168
+ context.sourceCode.getScope(aType),
169
+ context.sourceCode.getScope(rType)
170
+ ]) && aCapture === rCapture;
171
+ }
172
+ function checkInlineFunction(node, callKind, options) {
173
+ const listener = node.arguments.at(1);
174
+ if (!AST.isFunction(listener)) {
175
+ return;
157
176
  }
158
- function isInverseEntry(aEntry, rEntry) {
159
- const { type: aType, callee: aCallee, capture: aCapture, listener: aListener, phase: aPhase } = aEntry;
160
- const { type: rType, callee: rCallee, capture: rCapture, listener: rListener, phase: rPhase } = rEntry;
161
- if (!isInversePhase(aPhase, rPhase)) {
162
- return false;
163
- }
164
- return isSameObject(aCallee, rCallee) && AST.isNodeEqual(aListener, rListener) && VAR.isNodeValueEqual(aType, rType, [
165
- context.sourceCode.getScope(aType),
166
- context.sourceCode.getScope(rType)
167
- ]) && aCapture === rCapture;
177
+ if (options.signal != null) {
178
+ return;
168
179
  }
169
- function checkInlineFunction(node, callKind, options) {
170
- const listener = node.arguments.at(1);
171
- if (!AST.isFunction(listener)) {
180
+ context.report({
181
+ messageId: "unexpectedInlineFunction",
182
+ node: listener,
183
+ data: { eventMethodKind: callKind }
184
+ });
185
+ }
186
+ return {
187
+ [":function"](node) {
188
+ const kind = getFunctionKind(node);
189
+ fEntries.push({ kind, node });
190
+ },
191
+ [":function:exit"]() {
192
+ fEntries.pop();
193
+ },
194
+ ["CallExpression"](node) {
195
+ const fKind = fEntries.findLast((x) => x.kind !== "other")?.kind;
196
+ if (fKind == null) {
172
197
  return;
173
198
  }
174
- if (options.signal != null) {
199
+ if (!ERPhaseRelevance.has(fKind)) {
175
200
  return;
176
201
  }
177
- context.report({
178
- messageId: "unexpectedInlineFunction",
179
- node: listener,
180
- data: { eventMethodKind: callKind }
181
- });
182
- }
183
- return {
184
- [":function"](node) {
185
- const kind = getFunctionKind(node);
186
- fEntries.push({ kind, node });
187
- },
188
- [":function:exit"]() {
189
- fEntries.pop();
190
- },
191
- ["CallExpression"](node) {
192
- const fKind = fEntries.findLast((x) => x.kind !== "other")?.kind;
193
- if (fKind == null) {
202
+ match(getCallKind(node)).with("addEventListener", (callKind) => {
203
+ const [type, listener, options] = node.arguments;
204
+ if (type == null || listener == null) {
194
205
  return;
195
206
  }
196
- if (!ERPhaseRelevance.has(fKind)) {
207
+ const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
208
+ const { callee } = node;
209
+ checkInlineFunction(node, callKind, opts);
210
+ aEntries.push({
211
+ ...opts,
212
+ kind: "addEventListener",
213
+ type,
214
+ node,
215
+ callee,
216
+ listener,
217
+ phase: fKind
218
+ });
219
+ }).with("removeEventListener", (callKind) => {
220
+ const [type, listener, options] = node.arguments;
221
+ if (type == null || listener == null) {
197
222
  return;
198
223
  }
199
- match(getCallKind(node)).with("addEventListener", (callKind) => {
200
- const [type, listener, options] = node.arguments;
201
- if (type == null || listener == null) {
202
- return;
203
- }
204
- const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
205
- const { callee } = node;
206
- checkInlineFunction(node, callKind, opts);
207
- aEntries.push({
208
- ...opts,
209
- kind: "addEventListener",
210
- type,
211
- node,
212
- callee,
213
- listener,
214
- phase: fKind
215
- });
216
- }).with("removeEventListener", (callKind) => {
217
- const [type, listener, options] = node.arguments;
218
- if (type == null || listener == null) {
219
- return;
220
- }
221
- const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
222
- const { callee } = node;
223
- checkInlineFunction(node, callKind, opts);
224
- rEntries.push({
225
- ...opts,
226
- kind: "removeEventListener",
227
- type,
228
- node,
229
- callee,
230
- listener,
231
- phase: fKind
232
- });
233
- }).with("abort", () => {
234
- abortedSignals.push(node.callee);
235
- }).otherwise(() => _);
236
- },
237
- ["Program:exit"]() {
238
- for (const aEntry of aEntries) {
239
- const signal = aEntry.signal;
240
- if (signal != null && abortedSignals.some((a) => isSameObject(a, signal))) {
224
+ const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
225
+ const { callee } = node;
226
+ checkInlineFunction(node, callKind, opts);
227
+ rEntries.push({
228
+ ...opts,
229
+ kind: "removeEventListener",
230
+ type,
231
+ node,
232
+ callee,
233
+ listener,
234
+ phase: fKind
235
+ });
236
+ }).with("abort", () => {
237
+ abortedSignals.push(node.callee);
238
+ }).otherwise(() => _);
239
+ },
240
+ ["Program:exit"]() {
241
+ for (const aEntry of aEntries) {
242
+ const signal = aEntry.signal;
243
+ if (signal != null && abortedSignals.some((a) => isSameObject(a, signal))) {
244
+ continue;
245
+ }
246
+ if (rEntries.some((rEntry) => isInverseEntry(aEntry, rEntry))) {
247
+ continue;
248
+ }
249
+ switch (aEntry.phase) {
250
+ case "setup":
251
+ case "cleanup":
252
+ context.report({
253
+ messageId: "expectedRemoveEventListenerInCleanup",
254
+ node: aEntry.node,
255
+ data: {
256
+ effectMethodKind: "useEffect"
257
+ }
258
+ });
241
259
  continue;
242
- }
243
- if (rEntries.some((rEntry) => isInverseEntry(aEntry, rEntry))) {
260
+ case "mount":
261
+ case "unmount":
262
+ context.report({
263
+ messageId: "expectedRemoveEventListenerInUnmount",
264
+ node: aEntry.node
265
+ });
244
266
  continue;
245
- }
246
- switch (aEntry.phase) {
247
- case "setup":
248
- case "cleanup":
249
- context.report({
250
- messageId: "expectedRemoveEventListenerInCleanup",
251
- node: aEntry.node,
252
- data: {
253
- effectMethodKind: "useEffect"
254
- }
255
- });
256
- continue;
257
- case "mount":
258
- case "unmount":
259
- context.report({
260
- messageId: "expectedRemoveEventListenerInUnmount",
261
- node: aEntry.node
262
- });
263
- continue;
264
- }
265
267
  }
266
268
  }
267
- };
268
- },
269
- defaultOptions: []
270
- });
269
+ }
270
+ };
271
+ }
271
272
  var RULE_NAME2 = "no-leaked-interval";
272
273
  var RULE_FEATURES2 = [
273
274
  "CHK"
@@ -297,107 +298,108 @@ var no_leaked_interval_default = createRule({
297
298
  schema: []
298
299
  },
299
300
  name: RULE_NAME2,
300
- create(context) {
301
- if (!context.sourceCode.text.includes("setInterval")) {
302
- return {};
303
- }
304
- const fEntries = [];
305
- const sEntries = [];
306
- const cEntries = [];
307
- function isInverseEntry(a, b) {
308
- return isInstanceIdEqual(context, a.timerId, b.timerId);
309
- }
310
- return {
311
- [":function"](node) {
312
- const kind = getPhaseKindOfFunction(node) ?? "other";
313
- fEntries.push({ kind, node });
314
- },
315
- [":function:exit"]() {
316
- fEntries.pop();
317
- },
318
- ["CallExpression"](node) {
319
- switch (getCallKind2(node)) {
320
- case "setInterval": {
321
- const fEntry = fEntries.findLast((x) => x.kind !== "other");
322
- if (fEntry == null) {
323
- break;
324
- }
325
- if (!ERPhaseRelevance.has(fEntry.kind)) {
326
- break;
327
- }
328
- const intervalIdNode = VAR.getVariableDeclaratorId(node);
329
- if (intervalIdNode == null) {
330
- context.report({
331
- messageId: "expectedIntervalId",
332
- node
333
- });
334
- break;
335
- }
336
- sEntries.push({
337
- kind: "interval",
338
- node,
339
- callee: node.callee,
340
- phase: fEntry.kind,
341
- timerId: intervalIdNode
342
- });
301
+ create: create2,
302
+ defaultOptions: []
303
+ });
304
+ function create2(context) {
305
+ if (!context.sourceCode.text.includes("setInterval")) {
306
+ return {};
307
+ }
308
+ const fEntries = [];
309
+ const sEntries = [];
310
+ const cEntries = [];
311
+ function isInverseEntry(a, b) {
312
+ return isInstanceIdEqual(context, a.timerId, b.timerId);
313
+ }
314
+ return {
315
+ [":function"](node) {
316
+ const kind = getPhaseKindOfFunction(node) ?? "other";
317
+ fEntries.push({ kind, node });
318
+ },
319
+ [":function:exit"]() {
320
+ fEntries.pop();
321
+ },
322
+ ["CallExpression"](node) {
323
+ switch (getCallKind2(node)) {
324
+ case "setInterval": {
325
+ const fEntry = fEntries.findLast((x) => x.kind !== "other");
326
+ if (fEntry == null) {
327
+ break;
328
+ }
329
+ if (!ERPhaseRelevance.has(fEntry.kind)) {
343
330
  break;
344
331
  }
345
- case "clearInterval": {
346
- const fEntry = fEntries.findLast((x) => x.kind !== "other");
347
- if (fEntry == null) {
348
- break;
349
- }
350
- if (!ERPhaseRelevance.has(fEntry.kind)) {
351
- break;
352
- }
353
- const [intervalIdNode] = node.arguments;
354
- if (intervalIdNode == null) {
355
- break;
356
- }
357
- cEntries.push({
358
- kind: "interval",
359
- node,
360
- callee: node.callee,
361
- phase: fEntry.kind,
362
- timerId: intervalIdNode
332
+ const intervalIdNode = VAR.getVariableDeclaratorId(node);
333
+ if (intervalIdNode == null) {
334
+ context.report({
335
+ messageId: "expectedIntervalId",
336
+ node
363
337
  });
364
338
  break;
365
339
  }
340
+ sEntries.push({
341
+ kind: "interval",
342
+ node,
343
+ callee: node.callee,
344
+ phase: fEntry.kind,
345
+ timerId: intervalIdNode
346
+ });
347
+ break;
366
348
  }
367
- },
368
- ["Program:exit"]() {
369
- for (const sEntry of sEntries) {
370
- if (cEntries.some((cEntry) => isInverseEntry(sEntry, cEntry))) {
371
- continue;
349
+ case "clearInterval": {
350
+ const fEntry = fEntries.findLast((x) => x.kind !== "other");
351
+ if (fEntry == null) {
352
+ break;
372
353
  }
373
- switch (sEntry.phase) {
374
- case "setup":
375
- case "cleanup":
376
- context.report({
377
- messageId: "expectedClearIntervalInCleanup",
378
- node: sEntry.node,
379
- data: {
380
- kind: "useEffect"
381
- }
382
- });
383
- continue;
384
- case "mount":
385
- case "unmount":
386
- context.report({
387
- messageId: "expectedClearIntervalInUnmount",
388
- node: sEntry.node,
389
- data: {
390
- kind: "componentDidMount"
391
- }
392
- });
393
- continue;
354
+ if (!ERPhaseRelevance.has(fEntry.kind)) {
355
+ break;
356
+ }
357
+ const [intervalIdNode] = node.arguments;
358
+ if (intervalIdNode == null) {
359
+ break;
394
360
  }
361
+ cEntries.push({
362
+ kind: "interval",
363
+ node,
364
+ callee: node.callee,
365
+ phase: fEntry.kind,
366
+ timerId: intervalIdNode
367
+ });
368
+ break;
395
369
  }
396
370
  }
397
- };
398
- },
399
- defaultOptions: []
400
- });
371
+ },
372
+ ["Program:exit"]() {
373
+ for (const sEntry of sEntries) {
374
+ if (cEntries.some((cEntry) => isInverseEntry(sEntry, cEntry))) {
375
+ continue;
376
+ }
377
+ switch (sEntry.phase) {
378
+ case "setup":
379
+ case "cleanup":
380
+ context.report({
381
+ messageId: "expectedClearIntervalInCleanup",
382
+ node: sEntry.node,
383
+ data: {
384
+ kind: "useEffect"
385
+ }
386
+ });
387
+ continue;
388
+ case "mount":
389
+ case "unmount":
390
+ context.report({
391
+ messageId: "expectedClearIntervalInUnmount",
392
+ node: sEntry.node,
393
+ data: {
394
+ kind: "componentDidMount"
395
+ }
396
+ });
397
+ continue;
398
+ }
399
+ }
400
+ }
401
+ };
402
+ }
401
403
  var RULE_NAME3 = "no-leaked-resize-observer";
402
404
  var RULE_FEATURES3 = [
403
405
  "CHK"
@@ -446,121 +448,122 @@ var no_leaked_resize_observer_default = createRule({
446
448
  schema: []
447
449
  },
448
450
  name: RULE_NAME3,
449
- create(context) {
450
- if (!context.sourceCode.text.includes("ResizeObserver")) {
451
- return {};
452
- }
453
- const fEntries = [];
454
- const observers = [];
455
- const oEntries = [];
456
- const uEntries = [];
457
- const dEntries = [];
458
- return {
459
- [":function"](node) {
460
- const kind = getFunctionKind2(node);
461
- fEntries.push({ kind, node });
462
- },
463
- [":function:exit"]() {
464
- fEntries.pop();
465
- },
466
- ["CallExpression"](node) {
467
- if (node.callee.type !== AST_NODE_TYPES.MemberExpression) {
468
- return;
469
- }
470
- const fKind = fEntries.findLast((x) => x.kind !== "other")?.kind;
471
- if (fKind == null || !ERPhaseRelevance.has(fKind)) {
472
- return;
473
- }
474
- const { object } = node.callee;
475
- match(getCallKind3(context, node)).with("disconnect", () => {
476
- dEntries.push({
477
- kind: "disconnect",
478
- node,
479
- callee: node.callee,
480
- observer: object,
481
- observerKind: "ResizeObserver",
482
- phase: fKind
483
- });
484
- }).with("observe", () => {
485
- const [element] = node.arguments;
486
- if (element == null) {
487
- return;
488
- }
489
- oEntries.push({
490
- kind: "observe",
491
- node,
492
- callee: node.callee,
493
- element,
494
- observer: object,
495
- observerKind: "ResizeObserver",
496
- phase: fKind
497
- });
498
- }).with("unobserve", () => {
499
- const [element] = node.arguments;
500
- if (element == null) {
501
- return;
502
- }
503
- uEntries.push({
504
- kind: "unobserve",
505
- node,
506
- callee: node.callee,
507
- element,
508
- observer: object,
509
- observerKind: "ResizeObserver",
510
- phase: fKind
511
- });
512
- }).otherwise(() => _);
513
- },
514
- ["NewExpression"](node) {
515
- const fEntry = fEntries.findLast((x) => x.kind !== "other");
516
- if (fEntry == null) return;
517
- if (!ERPhaseRelevance.has(fEntry.kind)) {
518
- return;
519
- }
520
- if (!isNewResizeObserver(node)) {
451
+ create: create3,
452
+ defaultOptions: []
453
+ });
454
+ function create3(context) {
455
+ if (!context.sourceCode.text.includes("ResizeObserver")) {
456
+ return {};
457
+ }
458
+ const fEntries = [];
459
+ const observers = [];
460
+ const oEntries = [];
461
+ const uEntries = [];
462
+ const dEntries = [];
463
+ return {
464
+ [":function"](node) {
465
+ const kind = getFunctionKind2(node);
466
+ fEntries.push({ kind, node });
467
+ },
468
+ [":function:exit"]() {
469
+ fEntries.pop();
470
+ },
471
+ ["CallExpression"](node) {
472
+ if (node.callee.type !== AST_NODE_TYPES.MemberExpression) {
473
+ return;
474
+ }
475
+ const fKind = fEntries.findLast((x) => x.kind !== "other")?.kind;
476
+ if (fKind == null || !ERPhaseRelevance.has(fKind)) {
477
+ return;
478
+ }
479
+ const { object } = node.callee;
480
+ match(getCallKind3(context, node)).with("disconnect", () => {
481
+ dEntries.push({
482
+ kind: "disconnect",
483
+ node,
484
+ callee: node.callee,
485
+ observer: object,
486
+ observerKind: "ResizeObserver",
487
+ phase: fKind
488
+ });
489
+ }).with("observe", () => {
490
+ const [element] = node.arguments;
491
+ if (element == null) {
521
492
  return;
522
493
  }
523
- const id = getInstanceId(node);
524
- if (id == null) {
525
- context.report({
526
- messageId: "unexpectedFloatingInstance",
527
- node
528
- });
494
+ oEntries.push({
495
+ kind: "observe",
496
+ node,
497
+ callee: node.callee,
498
+ element,
499
+ observer: object,
500
+ observerKind: "ResizeObserver",
501
+ phase: fKind
502
+ });
503
+ }).with("unobserve", () => {
504
+ const [element] = node.arguments;
505
+ if (element == null) {
529
506
  return;
530
507
  }
531
- observers.push({
532
- id,
508
+ uEntries.push({
509
+ kind: "unobserve",
533
510
  node,
534
- phase: fEntry.kind,
535
- phaseNode: fEntry.node
511
+ callee: node.callee,
512
+ element,
513
+ observer: object,
514
+ observerKind: "ResizeObserver",
515
+ phase: fKind
536
516
  });
537
- },
538
- ["Program:exit"]() {
539
- for (const { id, node, phaseNode } of observers) {
540
- if (dEntries.some((e) => isInstanceIdEqual(context, e.observer, id))) {
541
- continue;
542
- }
543
- const oentries = oEntries.filter((e) => isInstanceIdEqual(context, e.observer, id));
544
- const uentries = uEntries.filter((e) => isInstanceIdEqual(context, e.observer, id));
545
- const isDynamic = (node2) => node2?.type === AST_NODE_TYPES.CallExpression || AST.isConditional(node2);
546
- const isPhaseNode = (node2) => node2 === phaseNode;
547
- const hasDynamicallyAdded = oentries.some((e) => !isPhaseNode(AST.findParentNode(e.node, or(isDynamic, isPhaseNode))));
548
- if (hasDynamicallyAdded) {
549
- context.report({ messageId: "expectedDisconnectInControlFlow", node });
517
+ }).otherwise(() => _);
518
+ },
519
+ ["NewExpression"](node) {
520
+ const fEntry = fEntries.findLast((x) => x.kind !== "other");
521
+ if (fEntry == null) return;
522
+ if (!ERPhaseRelevance.has(fEntry.kind)) {
523
+ return;
524
+ }
525
+ if (!isNewResizeObserver(node)) {
526
+ return;
527
+ }
528
+ const id = getInstanceId(node);
529
+ if (id == null) {
530
+ context.report({
531
+ messageId: "unexpectedFloatingInstance",
532
+ node
533
+ });
534
+ return;
535
+ }
536
+ observers.push({
537
+ id,
538
+ node,
539
+ phase: fEntry.kind,
540
+ phaseNode: fEntry.node
541
+ });
542
+ },
543
+ ["Program:exit"]() {
544
+ for (const { id, node, phaseNode } of observers) {
545
+ if (dEntries.some((e) => isInstanceIdEqual(context, e.observer, id))) {
546
+ continue;
547
+ }
548
+ const oentries = oEntries.filter((e) => isInstanceIdEqual(context, e.observer, id));
549
+ const uentries = uEntries.filter((e) => isInstanceIdEqual(context, e.observer, id));
550
+ const isDynamic = (node2) => node2?.type === AST_NODE_TYPES.CallExpression || AST.isConditional(node2);
551
+ const isPhaseNode = (node2) => node2 === phaseNode;
552
+ const hasDynamicallyAdded = oentries.some((e) => !isPhaseNode(AST.findParentNode(e.node, or(isDynamic, isPhaseNode))));
553
+ if (hasDynamicallyAdded) {
554
+ context.report({ messageId: "expectedDisconnectInControlFlow", node });
555
+ continue;
556
+ }
557
+ for (const oEntry of oentries) {
558
+ if (uentries.some((uEntry) => isInstanceIdEqual(context, uEntry.element, oEntry.element))) {
550
559
  continue;
551
560
  }
552
- for (const oEntry of oentries) {
553
- if (uentries.some((uEntry) => isInstanceIdEqual(context, uEntry.element, oEntry.element))) {
554
- continue;
555
- }
556
- context.report({ messageId: "expectedDisconnectOrUnobserveInCleanup", node: oEntry.node });
557
- }
561
+ context.report({ messageId: "expectedDisconnectOrUnobserveInCleanup", node: oEntry.node });
558
562
  }
559
563
  }
560
- };
561
- },
562
- defaultOptions: []
563
- });
564
+ }
565
+ };
566
+ }
564
567
  var RULE_NAME4 = "no-leaked-timeout";
565
568
  var RULE_FEATURES4 = [
566
569
  "CHK"
@@ -590,97 +593,98 @@ var no_leaked_timeout_default = createRule({
590
593
  schema: []
591
594
  },
592
595
  name: RULE_NAME4,
593
- create(context) {
594
- if (!context.sourceCode.text.includes("setTimeout")) {
595
- return {};
596
- }
597
- const fEntries = [];
598
- const sEntries = [];
599
- const rEntries = [];
600
- function isInverseEntry(a, b) {
601
- return isInstanceIdEqual(context, a.timerId, b.timerId);
602
- }
603
- return {
604
- [":function"](node) {
605
- const kind = getPhaseKindOfFunction(node) ?? "other";
606
- fEntries.push({ kind, node });
607
- },
608
- [":function:exit"]() {
609
- fEntries.pop();
610
- },
611
- ["CallExpression"](node) {
612
- const fEntry = fEntries.findLast((f) => f.kind !== "other");
613
- if (!ERPhaseRelevance.has(fEntry?.kind)) {
614
- return;
615
- }
616
- switch (getCallKind4(node)) {
617
- case "setTimeout": {
618
- const timeoutIdNode = VAR.getVariableDeclaratorId(node);
619
- if (timeoutIdNode == null) {
620
- context.report({
621
- messageId: "expectedTimeoutId",
622
- node
623
- });
624
- break;
625
- }
626
- sEntries.push({
627
- kind: "timeout",
628
- node,
629
- callee: node.callee,
630
- phase: fEntry.kind,
631
- timerId: timeoutIdNode
596
+ create: create4,
597
+ defaultOptions: []
598
+ });
599
+ function create4(context) {
600
+ if (!context.sourceCode.text.includes("setTimeout")) {
601
+ return {};
602
+ }
603
+ const fEntries = [];
604
+ const sEntries = [];
605
+ const rEntries = [];
606
+ function isInverseEntry(a, b) {
607
+ return isInstanceIdEqual(context, a.timerId, b.timerId);
608
+ }
609
+ return {
610
+ [":function"](node) {
611
+ const kind = getPhaseKindOfFunction(node) ?? "other";
612
+ fEntries.push({ kind, node });
613
+ },
614
+ [":function:exit"]() {
615
+ fEntries.pop();
616
+ },
617
+ ["CallExpression"](node) {
618
+ const fEntry = fEntries.findLast((f) => f.kind !== "other");
619
+ if (!ERPhaseRelevance.has(fEntry?.kind)) {
620
+ return;
621
+ }
622
+ switch (getCallKind4(node)) {
623
+ case "setTimeout": {
624
+ const timeoutIdNode = VAR.getVariableDeclaratorId(node);
625
+ if (timeoutIdNode == null) {
626
+ context.report({
627
+ messageId: "expectedTimeoutId",
628
+ node
632
629
  });
633
630
  break;
634
631
  }
635
- case "clearTimeout": {
636
- const [timeoutIdNode] = node.arguments;
637
- if (timeoutIdNode == null) {
638
- break;
639
- }
640
- rEntries.push({
641
- kind: "timeout",
642
- node,
643
- callee: node.callee,
644
- phase: fEntry.kind,
645
- timerId: timeoutIdNode
646
- });
632
+ sEntries.push({
633
+ kind: "timeout",
634
+ node,
635
+ callee: node.callee,
636
+ phase: fEntry.kind,
637
+ timerId: timeoutIdNode
638
+ });
639
+ break;
640
+ }
641
+ case "clearTimeout": {
642
+ const [timeoutIdNode] = node.arguments;
643
+ if (timeoutIdNode == null) {
647
644
  break;
648
645
  }
646
+ rEntries.push({
647
+ kind: "timeout",
648
+ node,
649
+ callee: node.callee,
650
+ phase: fEntry.kind,
651
+ timerId: timeoutIdNode
652
+ });
653
+ break;
649
654
  }
650
- },
651
- ["Program:exit"]() {
652
- for (const sEntry of sEntries) {
653
- if (rEntries.some((rEntry) => isInverseEntry(sEntry, rEntry))) {
655
+ }
656
+ },
657
+ ["Program:exit"]() {
658
+ for (const sEntry of sEntries) {
659
+ if (rEntries.some((rEntry) => isInverseEntry(sEntry, rEntry))) {
660
+ continue;
661
+ }
662
+ switch (sEntry.phase) {
663
+ case "setup":
664
+ case "cleanup":
665
+ context.report({
666
+ messageId: "expectedClearTimeoutInCleanup",
667
+ node: sEntry.node,
668
+ data: {
669
+ kind: "useEffect"
670
+ }
671
+ });
672
+ continue;
673
+ case "mount":
674
+ case "unmount":
675
+ context.report({
676
+ messageId: "expectedClearTimeoutInUnmount",
677
+ node: sEntry.node,
678
+ data: {
679
+ kind: "componentDidMount"
680
+ }
681
+ });
654
682
  continue;
655
- }
656
- switch (sEntry.phase) {
657
- case "setup":
658
- case "cleanup":
659
- context.report({
660
- messageId: "expectedClearTimeoutInCleanup",
661
- node: sEntry.node,
662
- data: {
663
- kind: "useEffect"
664
- }
665
- });
666
- continue;
667
- case "mount":
668
- case "unmount":
669
- context.report({
670
- messageId: "expectedClearTimeoutInUnmount",
671
- node: sEntry.node,
672
- data: {
673
- kind: "componentDidMount"
674
- }
675
- });
676
- continue;
677
- }
678
683
  }
679
684
  }
680
- };
681
- },
682
- defaultOptions: []
683
- });
685
+ }
686
+ };
687
+ }
684
688
 
685
689
  // src/plugin.ts
686
690
  var plugin = {