eslint-plugin-react-web-api 3.0.0-next.7 → 3.0.0-next.70

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,11 +1,11 @@
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
- import { dual, or, unit } from "@eslint-react/eff";
5
- import { findEnclosingAssignmentTarget, findProperty, findVariable, getVariableDefinitionNode, isAssignmentTargetEqual, isNodeEqual } from "@eslint-react/var";
4
+ import { findEnclosingAssignmentTarget, isAssignmentTargetEqual, isValueEqual, resolve } from "@eslint-react/var";
6
5
  import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
7
6
  import { getStaticValue } from "@typescript-eslint/utils/ast-utils";
8
7
  import { P, isMatching, match } from "ts-pattern";
8
+ import { dual, or } from "@eslint-react/eff";
9
9
  import birecord from "birecord";
10
10
 
11
11
  //#region \0rolldown/runtime.js
@@ -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.7";
29
+ var name$1 = "eslint-plugin-react-web-api";
30
+ var version = "3.0.0-next.70";
47
31
 
48
32
  //#endregion
49
33
  //#region src/types/component-phase.ts
@@ -64,11 +48,11 @@ 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,
71
- signal: unit
55
+ signal: null
72
56
  };
73
57
  function getCallKind$3(node) {
74
58
  switch (true) {
@@ -80,23 +64,21 @@ function getCallKind$3(node) {
80
64
  function getFunctionKind$1(node) {
81
65
  return getPhaseKindOfFunction(node) ?? "other";
82
66
  }
83
- function getSignalValueExpression(node, initialScope) {
84
- if (node == null) return unit;
67
+ function getSignalValueExpression(context, node) {
68
+ if (node == null) return null;
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: return getSignalValueExpression(context, resolve(context, node));
87
71
  case AST_NODE_TYPES.MemberExpression: return node;
88
- default: return unit;
72
+ default: return null;
89
73
  }
90
74
  }
91
- function getOptions(node, initialScope) {
92
- function findProp(properties, propName) {
93
- return findProperty(propName, properties, initialScope);
94
- }
75
+ function getOptions(context, node) {
76
+ const initialScope = context.sourceCode.getScope(node);
95
77
  function getOpts(node) {
96
78
  switch (node.type) {
97
79
  case AST_NODE_TYPES.Identifier: {
98
- const variableNode = getVariableDefinitionNode(findVariable(node, initialScope), 0);
99
- if (variableNode?.type === AST_NODE_TYPES.ObjectExpression) return getOpts(variableNode);
80
+ const initNode = resolve(context, node);
81
+ if (initNode?.type === AST_NODE_TYPES.ObjectExpression) return getOpts(initNode);
100
82
  return defaultOptions;
101
83
  }
102
84
  case AST_NODE_TYPES.Literal: return {
@@ -104,17 +86,17 @@ function getOptions(node, initialScope) {
104
86
  capture: Boolean(node.value)
105
87
  };
106
88
  case AST_NODE_TYPES.ObjectExpression: {
107
- const vCapture = match(findProp(node.properties, "capture")).with(P.nullish, () => false).with({ type: AST_NODE_TYPES.Property }, (prop) => {
89
+ const vCapture = match(ast.findProperty(node.properties, "capture")).with(P.nullish, () => false).with({ type: AST_NODE_TYPES.Property }, (prop) => {
108
90
  const value = prop.value;
109
91
  switch (value.type) {
110
92
  case AST_NODE_TYPES.Literal: return Boolean(value.value);
111
93
  default: return Boolean(getStaticValue(value, initialScope)?.value);
112
94
  }
113
95
  }).otherwise(() => false);
114
- const pSignal = findProp(node.properties, "signal");
96
+ const pSignal = ast.findProperty(node.properties, "signal");
115
97
  return {
116
98
  capture: vCapture,
117
- signal: pSignal?.type === AST_NODE_TYPES.Property ? getSignalValueExpression(pSignal.value, initialScope) : unit
99
+ signal: pSignal?.type === AST_NODE_TYPES.Property ? getSignalValueExpression(context, pSignal.value) : null
118
100
  };
119
101
  }
120
102
  default: return defaultOptions;
@@ -154,19 +136,19 @@ function create$3(context) {
154
136
  const { type: aType, callee: aCallee, capture: aCapture, listener: aListener, phase: aPhase } = aEntry;
155
137
  const { type: rType, callee: rCallee, capture: rCapture, listener: rListener, phase: rPhase } = rEntry;
156
138
  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;
139
+ return isSameObject(aCallee, rCallee) && ast.isNodeEqual(aListener, rListener) && isValueEqual(context, aType, rType) && aCapture === rCapture;
158
140
  }
159
141
  function checkInlineFunction(node, callKind, options) {
160
142
  const listener = node.arguments.at(1);
161
143
  if (!ast.isFunction(listener)) return;
162
144
  if (options.signal != null) return;
163
145
  context.report({
146
+ data: { eventMethodKind: callKind },
164
147
  messageId: "unexpectedInlineFunction",
165
- node: listener,
166
- data: { eventMethodKind: callKind }
148
+ node: listener
167
149
  });
168
150
  }
169
- return {
151
+ return defineRuleListener({
170
152
  [":function"](node) {
171
153
  const kind = getFunctionKind$1(node);
172
154
  fEntries.push({
@@ -185,31 +167,31 @@ function create$3(context) {
185
167
  if (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.object.type === AST_NODE_TYPES.Identifier && core.isInitializedFromReactNative(node.callee.object.name, context.sourceCode.getScope(node))) return;
186
168
  const [type, listener, options] = node.arguments;
187
169
  if (type == null || listener == null) return;
188
- const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
170
+ const opts = options == null ? defaultOptions : getOptions(context, options);
189
171
  const { callee } = node;
190
172
  checkInlineFunction(node, callKind, opts);
191
173
  aEntries.push({
192
174
  ...opts,
193
175
  type,
194
- node,
195
176
  callee,
196
177
  listener,
197
178
  method: "addEventListener",
179
+ node,
198
180
  phase: fKind
199
181
  });
200
182
  }).with("removeEventListener", (callKind) => {
201
183
  const [type, listener, options] = node.arguments;
202
184
  if (type == null || listener == null) return;
203
- const opts = options == null ? defaultOptions : getOptions(options, context.sourceCode.getScope(options));
185
+ const opts = options == null ? defaultOptions : getOptions(context, options);
204
186
  const { callee } = node;
205
187
  checkInlineFunction(node, callKind, opts);
206
188
  rEntries.push({
207
189
  ...opts,
208
190
  type,
209
- node,
210
191
  callee,
211
192
  listener,
212
193
  method: "removeEventListener",
194
+ node,
213
195
  phase: fKind
214
196
  });
215
197
  }).with("abort", () => {
@@ -224,9 +206,9 @@ function create$3(context) {
224
206
  case "setup":
225
207
  case "cleanup":
226
208
  context.report({
209
+ data: { effectMethodKind: "useEffect" },
227
210
  messageId: "expectedRemoveEventListenerInCleanup",
228
- node: aEntry.node,
229
- data: { effectMethodKind: "useEffect" }
211
+ node: aEntry.node
230
212
  });
231
213
  continue;
232
214
  case "mount":
@@ -239,11 +221,11 @@ function create$3(context) {
239
221
  }
240
222
  }
241
223
  }
242
- };
224
+ });
243
225
  }
244
226
 
245
227
  //#endregion
246
- //#region src/rules/no-leaked-interval.ts
228
+ //#region src/rules/no-leaked-interval/no-leaked-interval.ts
247
229
  const RULE_NAME$2 = "no-leaked-interval";
248
230
  function getCallKind$2(node) {
249
231
  switch (true) {
@@ -275,7 +257,7 @@ function create$2(context) {
275
257
  function isInverseEntry(a, b) {
276
258
  return isAssignmentTargetEqual(context, a.timerId, b.timerId);
277
259
  }
278
- return {
260
+ return defineRuleListener({
279
261
  [":function"](node) {
280
262
  const kind = getPhaseKindOfFunction(node) ?? "other";
281
263
  fEntries.push({
@@ -302,8 +284,8 @@ function create$2(context) {
302
284
  }
303
285
  sEntries.push({
304
286
  kind: "interval",
305
- node,
306
287
  callee: node.callee,
288
+ node,
307
289
  phase: fEntry.kind,
308
290
  timerId: intervalIdNode
309
291
  });
@@ -317,8 +299,8 @@ function create$2(context) {
317
299
  if (intervalIdNode == null) break;
318
300
  cEntries.push({
319
301
  kind: "interval",
320
- node,
321
302
  callee: node.callee,
303
+ node,
322
304
  phase: fEntry.kind,
323
305
  timerId: intervalIdNode
324
306
  });
@@ -333,34 +315,34 @@ function create$2(context) {
333
315
  case "setup":
334
316
  case "cleanup":
335
317
  context.report({
318
+ data: { kind: "useEffect" },
336
319
  messageId: "expectedClearIntervalInCleanup",
337
- node: sEntry.node,
338
- data: { kind: "useEffect" }
320
+ node: sEntry.node
339
321
  });
340
322
  continue;
341
323
  case "mount":
342
324
  case "unmount":
343
325
  context.report({
326
+ data: { kind: "componentDidMount" },
344
327
  messageId: "expectedClearIntervalInUnmount",
345
- node: sEntry.node,
346
- data: { kind: "componentDidMount" }
328
+ node: sEntry.node
347
329
  });
348
330
  continue;
349
331
  }
350
332
  }
351
333
  }
352
- };
334
+ });
353
335
  }
354
336
 
355
337
  //#endregion
356
- //#region src/rules/no-leaked-resize-observer.ts
338
+ //#region src/rules/no-leaked-resize-observer/no-leaked-resize-observer.ts
357
339
  const RULE_NAME$1 = "no-leaked-resize-observer";
358
340
  function isNewResizeObserver(node) {
359
341
  return node?.type === AST_NODE_TYPES.NewExpression && node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === "ResizeObserver";
360
342
  }
361
343
  function isFromObserver(context, node) {
362
344
  switch (true) {
363
- case node.type === AST_NODE_TYPES.Identifier: return isNewResizeObserver(getVariableDefinitionNode(findVariable(node, context.sourceCode.getScope(node)), 0));
345
+ case node.type === AST_NODE_TYPES.Identifier: return isNewResizeObserver(resolve(context, node));
364
346
  case node.type === AST_NODE_TYPES.MemberExpression: return isFromObserver(context, node.object);
365
347
  default: return false;
366
348
  }
@@ -397,7 +379,7 @@ function create$1(context) {
397
379
  const oEntries = [];
398
380
  const uEntries = [];
399
381
  const dEntries = [];
400
- return {
382
+ return defineRuleListener({
401
383
  [":function"](node) {
402
384
  const kind = getFunctionKind(node);
403
385
  fEntries.push({
@@ -416,9 +398,9 @@ function create$1(context) {
416
398
  match(getCallKind$1(context, node)).with("disconnect", () => {
417
399
  dEntries.push({
418
400
  kind: "ResizeObserver",
419
- node,
420
401
  callee: node.callee,
421
402
  method: "disconnect",
403
+ node,
422
404
  observer: object,
423
405
  phase: fKind
424
406
  });
@@ -427,10 +409,10 @@ function create$1(context) {
427
409
  if (element == null) return;
428
410
  oEntries.push({
429
411
  kind: "ResizeObserver",
430
- node,
431
412
  callee: node.callee,
432
413
  element,
433
414
  method: "observe",
415
+ node,
434
416
  observer: object,
435
417
  phase: fKind
436
418
  });
@@ -439,10 +421,10 @@ function create$1(context) {
439
421
  if (element == null) return;
440
422
  uEntries.push({
441
423
  kind: "ResizeObserver",
442
- node,
443
424
  callee: node.callee,
444
425
  element,
445
426
  method: "unobserve",
427
+ node,
446
428
  observer: object,
447
429
  phase: fKind
448
430
  });
@@ -491,11 +473,11 @@ function create$1(context) {
491
473
  }
492
474
  }
493
475
  }
494
- };
476
+ });
495
477
  }
496
478
 
497
479
  //#endregion
498
- //#region src/rules/no-leaked-timeout.ts
480
+ //#region src/rules/no-leaked-timeout/no-leaked-timeout.ts
499
481
  const RULE_NAME = "no-leaked-timeout";
500
482
  function getCallKind(node) {
501
483
  switch (true) {
@@ -527,7 +509,7 @@ function create(context) {
527
509
  function isInverseEntry(a, b) {
528
510
  return isAssignmentTargetEqual(context, a.timerId, b.timerId);
529
511
  }
530
- return {
512
+ return defineRuleListener({
531
513
  [":function"](node) {
532
514
  const kind = getPhaseKindOfFunction(node) ?? "other";
533
515
  fEntries.push({
@@ -553,8 +535,8 @@ function create(context) {
553
535
  }
554
536
  sEntries.push({
555
537
  kind: "timeout",
556
- node,
557
538
  callee: node.callee,
539
+ node,
558
540
  phase: fEntry.kind,
559
541
  timerId: timeoutIdNode
560
542
  });
@@ -565,8 +547,8 @@ function create(context) {
565
547
  if (timeoutIdNode == null) break;
566
548
  rEntries.push({
567
549
  kind: "timeout",
568
- node,
569
550
  callee: node.callee,
551
+ node,
570
552
  phase: fEntry.kind,
571
553
  timerId: timeoutIdNode
572
554
  });
@@ -581,30 +563,30 @@ function create(context) {
581
563
  case "setup":
582
564
  case "cleanup":
583
565
  context.report({
566
+ data: { kind: "useEffect" },
584
567
  messageId: "expectedClearTimeoutInCleanup",
585
- node: sEntry.node,
586
- data: { kind: "useEffect" }
568
+ node: sEntry.node
587
569
  });
588
570
  continue;
589
571
  case "mount":
590
572
  case "unmount":
591
573
  context.report({
574
+ data: { kind: "componentDidMount" },
592
575
  messageId: "expectedClearTimeoutInUnmount",
593
- node: sEntry.node,
594
- data: { kind: "componentDidMount" }
576
+ node: sEntry.node
595
577
  });
596
578
  continue;
597
579
  }
598
580
  }
599
581
  }
600
- };
582
+ });
601
583
  }
602
584
 
603
585
  //#endregion
604
586
  //#region src/plugin.ts
605
587
  const plugin = {
606
588
  meta: {
607
- name,
589
+ name: name$1,
608
590
  version
609
591
  },
610
592
  rules: {
@@ -615,13 +597,30 @@ const plugin = {
615
597
  }
616
598
  };
617
599
 
600
+ //#endregion
601
+ //#region src/configs/recommended.ts
602
+ var recommended_exports = /* @__PURE__ */ __exportAll({
603
+ name: () => name,
604
+ plugins: () => plugins,
605
+ rules: () => rules,
606
+ settings: () => settings
607
+ });
608
+ const name = "react-web-api/recommended";
609
+ const rules = {
610
+ "react-web-api/no-leaked-event-listener": "warn",
611
+ "react-web-api/no-leaked-interval": "warn",
612
+ "react-web-api/no-leaked-resize-observer": "warn",
613
+ "react-web-api/no-leaked-timeout": "warn"
614
+ };
615
+ const plugins = { "react-web-api": plugin };
616
+ const settings = { "react-x": DEFAULT_ESLINT_REACT_SETTINGS };
617
+
618
618
  //#endregion
619
619
  //#region src/index.ts
620
- const { toFlatConfig } = getConfigAdapters("react-web-api", plugin);
621
- var src_default = {
620
+ const finalPlugin = {
622
621
  ...plugin,
623
- configs: { ["recommended"]: toFlatConfig(recommended_exports) }
622
+ configs: { ["recommended"]: recommended_exports }
624
623
  };
625
624
 
626
625
  //#endregion
627
- export { src_default as default };
626
+ 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.7",
3
+ "version": "3.0.0-next.70",
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/ast": "3.0.0-next.7",
47
- "@eslint-react/core": "3.0.0-next.7",
48
- "@eslint-react/shared": "3.0.0-next.7",
49
- "@eslint-react/eff": "3.0.0-next.7",
50
- "@eslint-react/var": "3.0.0-next.7"
46
+ "@eslint-react/ast": "3.0.0-next.70",
47
+ "@eslint-react/core": "3.0.0-next.70",
48
+ "@eslint-react/eff": "3.0.0-next.70",
49
+ "@eslint-react/shared": "3.0.0-next.70",
50
+ "@eslint-react/var": "3.0.0-next.70"
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
  }