eslint-plugin-react-web-api 3.0.0-next.6 → 3.0.0-next.61

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 CHANGED
@@ -1,20 +1,9 @@
1
- import * as _eslint_react_shared0 from "@eslint-react/shared";
1
+ import { ESLint, Linter } from "eslint";
2
2
 
3
3
  //#region src/index.d.ts
4
- declare const _default: {
5
- configs: {
6
- recommended: {
7
- plugins: {};
8
- name?: string;
9
- rules?: Record<string, _eslint_react_shared0.RuleConfig>;
10
- settings?: _eslint_react_shared0.SettingsConfig;
11
- };
12
- };
13
- meta: {
14
- name: string;
15
- version: string;
16
- };
17
- rules: Record<string, _eslint_react_shared0.CompatibleRule>;
4
+ type ConfigName = "recommended";
5
+ declare const finalPlugin: ESLint.Plugin & {
6
+ configs: Record<ConfigName, Linter.Config>;
18
7
  };
19
8
  //#endregion
20
- export { _default as default };
9
+ export { finalPlugin as default };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { DEFAULT_ESLINT_REACT_SETTINGS, WEBSITE_URL, getConfigAdapters } from "@eslint-react/shared";
1
+ import { DEFAULT_ESLINT_REACT_SETTINGS, WEBSITE_URL, defineRuleListener } from "@eslint-react/shared";
2
2
  import * as ast from "@eslint-react/ast";
3
3
  import * as core from "@eslint-react/core";
4
4
  import { dual, or, unit } from "@eslint-react/eff";
5
- import { findEnclosingAssignmentTarget, findProperty, findVariable, getVariableDefinitionNode, isAssignmentTargetEqual, isNodeEqual } from "@eslint-react/var";
5
+ import { findEnclosingAssignmentTarget, findVariable, isAssignmentTargetEqual, isValueEqual } from "@eslint-react/var";
6
6
  import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
7
7
  import { getStaticValue } from "@typescript-eslint/utils/ast-utils";
8
8
  import { P, isMatching, match } from "ts-pattern";
@@ -24,26 +24,10 @@ var __exportAll = (all, no_symbols) => {
24
24
  return target;
25
25
  };
26
26
 
27
- //#endregion
28
- //#region src/configs/recommended.ts
29
- var recommended_exports = /* @__PURE__ */ __exportAll({
30
- name: () => name$1,
31
- rules: () => rules,
32
- settings: () => settings
33
- });
34
- const name$1 = "react-web-api/recommended";
35
- const rules = {
36
- "react-web-api/no-leaked-event-listener": "warn",
37
- "react-web-api/no-leaked-interval": "warn",
38
- "react-web-api/no-leaked-resize-observer": "warn",
39
- "react-web-api/no-leaked-timeout": "warn"
40
- };
41
- const settings = { "react-x": DEFAULT_ESLINT_REACT_SETTINGS };
42
-
43
27
  //#endregion
44
28
  //#region package.json
45
- var name = "eslint-plugin-react-web-api";
46
- var version = "3.0.0-next.6";
29
+ var name$1 = "eslint-plugin-react-web-api";
30
+ var version = "3.0.0-next.61";
47
31
 
48
32
  //#endregion
49
33
  //#region src/types/component-phase.ts
@@ -64,7 +48,7 @@ function getDocsUrl(ruleName) {
64
48
  const createRule = ESLintUtils.RuleCreator(getDocsUrl);
65
49
 
66
50
  //#endregion
67
- //#region src/rules/no-leaked-event-listener.ts
51
+ //#region src/rules/no-leaked-event-listener/no-leaked-event-listener.ts
68
52
  const RULE_NAME$3 = "no-leaked-event-listener";
69
53
  const defaultOptions = {
70
54
  capture: false,
@@ -83,19 +67,32 @@ function getFunctionKind$1(node) {
83
67
  function getSignalValueExpression(node, initialScope) {
84
68
  if (node == null) return unit;
85
69
  switch (node.type) {
86
- case AST_NODE_TYPES.Identifier: return getSignalValueExpression(getVariableDefinitionNode(findVariable(node, initialScope), 0), initialScope);
70
+ case AST_NODE_TYPES.Identifier: {
71
+ function resolve(v) {
72
+ if (v == null) return unit;
73
+ const def = v.defs.at(0);
74
+ if (def == null) return unit;
75
+ if ("init" in def.node && def.node.init != null && !("declarations" in def.node.init)) return def.node.init;
76
+ return unit;
77
+ }
78
+ return getSignalValueExpression(resolve(findVariable(node, initialScope)), initialScope);
79
+ }
87
80
  case AST_NODE_TYPES.MemberExpression: return node;
88
81
  default: return unit;
89
82
  }
90
83
  }
91
84
  function getOptions(node, initialScope) {
92
- function findProp(properties, propName) {
93
- return findProperty(propName, properties, initialScope);
94
- }
95
85
  function getOpts(node) {
96
86
  switch (node.type) {
97
87
  case AST_NODE_TYPES.Identifier: {
98
- const variableNode = getVariableDefinitionNode(findVariable(node, initialScope), 0);
88
+ function resolve(v) {
89
+ if (v == null) return unit;
90
+ const def = v.defs.at(0);
91
+ if (def == null) return unit;
92
+ if ("init" in def.node && def.node.init != null && !("declarations" in def.node.init)) return def.node.init;
93
+ return unit;
94
+ }
95
+ const variableNode = resolve(findVariable(node, initialScope));
99
96
  if (variableNode?.type === AST_NODE_TYPES.ObjectExpression) return getOpts(variableNode);
100
97
  return defaultOptions;
101
98
  }
@@ -104,14 +101,14 @@ function getOptions(node, initialScope) {
104
101
  capture: Boolean(node.value)
105
102
  };
106
103
  case AST_NODE_TYPES.ObjectExpression: {
107
- const vCapture = match(findProp(node.properties, "capture")).with(P.nullish, () => false).with({ type: AST_NODE_TYPES.Property }, (prop) => {
104
+ const vCapture = match(ast.findProperty(node.properties, "capture")).with(P.nullish, () => false).with({ type: AST_NODE_TYPES.Property }, (prop) => {
108
105
  const value = prop.value;
109
106
  switch (value.type) {
110
107
  case AST_NODE_TYPES.Literal: return Boolean(value.value);
111
108
  default: return Boolean(getStaticValue(value, initialScope)?.value);
112
109
  }
113
110
  }).otherwise(() => false);
114
- const pSignal = findProp(node.properties, "signal");
111
+ const pSignal = ast.findProperty(node.properties, "signal");
115
112
  return {
116
113
  capture: vCapture,
117
114
  signal: pSignal?.type === AST_NODE_TYPES.Property ? getSignalValueExpression(pSignal.value, initialScope) : unit
@@ -154,19 +151,19 @@ function create$3(context) {
154
151
  const { type: aType, callee: aCallee, capture: aCapture, listener: aListener, phase: aPhase } = aEntry;
155
152
  const { type: rType, callee: rCallee, capture: rCapture, listener: rListener, phase: rPhase } = rEntry;
156
153
  if (!isInversePhase(aPhase, rPhase)) return false;
157
- return isSameObject(aCallee, rCallee) && ast.isNodeEqual(aListener, rListener) && isNodeEqual(aType, rType, [context.sourceCode.getScope(aType), context.sourceCode.getScope(rType)]) && aCapture === rCapture;
154
+ return isSameObject(aCallee, rCallee) && ast.isNodeEqual(aListener, rListener) && isValueEqual(aType, rType, [context.sourceCode.getScope(aType), context.sourceCode.getScope(rType)]) && aCapture === rCapture;
158
155
  }
159
156
  function checkInlineFunction(node, callKind, options) {
160
157
  const listener = node.arguments.at(1);
161
158
  if (!ast.isFunction(listener)) return;
162
159
  if (options.signal != null) return;
163
160
  context.report({
161
+ data: { eventMethodKind: callKind },
164
162
  messageId: "unexpectedInlineFunction",
165
- node: listener,
166
- data: { eventMethodKind: callKind }
163
+ node: listener
167
164
  });
168
165
  }
169
- return {
166
+ return defineRuleListener({
170
167
  [":function"](node) {
171
168
  const kind = getFunctionKind$1(node);
172
169
  fEntries.push({
@@ -191,10 +188,10 @@ function create$3(context) {
191
188
  aEntries.push({
192
189
  ...opts,
193
190
  type,
194
- node,
195
191
  callee,
196
192
  listener,
197
193
  method: "addEventListener",
194
+ node,
198
195
  phase: fKind
199
196
  });
200
197
  }).with("removeEventListener", (callKind) => {
@@ -206,10 +203,10 @@ function create$3(context) {
206
203
  rEntries.push({
207
204
  ...opts,
208
205
  type,
209
- node,
210
206
  callee,
211
207
  listener,
212
208
  method: "removeEventListener",
209
+ node,
213
210
  phase: fKind
214
211
  });
215
212
  }).with("abort", () => {
@@ -224,9 +221,9 @@ function create$3(context) {
224
221
  case "setup":
225
222
  case "cleanup":
226
223
  context.report({
224
+ data: { effectMethodKind: "useEffect" },
227
225
  messageId: "expectedRemoveEventListenerInCleanup",
228
- node: aEntry.node,
229
- data: { effectMethodKind: "useEffect" }
226
+ node: aEntry.node
230
227
  });
231
228
  continue;
232
229
  case "mount":
@@ -239,11 +236,11 @@ function create$3(context) {
239
236
  }
240
237
  }
241
238
  }
242
- };
239
+ });
243
240
  }
244
241
 
245
242
  //#endregion
246
- //#region src/rules/no-leaked-interval.ts
243
+ //#region src/rules/no-leaked-interval/no-leaked-interval.ts
247
244
  const RULE_NAME$2 = "no-leaked-interval";
248
245
  function getCallKind$2(node) {
249
246
  switch (true) {
@@ -275,7 +272,7 @@ function create$2(context) {
275
272
  function isInverseEntry(a, b) {
276
273
  return isAssignmentTargetEqual(context, a.timerId, b.timerId);
277
274
  }
278
- return {
275
+ return defineRuleListener({
279
276
  [":function"](node) {
280
277
  const kind = getPhaseKindOfFunction(node) ?? "other";
281
278
  fEntries.push({
@@ -302,8 +299,8 @@ function create$2(context) {
302
299
  }
303
300
  sEntries.push({
304
301
  kind: "interval",
305
- node,
306
302
  callee: node.callee,
303
+ node,
307
304
  phase: fEntry.kind,
308
305
  timerId: intervalIdNode
309
306
  });
@@ -317,8 +314,8 @@ function create$2(context) {
317
314
  if (intervalIdNode == null) break;
318
315
  cEntries.push({
319
316
  kind: "interval",
320
- node,
321
317
  callee: node.callee,
318
+ node,
322
319
  phase: fEntry.kind,
323
320
  timerId: intervalIdNode
324
321
  });
@@ -333,34 +330,44 @@ function create$2(context) {
333
330
  case "setup":
334
331
  case "cleanup":
335
332
  context.report({
333
+ data: { kind: "useEffect" },
336
334
  messageId: "expectedClearIntervalInCleanup",
337
- node: sEntry.node,
338
- data: { kind: "useEffect" }
335
+ node: sEntry.node
339
336
  });
340
337
  continue;
341
338
  case "mount":
342
339
  case "unmount":
343
340
  context.report({
341
+ data: { kind: "componentDidMount" },
344
342
  messageId: "expectedClearIntervalInUnmount",
345
- node: sEntry.node,
346
- data: { kind: "componentDidMount" }
343
+ node: sEntry.node
347
344
  });
348
345
  continue;
349
346
  }
350
347
  }
351
348
  }
352
- };
349
+ });
353
350
  }
354
351
 
355
352
  //#endregion
356
- //#region src/rules/no-leaked-resize-observer.ts
353
+ //#region src/rules/no-leaked-resize-observer/no-leaked-resize-observer.ts
357
354
  const RULE_NAME$1 = "no-leaked-resize-observer";
358
355
  function isNewResizeObserver(node) {
359
356
  return node?.type === AST_NODE_TYPES.NewExpression && node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === "ResizeObserver";
360
357
  }
361
358
  function isFromObserver(context, node) {
362
359
  switch (true) {
363
- case node.type === AST_NODE_TYPES.Identifier: return isNewResizeObserver(getVariableDefinitionNode(findVariable(node, context.sourceCode.getScope(node)), 0));
360
+ case node.type === AST_NODE_TYPES.Identifier: {
361
+ const variable = findVariable(node, context.sourceCode.getScope(node));
362
+ function resolve(v) {
363
+ if (v == null) return unit;
364
+ const def = v.defs.at(0);
365
+ if (def == null) return unit;
366
+ if ("init" in def.node && def.node.init != null && !("declarations" in def.node.init)) return def.node.init;
367
+ return unit;
368
+ }
369
+ return isNewResizeObserver(resolve(variable));
370
+ }
364
371
  case node.type === AST_NODE_TYPES.MemberExpression: return isFromObserver(context, node.object);
365
372
  default: return false;
366
373
  }
@@ -397,7 +404,7 @@ function create$1(context) {
397
404
  const oEntries = [];
398
405
  const uEntries = [];
399
406
  const dEntries = [];
400
- return {
407
+ return defineRuleListener({
401
408
  [":function"](node) {
402
409
  const kind = getFunctionKind(node);
403
410
  fEntries.push({
@@ -416,9 +423,9 @@ function create$1(context) {
416
423
  match(getCallKind$1(context, node)).with("disconnect", () => {
417
424
  dEntries.push({
418
425
  kind: "ResizeObserver",
419
- node,
420
426
  callee: node.callee,
421
427
  method: "disconnect",
428
+ node,
422
429
  observer: object,
423
430
  phase: fKind
424
431
  });
@@ -427,10 +434,10 @@ function create$1(context) {
427
434
  if (element == null) return;
428
435
  oEntries.push({
429
436
  kind: "ResizeObserver",
430
- node,
431
437
  callee: node.callee,
432
438
  element,
433
439
  method: "observe",
440
+ node,
434
441
  observer: object,
435
442
  phase: fKind
436
443
  });
@@ -439,10 +446,10 @@ function create$1(context) {
439
446
  if (element == null) return;
440
447
  uEntries.push({
441
448
  kind: "ResizeObserver",
442
- node,
443
449
  callee: node.callee,
444
450
  element,
445
451
  method: "unobserve",
452
+ node,
446
453
  observer: object,
447
454
  phase: fKind
448
455
  });
@@ -491,11 +498,11 @@ function create$1(context) {
491
498
  }
492
499
  }
493
500
  }
494
- };
501
+ });
495
502
  }
496
503
 
497
504
  //#endregion
498
- //#region src/rules/no-leaked-timeout.ts
505
+ //#region src/rules/no-leaked-timeout/no-leaked-timeout.ts
499
506
  const RULE_NAME = "no-leaked-timeout";
500
507
  function getCallKind(node) {
501
508
  switch (true) {
@@ -527,7 +534,7 @@ function create(context) {
527
534
  function isInverseEntry(a, b) {
528
535
  return isAssignmentTargetEqual(context, a.timerId, b.timerId);
529
536
  }
530
- return {
537
+ return defineRuleListener({
531
538
  [":function"](node) {
532
539
  const kind = getPhaseKindOfFunction(node) ?? "other";
533
540
  fEntries.push({
@@ -553,8 +560,8 @@ function create(context) {
553
560
  }
554
561
  sEntries.push({
555
562
  kind: "timeout",
556
- node,
557
563
  callee: node.callee,
564
+ node,
558
565
  phase: fEntry.kind,
559
566
  timerId: timeoutIdNode
560
567
  });
@@ -565,8 +572,8 @@ function create(context) {
565
572
  if (timeoutIdNode == null) break;
566
573
  rEntries.push({
567
574
  kind: "timeout",
568
- node,
569
575
  callee: node.callee,
576
+ node,
570
577
  phase: fEntry.kind,
571
578
  timerId: timeoutIdNode
572
579
  });
@@ -581,30 +588,30 @@ function create(context) {
581
588
  case "setup":
582
589
  case "cleanup":
583
590
  context.report({
591
+ data: { kind: "useEffect" },
584
592
  messageId: "expectedClearTimeoutInCleanup",
585
- node: sEntry.node,
586
- data: { kind: "useEffect" }
593
+ node: sEntry.node
587
594
  });
588
595
  continue;
589
596
  case "mount":
590
597
  case "unmount":
591
598
  context.report({
599
+ data: { kind: "componentDidMount" },
592
600
  messageId: "expectedClearTimeoutInUnmount",
593
- node: sEntry.node,
594
- data: { kind: "componentDidMount" }
601
+ node: sEntry.node
595
602
  });
596
603
  continue;
597
604
  }
598
605
  }
599
606
  }
600
- };
607
+ });
601
608
  }
602
609
 
603
610
  //#endregion
604
611
  //#region src/plugin.ts
605
612
  const plugin = {
606
613
  meta: {
607
- name,
614
+ name: name$1,
608
615
  version
609
616
  },
610
617
  rules: {
@@ -615,13 +622,30 @@ const plugin = {
615
622
  }
616
623
  };
617
624
 
625
+ //#endregion
626
+ //#region src/configs/recommended.ts
627
+ var recommended_exports = /* @__PURE__ */ __exportAll({
628
+ name: () => name,
629
+ plugins: () => plugins,
630
+ rules: () => rules,
631
+ settings: () => settings
632
+ });
633
+ const name = "react-web-api/recommended";
634
+ const rules = {
635
+ "react-web-api/no-leaked-event-listener": "warn",
636
+ "react-web-api/no-leaked-interval": "warn",
637
+ "react-web-api/no-leaked-resize-observer": "warn",
638
+ "react-web-api/no-leaked-timeout": "warn"
639
+ };
640
+ const plugins = { "react-web-api": plugin };
641
+ const settings = { "react-x": DEFAULT_ESLINT_REACT_SETTINGS };
642
+
618
643
  //#endregion
619
644
  //#region src/index.ts
620
- const { toFlatConfig } = getConfigAdapters("react-web-api", plugin);
621
- var src_default = {
645
+ const finalPlugin = {
622
646
  ...plugin,
623
- configs: { ["recommended"]: toFlatConfig(recommended_exports) }
647
+ configs: { ["recommended"]: recommended_exports }
624
648
  };
625
649
 
626
650
  //#endregion
627
- export { src_default as default };
651
+ export { finalPlugin as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-web-api",
3
- "version": "3.0.0-next.6",
3
+ "version": "3.0.0-next.61",
4
4
  "description": "ESLint React's ESLint plugin for interacting with Web APIs",
5
5
  "keywords": [
6
6
  "react",
@@ -43,16 +43,17 @@
43
43
  "@typescript-eslint/utils": "canary",
44
44
  "birecord": "^0.1.1",
45
45
  "ts-pattern": "^5.9.0",
46
- "@eslint-react/eff": "3.0.0-next.6",
47
- "@eslint-react/ast": "3.0.0-next.6",
48
- "@eslint-react/shared": "3.0.0-next.6",
49
- "@eslint-react/core": "3.0.0-next.6",
50
- "@eslint-react/var": "3.0.0-next.6"
46
+ "@eslint-react/ast": "3.0.0-next.61",
47
+ "@eslint-react/core": "3.0.0-next.61",
48
+ "@eslint-react/shared": "3.0.0-next.61",
49
+ "@eslint-react/eff": "3.0.0-next.61",
50
+ "@eslint-react/var": "3.0.0-next.61"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/react": "^19.2.14",
54
54
  "@types/react-dom": "^19.2.3",
55
- "tsdown": "^0.20.3",
55
+ "eslint": "^10.0.2",
56
+ "tsdown": "^0.21.0-beta.2",
56
57
  "@local/configs": "0.0.0"
57
58
  },
58
59
  "peerDependencies": {
@@ -68,6 +69,6 @@
68
69
  "scripts": {
69
70
  "build": "tsdown",
70
71
  "lint:publish": "publint",
71
- "lint:ts": "tsc --noEmit"
72
+ "lint:ts": "tsl"
72
73
  }
73
74
  }