@zayne-labs/eslint-config 0.11.5 → 0.11.6

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.
@@ -0,0 +1,671 @@
1
+ import globals from "globals";
2
+
3
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/util/ast.js
4
+ /**
5
+ * @import {Scope,Rule} from 'eslint'
6
+ */
7
+ /**
8
+ * Get all references that ultimately flow into `ref`.
9
+ *
10
+ * @param {Rule.RuleContext} context
11
+ * @param {Scope.Reference} ref
12
+ * @param {"leaf" | "all"} [mode="all"]
13
+ * @param {Set<Scope.Reference>} visited
14
+ *
15
+ * @returns {Scope.Reference[]}
16
+ */
17
+ const getUpstreamRefs = (context, ref, mode = "all", visited = /* @__PURE__ */ new Set()) => {
18
+ visited.add(ref);
19
+ const upstreamRefs = ref.resolved?.defs.filter((def) => def.type !== "ImportBinding").filter((def) => def.type !== "Parameter").map((def) => def.node.init ?? def.node.body).filter(Boolean).flatMap((node) => getDownstreamRefs(context, node)).filter((ref$1) => !visited.has(ref$1)).flatMap((ref$1) => getUpstreamRefs(context, ref$1, mode, visited));
20
+ const isLeafRef = upstreamRefs === void 0 || upstreamRefs.length === 0;
21
+ return mode === "leaf" ? isLeafRef ? [ref] : upstreamRefs : [ref].concat(upstreamRefs ?? []);
22
+ };
23
+ /**
24
+ * Descend the AST from `node`, calling `visit` on each node.
25
+ *
26
+ * @param {Rule.RuleContext} context
27
+ * @param {Rule.Node} node
28
+ * @param {(node: Rule.Node) => void} visit
29
+ * @param {Set<Rule.Node>} visited
30
+ */
31
+ const descend = (context, node, visit, visited = /* @__PURE__ */ new Set()) => {
32
+ if (visited.has(node)) return;
33
+ visit(node);
34
+ visited.add(node);
35
+ (context.sourceCode.visitorKeys[node.type] || []).map((key) => node[key]).filter(Boolean).flatMap((child) => Array.isArray(child) ? child : [child]).filter(Boolean).filter((child) => typeof child.type === "string").forEach((child) => descend(context, child, visit, visited));
36
+ };
37
+ /**
38
+ * @param {Rule.RuleContext} context
39
+ * @param {Rule.Node} topNode
40
+ * @param {string} type
41
+ */
42
+ const findDownstreamNodes = (context, topNode, type) => {
43
+ const nodes = [];
44
+ descend(context, topNode, (node) => {
45
+ if (node.type === type) nodes.push(node);
46
+ });
47
+ return nodes;
48
+ };
49
+ /**
50
+ * @param {Rule.RuleContext} context
51
+ * @param {Rule.Node} node
52
+ */
53
+ const getDownstreamRefs = (context, node) => findDownstreamNodes(context, node, "Identifier").map((identifier) => getRef(context, identifier)).filter(Boolean);
54
+ /**
55
+ * @param {Scope.Reference} ref
56
+ * @param {Rule.Node} current
57
+ * @returns {Rule.Node | undefined}
58
+ */
59
+ const getCallExpr = (ref, current = ref.identifier.parent) => {
60
+ if (current.type === "CallExpression") {
61
+ let node = ref.identifier;
62
+ while (node.parent.type === "MemberExpression") node = node.parent;
63
+ if (current.callee === node) return current;
64
+ }
65
+ if (current.type === "MemberExpression") return getCallExpr(ref, current.parent);
66
+ };
67
+ /**
68
+ * When using this, we assume that args passed to the derived function are always eventually passed to underlying functions.
69
+ * Which they may not be. Would be better to trace the actual flow of values, but that's complex. We'll start with this for now.
70
+ *
71
+ * @param {Rule.RuleContext} context
72
+ * @param {Scope.Reference} ref
73
+ * @param {"leaf" | "all"} [mode="all"] Whether to return all refs, or only leaf refs. Note that "all" includes `ref` itself.
74
+ * @returns {Rule.Node[]}
75
+ */
76
+ const getArgsUpstreamRefs = (context, ref, mode) => getUpstreamRefs(context, ref, mode).map((ref$1) => getCallExpr(ref$1)).filter(Boolean).flatMap((callExpr) => callExpr.arguments).flatMap((arg) => getDownstreamRefs(context, arg)).flatMap((ref$1) => getUpstreamRefs(context, ref$1));
77
+ /**
78
+ * Walks up the AST until `within` (returns `true`) or finding any of (returns `false`):
79
+ * - An `async` function
80
+ * - A function declaration, which may be called at an arbitrary later time.
81
+ * - While we return false for *this* call, we may still return true for a call to a function containing this call. Combined with `getUpstreamRefs()`, it will still flag calls to the containing function.
82
+ * - A function passed as a callback to another function or `new` - event handler, `setTimeout`, `Promise.then()` `new ResizeObserver()`, etc.
83
+ *
84
+ * Inspired by https://eslint-react.xyz/docs/rules/hooks-extra-no-direct-set-state-in-use-effect
85
+ *
86
+ * @param {Rule.Node} node
87
+ * @param {Rule.Node} within
88
+ * @returns {boolean}
89
+ */
90
+ const isSynchronous = (node, within) => {
91
+ if (node == within) return true;
92
+ else if (node.async || node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") return false;
93
+ else return isSynchronous(node.parent, within);
94
+ };
95
+ /**
96
+ * @param {Rule.RuleContext} context
97
+ * @param {Rule.Node} identifier
98
+ *
99
+ * @returns {Scope.Reference | undefined}
100
+ */
101
+ const getRef = (context, identifier) => context.sourceCode.getScope(identifier)?.references.find((ref) => ref.identifier == identifier);
102
+ /**
103
+ * @param {Rule.RuleContext} context
104
+ * @param {Scope.Reference} ref
105
+ * @param {(ref: Scope.Reference) => boolean} predicate
106
+ * @returns {boolean} Whether this reference eventually calls a function matching the given predicate.
107
+ */
108
+ const isEventualCallTo = (context, ref, predicate) => getCallExpr(ref) !== void 0 && getUpstreamRefs(context, ref).some(predicate);
109
+
110
+ //#endregion
111
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/util/react.js
112
+ /**
113
+ * @import {Scope,Rule} from 'eslint'
114
+ */
115
+ /**
116
+ * @param {Rule.Node} node
117
+ * @returns {boolean}
118
+ */
119
+ const isReactFunctionalComponent = (node) => (node.type === "FunctionDeclaration" || node.type === "VariableDeclarator" && (node.init.type === "ArrowFunctionExpression" || node.init.type === "CallExpression")) && node.id.type === "Identifier" && node.id.name[0].toUpperCase() === node.id.name[0];
120
+ /**
121
+ * Excludes known pure HOCs like `memo` and `forwardRef`.
122
+ * Basically this is meant to detect custom HOCs that may have side effects, particularly when using their props.
123
+ *
124
+ * TODO: Will not detect when the component is defined normally and then exported wrapped in an HOC.
125
+ * e.g. `const MyComponent = (props) => {...}; export default memo(MyComponent);`
126
+ *
127
+ * @param {Rule.Node} node
128
+ * @returns {boolean}
129
+ */
130
+ const isReactFunctionalHOC = (node) => node.type === "VariableDeclarator" && node.init && node.init.type === "CallExpression" && node.init.callee.type === "Identifier" && !["memo", "forwardRef"].includes(node.init.callee.name) && node.init.arguments.length > 0 && (node.init.arguments[0].type === "ArrowFunctionExpression" || node.init.arguments[0].type === "FunctionExpression") && node.id.type === "Identifier" && node.id.name[0].toUpperCase() === node.id.name[0];
131
+ /**
132
+ * @param {Rule.Node} node
133
+ * @returns {boolean}
134
+ */
135
+ const isCustomHook = (node) => (node.type === "FunctionDeclaration" || node.type === "VariableDeclarator" && node.init && (node.init.type === "ArrowFunctionExpression" || node.init.type === "FunctionExpression")) && node.id.type === "Identifier" && node.id.name.startsWith("use") && node.id.name[3] === node.id.name[3].toUpperCase();
136
+ /**
137
+ * @param {Scope.Reference} ref
138
+ * @returns {boolean}
139
+ */
140
+ const isUseState = (ref) => ref.identifier.type === "Identifier" && ref.identifier.name === "useState" || ref.identifier.parent.type === "MemberExpression" && ref.identifier.parent.object.name === "React" && ref.identifier.parent.property.name === "useState";
141
+ /**
142
+ * @param {Scope.Reference} ref
143
+ * @returns {boolean}
144
+ */
145
+ const isState = (ref) => ref.resolved?.defs.some((def) => def.node.type === "VariableDeclarator" && def.node.id.type === "ArrayPattern" && (def.node.id.elements.length === 1 || def.node.id.elements.length === 2) && def.node.id.elements[0]?.type === "Identifier" && def.node.id.elements[0].name === ref.identifier.name);
146
+ /**
147
+ * @param {Scope.Reference} ref
148
+ * @returns {boolean}
149
+ */
150
+ const isStateSetter = (ref) => ref.resolved?.defs.some((def) => def.node.type === "VariableDeclarator" && def.node.id.type === "ArrayPattern" && def.node.id.elements.length === 2 && def.node.id.elements[1]?.type === "Identifier" && def.node.id.elements[1].name === ref.identifier.name);
151
+ /**
152
+ * Returns false for props of HOCs (e.g. `withRouter`) because they usually have side effects.
153
+ *
154
+ * @param {Scope.Reference} ref
155
+ * @returns {boolean}
156
+ */
157
+ const isProp = (ref) => ref.resolved?.defs.some((def) => {
158
+ const declaringNode = def.node.type === "ArrowFunctionExpression" ? def.node.parent.type === "CallExpression" ? def.node.parent.parent : def.node.parent : def.node;
159
+ return def.type === "Parameter" && (isReactFunctionalComponent(declaringNode) && !isReactFunctionalHOC(declaringNode) || isCustomHook(declaringNode));
160
+ });
161
+ /**
162
+ * @param {Scope.Reference} ref
163
+ * @returns {boolean}
164
+ */
165
+ const isConstant = (ref) => (ref.resolved?.defs ?? []).some((def) => def.node.type === "VariableDeclarator" && def.node.init?.type === "Literal" || def.node.init?.type === "TemplateLiteral" || def.node.init?.type === "ArrayExpression" || def.node.init?.type === "ObjectExpression");
166
+ /**
167
+ * @param {Scope.Reference} ref
168
+ * @returns {boolean}
169
+ */
170
+ const isUseRef = (ref) => ref.identifier.type === "Identifier" && ref.identifier.name === "useRef" || ref.identifier.parent.type === "MemberExpression" && ref.identifier.parent.object.name === "React" && ref.identifier.parent.property.name === "useRef";
171
+ /**
172
+ * @param {Scope.Reference} ref
173
+ * @returns {boolean}
174
+ */
175
+ const isRef = (ref) => ref.resolved?.defs.some((def) => def.node.type === "VariableDeclarator" && def.node.init?.type === "CallExpression" && (def.node.init.callee.type === "Identifier" && def.node.init.callee.name === "useRef" || def.node.init.callee.type === "MemberExpression" && def.node.init.callee.object.name === "React" && def.node.init.callee.property.name === "useRef"));
176
+ /**
177
+ * Whether the reference's `current` property is being accessed.
178
+ * Heuristic for whether the reference is a React ref object.
179
+ * Because we don't always have access to the `useRef` call itself.
180
+ * For example when receiving a ref from props.
181
+ *
182
+ * @param {Scope.Reference} ref
183
+ * @returns {boolean}
184
+ */
185
+ const isRefCurrent = (ref) => ref.identifier.parent.type === "MemberExpression" && ref.identifier.parent.property.type === "Identifier" && ref.identifier.parent.property.name === "current";
186
+ /**
187
+ * Does not include `useLayoutEffect`.
188
+ * When used correctly, it interacts with the DOM = external system = (probably) valid effect.
189
+ * When used incorrectly, it's probably too difficult to accurately analyze anyway.
190
+ *
191
+ * @param {Rule.Node} node
192
+ * @returns {boolean}
193
+ */
194
+ const isUseEffect = (node) => node.type === "CallExpression" && (node.callee.type === "Identifier" && node.callee.name === "useEffect" || node.callee.type === "MemberExpression" && node.callee.object.name === "React" && node.callee.property.name === "useEffect");
195
+ /**
196
+ * @param {Rule.Node} node - The `useEffect` `CallExpression` node
197
+ * @returns {Rule.Node | undefined}
198
+ */
199
+ const getEffectFn = (node) => {
200
+ const effectFn = node.arguments[0];
201
+ if (effectFn?.type !== "ArrowFunctionExpression" && effectFn?.type !== "FunctionExpression") return;
202
+ return effectFn;
203
+ };
204
+ /**
205
+ * @param {Rule.RuleContext} context
206
+ * @param {Rule.Node} node - The `useEffect` `CallExpression` node
207
+ * @returns {Scope.Reference[] | undefined}
208
+ */
209
+ const getEffectFnRefs = (context, node) => {
210
+ const effectFn = getEffectFn(node);
211
+ return effectFn ? getDownstreamRefs(context, effectFn) : void 0;
212
+ };
213
+ /**
214
+ * @param {Rule.RuleContext} context
215
+ * @param {Rule.Node} node - The `useEffect` `CallExpression` node
216
+ * @returns {Scope.Reference[] | undefined}
217
+ */
218
+ function getEffectDepsRefs(context, node) {
219
+ const depsArr = node.arguments[1];
220
+ if (depsArr?.type !== "ArrayExpression") return;
221
+ return getDownstreamRefs(context, depsArr);
222
+ }
223
+ /**
224
+ * @param {Rule.RuleContext} context
225
+ * @param {Scope.Reference} ref
226
+ * @returns {boolean} Whether this reference eventually calls a state setter function or a method on state.
227
+ */
228
+ const callsStateSetter = (context, ref) => isEventualCallTo(context, ref, isStateSetter);
229
+ /**
230
+ * @param {Rule.RuleContext} context
231
+ * @param {Scope.Reference} ref
232
+ * @returns {boolean} Whether this reference eventually calls a prop function or a method on a prop.
233
+ */
234
+ const callsProp = (context, ref) => isEventualCallTo(context, ref, isProp);
235
+ /**
236
+ * @param {Rule.RuleContext} context
237
+ * @param {Scope.Reference} ref
238
+ * @returns {boolean} Whether this reference eventually calls a method on a ref.
239
+ */
240
+ const callsRef = (context, ref) => isEventualCallTo(context, ref, (ref$1) => isRefCurrent(ref$1) || isRef(ref$1));
241
+ /**
242
+ * @param context {Rule.RuleContext}
243
+ * @param {Scope.Reference} ref
244
+ * @returns {Rule.Node | undefined} The `VariableDeclarator` node of the `useState` call.
245
+ */
246
+ const getUseStateDecl = (context, ref) => {
247
+ let node = getUpstreamRefs(context, ref).find((ref$1) => isUseState(ref$1))?.identifier;
248
+ while (node && node.type !== "VariableDeclarator") node = node.parent;
249
+ return node;
250
+ };
251
+ /**
252
+ * While it *could* be an anti-pattern or unnecessary, effects *are* meant to synchronize systems.
253
+ * So we presume that a "subscription effect" is usually valid, or at least may be more readable.
254
+ *
255
+ * TODO: We might be able to use this more granularly, e.g. ignore state setters inside a subscription effect,
256
+ * instead of ignoring the whole effect...? But it'd have to be more complicated, like also ignore the same state setters called in the body.
257
+ *
258
+ * @param {Rule.Node} node - The `useEffect` `CallExpression` node
259
+ * @returns {boolean}
260
+ */
261
+ const hasCleanup = (node) => {
262
+ const effectFn = node.arguments[0];
263
+ return (effectFn.type === "ArrowFunctionExpression" || effectFn.type === "FunctionExpression") && effectFn.body.type === "BlockStatement" && effectFn.body.body.some((stmt) => stmt.type === "ReturnStatement" && stmt.argument);
264
+ };
265
+
266
+ //#endregion
267
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-empty-effect.js
268
+ /**
269
+ * @type {import("eslint").Rule.RuleModule}
270
+ */
271
+ var no_empty_effect_default = {
272
+ meta: {
273
+ type: "suggestion",
274
+ docs: { description: "Disallow empty effects." },
275
+ schema: [],
276
+ messages: { avoidEmptyEffect: "This effect is empty and could be removed." }
277
+ },
278
+ create: (context) => ({ CallExpression: (node) => {
279
+ if (!isUseEffect(node)) return;
280
+ if (node.arguments?.length === 0 || getEffectFnRefs(context, node)?.length === 0) context.report({
281
+ node,
282
+ messageId: "avoidEmptyEffect"
283
+ });
284
+ } })
285
+ };
286
+
287
+ //#endregion
288
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-adjust-state-on-prop-change.js
289
+ /**
290
+ * @type {import("eslint").Rule.RuleModule}
291
+ */
292
+ var no_adjust_state_on_prop_change_default = {
293
+ meta: {
294
+ type: "suggestion",
295
+ docs: {
296
+ description: "Disallow adjusting state in an effect when a prop changes.",
297
+ url: "https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes"
298
+ },
299
+ schema: [],
300
+ messages: { avoidAdjustingStateWhenAPropChanges: "Avoid adjusting state when a prop changes. Instead, adjust the state directly during render, or refactor your state to avoid this need entirely." }
301
+ },
302
+ create: (context) => ({ CallExpression: (node) => {
303
+ if (!isUseEffect(node)) return;
304
+ const effectFnRefs = getEffectFnRefs(context, node);
305
+ const depsRefs = getEffectDepsRefs(context, node);
306
+ if (!effectFnRefs || !depsRefs) return;
307
+ const isSomeDepsProps = depsRefs.flatMap((ref) => getUpstreamRefs(context, ref)).some((ref) => isProp(ref));
308
+ effectFnRefs.filter((ref) => callsStateSetter(context, ref)).filter((ref) => isSynchronous(ref.identifier, getEffectFn(node))).forEach((ref) => {
309
+ const callExpr = getCallExpr(ref);
310
+ const isSomeArgsProps = getArgsUpstreamRefs(context, ref).some((ref$1) => isProp(ref$1));
311
+ if (isSomeDepsProps && !isSomeArgsProps) context.report({
312
+ node: callExpr,
313
+ messageId: "avoidAdjustingStateWhenAPropChanges"
314
+ });
315
+ });
316
+ } })
317
+ };
318
+
319
+ //#endregion
320
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-reset-all-state-on-prop-change.js
321
+ /**
322
+ * @type {import("eslint").Rule.RuleModule}
323
+ */
324
+ var no_reset_all_state_on_prop_change_default = {
325
+ meta: {
326
+ type: "suggestion",
327
+ docs: {
328
+ description: "Disallow resetting all state in an effect when a prop changes.",
329
+ url: "https://react.dev/learn/you-might-not-need-an-effect#resetting-all-state-when-a-prop-changes"
330
+ },
331
+ schema: [],
332
+ messages: { avoidResettingAllStateWhenAPropChanges: "Avoid resetting all state when a prop changes. If \"{{prop}}\" is a key, pass it as `key` instead so React will reset the component." }
333
+ },
334
+ create: (context) => ({ CallExpression: (node) => {
335
+ if (!isUseEffect(node)) return;
336
+ const effectFnRefs = getEffectFnRefs(context, node);
337
+ const depsRefs = getEffectDepsRefs(context, node);
338
+ if (!effectFnRefs || !depsRefs) return;
339
+ const containingNode = findContainingNode(node);
340
+ if (containingNode && isCustomHook(containingNode)) return;
341
+ const propUsedToResetAllState = findPropUsedToResetAllState(context, effectFnRefs, depsRefs, node);
342
+ if (propUsedToResetAllState) context.report({
343
+ node,
344
+ messageId: "avoidResettingAllStateWhenAPropChanges",
345
+ data: { prop: propUsedToResetAllState.identifier.name }
346
+ });
347
+ } })
348
+ };
349
+ const findPropUsedToResetAllState = (context, effectFnRefs, depsRefs, useEffectNode) => {
350
+ const stateSetterRefs = effectFnRefs.filter((ref) => callsStateSetter(context, ref));
351
+ return stateSetterRefs.length > 0 && stateSetterRefs.every((ref) => isSetStateToInitialValue(context, ref)) && stateSetterRefs.length === countUseStates(context, findContainingNode(useEffectNode)) ? depsRefs.flatMap((ref) => getUpstreamRefs(context, ref)).find((ref) => isProp(ref)) : void 0;
352
+ };
353
+ const isSetStateToInitialValue = (context, setterRef) => {
354
+ const setStateToValue = getCallExpr(setterRef).arguments[0];
355
+ const stateInitialValue = getUseStateDecl(context, setterRef).init.arguments[0];
356
+ const isUndefined = (node) => node === void 0 || node.name === "undefined";
357
+ if (isUndefined(setStateToValue) && isUndefined(stateInitialValue)) return true;
358
+ if (setStateToValue === null && stateInitialValue === null) return true;
359
+ else if (setStateToValue && !stateInitialValue || !setStateToValue && stateInitialValue) return false;
360
+ return context.sourceCode.getText(setStateToValue) === context.sourceCode.getText(stateInitialValue);
361
+ };
362
+ const countUseStates = (context, componentNode) => {
363
+ if (!componentNode) return 0;
364
+ return getDownstreamRefs(context, componentNode).filter((ref) => isState(ref)).length;
365
+ };
366
+ const findContainingNode = (node) => {
367
+ if (!node) return;
368
+ else if (isReactFunctionalComponent(node) || isReactFunctionalHOC(node) || isCustomHook(node)) return node;
369
+ else return findContainingNode(node.parent);
370
+ };
371
+
372
+ //#endregion
373
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-event-handler.js
374
+ /**
375
+ * @type {import("eslint").Rule.RuleModule}
376
+ */
377
+ var no_event_handler_default = {
378
+ meta: {
379
+ type: "suggestion",
380
+ docs: {
381
+ description: "Disallow using state and an effect as an event handler.",
382
+ url: "https://react.dev/learn/you-might-not-need-an-effect#sharing-logic-between-event-handlers"
383
+ },
384
+ schema: [],
385
+ messages: { avoidEventHandler: "Avoid using state and effects as an event handler. Instead, call the event handling code directly when the event occurs." }
386
+ },
387
+ create: (context) => ({ CallExpression: (node) => {
388
+ if (!isUseEffect(node) || hasCleanup(node)) return;
389
+ const effectFnRefs = getEffectFnRefs(context, node);
390
+ const depsRefs = getEffectDepsRefs(context, node);
391
+ if (!effectFnRefs || !depsRefs) return;
392
+ findDownstreamNodes(context, node, "IfStatement").filter((ifNode) => !ifNode.alternate).filter((ifNode) => getDownstreamRefs(context, ifNode.test).flatMap((ref) => getUpstreamRefs(context, ref)).some((ref) => isState(ref))).forEach((ifNode) => {
393
+ context.report({
394
+ node: ifNode.test,
395
+ messageId: "avoidEventHandler"
396
+ });
397
+ });
398
+ } })
399
+ };
400
+
401
+ //#endregion
402
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-pass-live-state-to-parent.js
403
+ /**
404
+ * @type {import("eslint").Rule.RuleModule}
405
+ */
406
+ var no_pass_live_state_to_parent_default = {
407
+ meta: {
408
+ type: "suggestion",
409
+ docs: {
410
+ description: "Disallow passing live state to parent components in an effect.",
411
+ url: "https://react.dev/learn/you-might-not-need-an-effect#notifying-parent-components-about-state-changes"
412
+ },
413
+ schema: [],
414
+ messages: { avoidPassingLiveStateToParent: "Avoid passing live state to parents in an effect. Instead, lift the state to the parent and pass it down to the child as a prop." }
415
+ },
416
+ create: (context) => ({ CallExpression: (node) => {
417
+ if (!isUseEffect(node)) return;
418
+ const effectFnRefs = getEffectFnRefs(context, node);
419
+ const depsRefs = getEffectDepsRefs(context, node);
420
+ if (!effectFnRefs || !depsRefs) return;
421
+ effectFnRefs.filter((ref) => callsProp(context, ref)).filter((ref) => isSynchronous(ref.identifier, getEffectFn(node))).forEach((ref) => {
422
+ const callExpr = getCallExpr(ref);
423
+ if (getArgsUpstreamRefs(context, ref).some((ref$1) => isState(ref$1))) context.report({
424
+ node: callExpr,
425
+ messageId: "avoidPassingLiveStateToParent"
426
+ });
427
+ });
428
+ } })
429
+ };
430
+
431
+ //#endregion
432
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-initialize-state.js
433
+ /**
434
+ * @type {import("eslint").Rule.RuleModule}
435
+ */
436
+ var no_initialize_state_default = {
437
+ meta: {
438
+ type: "suggestion",
439
+ docs: {
440
+ description: "Disallow initializing state in an effect.",
441
+ url: "https://tkdodo.eu/blog/avoiding-hydration-mismatches-with-use-sync-external-store"
442
+ },
443
+ schema: [],
444
+ messages: { avoidInitializingState: "Avoid initializing state in an effect. Instead, initialize \"{{state}}\"'s `useState()` with \"{{arguments}}\". For SSR hydration, prefer `useSyncExternalStore()`." }
445
+ },
446
+ create: (context) => ({ CallExpression: (node) => {
447
+ if (!isUseEffect(node)) return;
448
+ const effectFnRefs = getEffectFnRefs(context, node);
449
+ const depsRefs = getEffectDepsRefs(context, node);
450
+ if (!effectFnRefs || !depsRefs) return;
451
+ if (depsRefs.length > 0) return;
452
+ effectFnRefs.filter((ref) => callsStateSetter(context, ref)).filter((ref) => isSynchronous(ref.identifier, getEffectFn(node))).forEach((ref) => {
453
+ const callExpr = getCallExpr(ref);
454
+ const useStateNode = getUseStateDecl(context, ref);
455
+ const stateName = (useStateNode.id.elements[0] ?? useStateNode.id.elements[1])?.name;
456
+ const argumentText = callExpr.arguments[0] ? context.sourceCode.getText(callExpr.arguments[0]) : "undefined";
457
+ context.report({
458
+ node: getCallExpr(ref),
459
+ messageId: "avoidInitializingState",
460
+ data: {
461
+ state: stateName,
462
+ arguments: argumentText
463
+ }
464
+ });
465
+ });
466
+ } })
467
+ };
468
+
469
+ //#endregion
470
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-chain-state-updates.js
471
+ /**
472
+ * @type {import("eslint").Rule.RuleModule}
473
+ */
474
+ var no_chain_state_updates_default = {
475
+ meta: {
476
+ type: "suggestion",
477
+ docs: {
478
+ description: "Disallow chaining state changes in an effect.",
479
+ url: "https://react.dev/learn/you-might-not-need-an-effect#chains-of-computations"
480
+ },
481
+ schema: [],
482
+ messages: { avoidChainingStateUpdates: "Avoid chaining state changes. When possible, update all relevant state simultaneously." }
483
+ },
484
+ create: (context) => ({ CallExpression: (node) => {
485
+ if (!isUseEffect(node) || hasCleanup(node)) return;
486
+ const effectFnRefs = getEffectFnRefs(context, node);
487
+ const depsRefs = getEffectDepsRefs(context, node);
488
+ if (!effectFnRefs || !depsRefs) return;
489
+ const isSomeDepsState = depsRefs.flatMap((ref) => getUpstreamRefs(context, ref)).some((ref) => isState(ref));
490
+ effectFnRefs.filter((ref) => callsStateSetter(context, ref)).filter((ref) => isSynchronous(ref.identifier, getEffectFn(node))).forEach((ref) => {
491
+ const callExpr = getCallExpr(ref);
492
+ const isSomeArgsState = getArgsUpstreamRefs(context, ref).some((ref$1) => isState(ref$1));
493
+ if (isSomeDepsState && !isSomeArgsState) context.report({
494
+ node: callExpr,
495
+ messageId: "avoidChainingStateUpdates"
496
+ });
497
+ });
498
+ } })
499
+ };
500
+
501
+ //#endregion
502
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-derived-state.js
503
+ /**
504
+ * @type {import('eslint').Rule.RuleModule}
505
+ */
506
+ var no_derived_state_default = {
507
+ meta: {
508
+ type: "suggestion",
509
+ docs: {
510
+ description: "Disallow storing derived state in an effect.",
511
+ url: "https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state"
512
+ },
513
+ schema: [],
514
+ messages: {
515
+ avoidDerivedState: "Avoid storing derived state. Compute \"{{state}}\" directly during render, optionally with `useMemo` if it's expensive.",
516
+ avoidSingleSetter: "Avoid storing derived state. \"{{state}}\" is only set here, and thus could be computed directly during render."
517
+ }
518
+ },
519
+ create: (context) => ({ CallExpression: (node) => {
520
+ if (!isUseEffect(node) || hasCleanup(node)) return;
521
+ const effectFnRefs = getEffectFnRefs(context, node);
522
+ const depsRefs = getEffectDepsRefs(context, node);
523
+ if (!effectFnRefs || !depsRefs) return;
524
+ effectFnRefs.filter((ref) => callsStateSetter(context, ref)).filter((ref) => isSynchronous(ref.identifier, getEffectFn(node))).forEach((ref) => {
525
+ const callExpr = getCallExpr(ref);
526
+ const useStateNode = getUseStateDecl(context, ref);
527
+ const stateName = (useStateNode?.id.elements[0] ?? useStateNode?.id.elements[1])?.name;
528
+ const argsUpstreamRefs = getArgsUpstreamRefs(context, ref);
529
+ const depsUpstreamRefs = depsRefs.flatMap((ref$1) => getUpstreamRefs(context, ref$1));
530
+ const isSomeArgsInternal = argsUpstreamRefs.some((ref$1) => isState(ref$1) || isProp(ref$1));
531
+ const isValueAlwaysInSync = argsUpstreamRefs.length && argsUpstreamRefs.every((argRef) => depsUpstreamRefs.some((depRef) => argRef.resolved == depRef.resolved)) && countCalls(ref) === 1;
532
+ if (isSomeArgsInternal) context.report({
533
+ node: callExpr,
534
+ messageId: "avoidDerivedState",
535
+ data: { state: stateName }
536
+ });
537
+ else if (isValueAlwaysInSync) context.report({
538
+ node: callExpr,
539
+ messageId: "avoidSingleSetter",
540
+ data: { state: stateName }
541
+ });
542
+ });
543
+ } })
544
+ };
545
+ const countCalls = (ref) => ref.resolved.references.filter((ref$1) => ref$1.identifier.parent.type === "CallExpression").length;
546
+
547
+ //#endregion
548
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-pass-data-to-parent.js
549
+ /**
550
+ * @type {import("eslint").Rule.RuleModule}
551
+ */
552
+ var no_pass_data_to_parent_default = {
553
+ meta: {
554
+ type: "suggestion",
555
+ docs: {
556
+ description: "Disallow passing data to parents in an effect.",
557
+ url: "https://react.dev/learn/you-might-not-need-an-effect#passing-data-to-the-parent"
558
+ },
559
+ schema: [],
560
+ messages: { avoidPassingDataToParent: "Avoid passing data to parents in an effect. Instead, let the parent fetch the data itself and pass it down to the child as a prop." }
561
+ },
562
+ create: (context) => ({ CallExpression: (node) => {
563
+ if (!isUseEffect(node) || hasCleanup(node)) return;
564
+ const effectFnRefs = getEffectFnRefs(context, node);
565
+ const depsRefs = getEffectDepsRefs(context, node);
566
+ if (!effectFnRefs || !depsRefs) return;
567
+ effectFnRefs.filter((ref) => callsProp(context, ref)).filter((ref) => !callsRef(context, ref)).filter((ref) => isSynchronous(ref.identifier, getEffectFn(node))).forEach((ref) => {
568
+ const callExpr = getCallExpr(ref);
569
+ if (getUpstreamRefs(context, ref).map((ref$1) => getCallExpr(ref$1)).filter(Boolean).flatMap((callExpr$1) => callExpr$1.arguments).flatMap((arg) => getDownstreamRefs(context, arg)).flatMap((ref$1) => getUpstreamRefs(context, ref$1, "leaf")).some((ref$1) => !isUseState(ref$1) && !isProp(ref$1) && !isUseRef(ref$1) && !isRefCurrent(ref$1) && !isConstant(ref$1))) context.report({
570
+ node: callExpr,
571
+ messageId: "avoidPassingDataToParent"
572
+ });
573
+ });
574
+ } })
575
+ };
576
+
577
+ //#endregion
578
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/rules/no-pass-ref-to-parent.js
579
+ /**
580
+ * @type {import("eslint").Rule.RuleModule}
581
+ */
582
+ var no_pass_ref_to_parent_default = {
583
+ meta: {
584
+ type: "suggestion",
585
+ docs: {
586
+ description: "Disallow passing refs, or data from callbacks registered on them, to parents in an effect. Use `forwardRef` instead.",
587
+ url: "https://react.dev/reference/react/forwardRef"
588
+ },
589
+ schema: [],
590
+ messages: {
591
+ avoidPassingRefToParent: "Avoid passing refs to parents in an effect. Use `forwardRef` instead.",
592
+ avoidPropCallbackInRefCallback: "Avoid calling props inside callbacks registered on refs in an effect. Use `forwardRef` to register the callback in the parent instead.",
593
+ avoidReceivingRefFromParent: "Avoid receiving refs from parents to use in an effect. Use `forwardRef` instead."
594
+ }
595
+ },
596
+ create: (context) => ({ CallExpression: (node) => {
597
+ if (!isUseEffect(node) || hasCleanup(node)) return;
598
+ const effectFnRefs = getEffectFnRefs(context, node);
599
+ const depsRefs = getEffectDepsRefs(context, node);
600
+ if (!effectFnRefs || !depsRefs) return;
601
+ effectFnRefs.filter((ref) => callsProp(context, ref)).forEach((ref) => {
602
+ const callExpr = getCallExpr(ref);
603
+ if (getArgsUpstreamRefs(context, ref).some((ref$1) => isRef(ref$1))) context.report({
604
+ node: callExpr,
605
+ messageId: "avoidPassingRefToParent"
606
+ });
607
+ });
608
+ effectFnRefs.filter((ref) => callsRef(context, ref)).forEach((ref) => {
609
+ const callExpr = getCallExpr(ref);
610
+ if (getArgsUpstreamRefs(context, ref).some((ref$1) => callsProp(context, ref$1))) context.report({
611
+ node: callExpr,
612
+ messageId: "avoidPropCallbackInRefCallback"
613
+ });
614
+ });
615
+ effectFnRefs.filter((ref) => callsProp(context, ref) && callsRef(context, ref)).forEach((ref) => {
616
+ const callExpr = getCallExpr(ref);
617
+ context.report({
618
+ node: callExpr,
619
+ messageId: "avoidReceivingRefFromParent"
620
+ });
621
+ });
622
+ } })
623
+ };
624
+
625
+ //#endregion
626
+ //#region ../../node_modules/.pnpm/eslint-plugin-react-you-might-not-need-an-effect@0.8.1_eslint@9.39.2_jiti@2.6.1_/node_modules/eslint-plugin-react-you-might-not-need-an-effect/src/index.js
627
+ /**
628
+ * @type {import("eslint").ESLint.Plugin}
629
+ */
630
+ const plugin = {
631
+ meta: { name: "react-you-might-not-need-an-effect" },
632
+ configs: {},
633
+ rules: {
634
+ "no-empty-effect": no_empty_effect_default,
635
+ "no-adjust-state-on-prop-change": no_adjust_state_on_prop_change_default,
636
+ "no-reset-all-state-on-prop-change": no_reset_all_state_on_prop_change_default,
637
+ "no-event-handler": no_event_handler_default,
638
+ "no-pass-live-state-to-parent": no_pass_live_state_to_parent_default,
639
+ "no-pass-data-to-parent": no_pass_data_to_parent_default,
640
+ "no-pass-ref-to-parent": no_pass_ref_to_parent_default,
641
+ "no-initialize-state": no_initialize_state_default,
642
+ "no-chain-state-updates": no_chain_state_updates_default,
643
+ "no-derived-state": no_derived_state_default
644
+ }
645
+ };
646
+ const recommendedRules = Object.keys(plugin.rules).reduce((acc, ruleName) => {
647
+ acc[plugin.meta.name + "/" + ruleName] = "warn";
648
+ return acc;
649
+ }, {});
650
+ const languageOptions = {
651
+ globals: { ...globals.browser },
652
+ parserOptions: { ecmaFeatures: { jsx: true } }
653
+ };
654
+ Object.assign(plugin.configs, {
655
+ recommended: {
656
+ files: ["**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}"],
657
+ plugins: { [plugin.meta.name]: plugin },
658
+ rules: recommendedRules,
659
+ languageOptions
660
+ },
661
+ "legacy-recommended": {
662
+ plugins: [plugin.meta.name],
663
+ rules: recommendedRules,
664
+ ...languageOptions
665
+ }
666
+ });
667
+ var src_default = plugin;
668
+
669
+ //#endregion
670
+ export { src_default as default };
671
+ //# sourceMappingURL=src-BncWNtPe.js.map