eslint-plugin-react-web-api 2.7.4-beta.0 → 2.7.4-beta.10

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/README.md +12 -0
  2. package/dist/index.js +22 -22
  3. package/package.json +8 -8
package/README.md CHANGED
@@ -36,6 +36,18 @@ export default defineConfig(
36
36
  );
37
37
  ```
38
38
 
39
+ ## Web API Rules
40
+
41
+ > [!NOTE]
42
+ > Web API rules prevent resource leaks by detecting uncleaned Web API subscriptions in components and hooks.
43
+
44
+ **Implemented Rules:**
45
+
46
+ - [`no-leaked-event-listener`](./web-api-no-leaked-event-listener) - Prevents leaked `addEventListener` calls
47
+ - [`no-leaked-interval`](./web-api-no-leaked-interval) - Prevents leaked `setInterval` calls
48
+ - [`no-leaked-resize-observer`](./web-api-no-leaked-resize-observer) - Prevents leaked `ResizeObserver` instances
49
+ - [`no-leaked-timeout`](./web-api-no-leaked-timeout) - Prevents leaked `setTimeout` calls
50
+
39
51
  ## Rules
40
52
 
41
53
  <https://eslint-react.xyz/docs/rules/overview#web-api-rules>
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { DEFAULT_ESLINT_REACT_SETTINGS, WEBSITE_URL, getConfigAdapters } from "@eslint-react/shared";
2
2
  import * as AST from "@eslint-react/ast";
3
- import { ComponentPhaseRelevance, findEnclosingAssignmentTarget, getPhaseKindOfFunction, isInitializedFromReactNative, isInstanceIdEqual, isInversePhase } from "@eslint-react/core";
3
+ import { ComponentPhaseRelevance, getPhaseKindOfFunction, isInitializedFromReactNative, isInversePhase } from "@eslint-react/core";
4
4
  import { or, unit } from "@eslint-react/eff";
5
- import { findAssignmentTarget, findProperty, findVariable, getVariableDefinitionNode, isNodeValueEqual } from "@eslint-react/var";
5
+ import { findEnclosingAssignmentTarget, findProperty, findVariable, getVariableDefinitionNode, isAssignmentTargetEqual, isNodeValueEqual } 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";
@@ -11,9 +11,9 @@ import { P, isMatching, match } from "ts-pattern";
11
11
  var __defProp = Object.defineProperty;
12
12
  var __exportAll = (all, symbols) => {
13
13
  let target = {};
14
- for (var name$2 in all) {
15
- __defProp(target, name$2, {
16
- get: all[name$2],
14
+ for (var name in all) {
15
+ __defProp(target, name, {
16
+ get: all[name],
17
17
  enumerable: true
18
18
  });
19
19
  }
@@ -42,7 +42,7 @@ const settings = { "react-x": DEFAULT_ESLINT_REACT_SETTINGS };
42
42
  //#endregion
43
43
  //#region package.json
44
44
  var name = "eslint-plugin-react-web-api";
45
- var version = "2.7.4-beta.0";
45
+ var version = "2.7.4-beta.10";
46
46
 
47
47
  //#endregion
48
48
  //#region src/utils/create-rule.ts
@@ -94,20 +94,20 @@ function getOptions(node, initialScope) {
94
94
  }
95
95
  return filter(v) ? v : unit;
96
96
  }
97
- function getOpts(node$1) {
98
- switch (node$1.type) {
97
+ function getOpts(node) {
98
+ switch (node.type) {
99
99
  case AST_NODE_TYPES.Identifier: {
100
- const variableNode = getVariableDefinitionNode(findVariable(node$1, initialScope), 0);
100
+ const variableNode = getVariableDefinitionNode(findVariable(node, initialScope), 0);
101
101
  if (variableNode?.type === AST_NODE_TYPES.ObjectExpression) return getOpts(variableNode);
102
102
  return defaultOptions;
103
103
  }
104
104
  case AST_NODE_TYPES.Literal: return {
105
105
  ...defaultOptions,
106
- capture: Boolean(node$1.value)
106
+ capture: Boolean(node.value)
107
107
  };
108
108
  case AST_NODE_TYPES.ObjectExpression: {
109
- const vCapture = !!getPropValue(findProp(node$1.properties, "capture"));
110
- const pSignal = findProp(node$1.properties, "signal");
109
+ const vCapture = !!getPropValue(findProp(node.properties, "capture"));
110
+ const pSignal = findProp(node.properties, "signal");
111
111
  return {
112
112
  capture: vCapture,
113
113
  signal: pSignal?.type === AST_NODE_TYPES.Property ? getSignalValueExpression(pSignal.value, initialScope) : unit
@@ -269,7 +269,7 @@ function create$2(context) {
269
269
  const sEntries = [];
270
270
  const cEntries = [];
271
271
  function isInverseEntry(a, b) {
272
- return isInstanceIdEqual(context, a.timerId, b.timerId);
272
+ return isAssignmentTargetEqual(context, a.timerId, b.timerId);
273
273
  }
274
274
  return {
275
275
  [":function"](node) {
@@ -288,7 +288,7 @@ function create$2(context) {
288
288
  const fEntry = fEntries.findLast((x) => x.kind !== "other");
289
289
  if (fEntry == null) break;
290
290
  if (!ComponentPhaseRelevance.has(fEntry.kind)) break;
291
- const intervalIdNode = findAssignmentTarget(node);
291
+ const intervalIdNode = findEnclosingAssignmentTarget(node);
292
292
  if (intervalIdNode == null) {
293
293
  context.report({
294
294
  messageId: "expectedIntervalId",
@@ -466,11 +466,11 @@ function create$1(context) {
466
466
  },
467
467
  ["Program:exit"]() {
468
468
  for (const { id, node, phaseNode } of observers) {
469
- if (dEntries.some((e) => isInstanceIdEqual(context, e.observer, id))) continue;
470
- const oentries = oEntries.filter((e) => isInstanceIdEqual(context, e.observer, id));
471
- const uentries = uEntries.filter((e) => isInstanceIdEqual(context, e.observer, id));
472
- const isDynamic = (node$1) => node$1?.type === AST_NODE_TYPES.CallExpression || AST.isConditional(node$1);
473
- const isPhaseNode = (node$1) => node$1 === phaseNode;
469
+ if (dEntries.some((e) => isAssignmentTargetEqual(context, e.observer, id))) continue;
470
+ const oentries = oEntries.filter((e) => isAssignmentTargetEqual(context, e.observer, id));
471
+ const uentries = uEntries.filter((e) => isAssignmentTargetEqual(context, e.observer, id));
472
+ const isDynamic = (node) => node?.type === AST_NODE_TYPES.CallExpression || AST.isConditional(node);
473
+ const isPhaseNode = (node) => node === phaseNode;
474
474
  if (oentries.some((e) => !isPhaseNode(AST.findParentNode(e.node, or(isDynamic, isPhaseNode))))) {
475
475
  context.report({
476
476
  messageId: "expectedDisconnectInControlFlow",
@@ -479,7 +479,7 @@ function create$1(context) {
479
479
  continue;
480
480
  }
481
481
  for (const oEntry of oentries) {
482
- if (uentries.some((uEntry) => isInstanceIdEqual(context, uEntry.element, oEntry.element))) continue;
482
+ if (uentries.some((uEntry) => isAssignmentTargetEqual(context, uEntry.element, oEntry.element))) continue;
483
483
  context.report({
484
484
  messageId: "expectedDisconnectOrUnobserveInCleanup",
485
485
  node: oEntry.node
@@ -521,7 +521,7 @@ function create(context) {
521
521
  const sEntries = [];
522
522
  const rEntries = [];
523
523
  function isInverseEntry(a, b) {
524
- return isInstanceIdEqual(context, a.timerId, b.timerId);
524
+ return isAssignmentTargetEqual(context, a.timerId, b.timerId);
525
525
  }
526
526
  return {
527
527
  [":function"](node) {
@@ -539,7 +539,7 @@ function create(context) {
539
539
  if (!ComponentPhaseRelevance.has(fEntry?.kind)) return;
540
540
  switch (getCallKind(node)) {
541
541
  case "setTimeout": {
542
- const timeoutIdNode = findAssignmentTarget(node);
542
+ const timeoutIdNode = findEnclosingAssignmentTarget(node);
543
543
  if (timeoutIdNode == null) {
544
544
  context.report({
545
545
  messageId: "expectedTimeoutId",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-web-api",
3
- "version": "2.7.4-beta.0",
3
+ "version": "2.7.4-beta.10",
4
4
  "description": "ESLint React's ESLint plugin for interacting with Web APIs",
5
5
  "keywords": [
6
6
  "react",
@@ -20,7 +20,7 @@
20
20
  "directory": "packages/plugins/eslint-plugin-react-web-api"
21
21
  },
22
22
  "license": "MIT",
23
- "author": "Rel1cx<rel1cx@proton.me>",
23
+ "author": "Rel1cx",
24
24
  "sideEffects": false,
25
25
  "type": "module",
26
26
  "exports": {
@@ -43,16 +43,16 @@
43
43
  "@typescript-eslint/utils": "^8.53.1",
44
44
  "string-ts": "^2.3.1",
45
45
  "ts-pattern": "^5.9.0",
46
- "@eslint-react/ast": "2.7.4-beta.0",
47
- "@eslint-react/core": "2.7.4-beta.0",
48
- "@eslint-react/eff": "2.7.4-beta.0",
49
- "@eslint-react/var": "2.7.4-beta.0",
50
- "@eslint-react/shared": "2.7.4-beta.0"
46
+ "@eslint-react/ast": "2.7.4-beta.10",
47
+ "@eslint-react/core": "2.7.4-beta.10",
48
+ "@eslint-react/eff": "2.7.4-beta.10",
49
+ "@eslint-react/shared": "2.7.4-beta.10",
50
+ "@eslint-react/var": "2.7.4-beta.10"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/react": "^19.2.9",
54
54
  "@types/react-dom": "^19.2.3",
55
- "tsdown": "^0.20.0-beta.4",
55
+ "tsdown": "^0.20.1",
56
56
  "@local/configs": "0.0.0"
57
57
  },
58
58
  "peerDependencies": {