eslint-plugin-react-x 5.24.0-beta.1 → 5.24.0

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 (2) hide show
  1. package/dist/index.js +791 -770
  2. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -145,7 +145,7 @@ const rules$6 = {
145
145
  //#endregion
146
146
  //#region package.json
147
147
  var name$6 = "eslint-plugin-react-x";
148
- var version = "5.24.0-beta.1";
148
+ var version = "5.24.0";
149
149
 
150
150
  //#endregion
151
151
  //#region src/utils/create-rule.ts
@@ -2093,748 +2093,165 @@ function create$41(context) {
2093
2093
  }
2094
2094
 
2095
2095
  //#endregion
2096
- //#region src/rules/no-class-component/no-class-component.ts
2097
- const RULE_NAME$40 = "no-class-component";
2098
- var no_class_component_default = createRule({
2099
- meta: {
2100
- type: "suggestion",
2101
- docs: { description: "Disallows class components except for error boundaries." },
2102
- messages: { default: "Avoid using class components. Use function components instead." },
2103
- schema: []
2104
- },
2105
- name: RULE_NAME$40,
2106
- create: create$40,
2107
- defaultOptions: []
2108
- });
2109
- function create$40(context) {
2110
- if (!context.sourceCode.text.includes("Component")) return {};
2111
- const { api, visitor } = core.getClassComponentCollector(context);
2112
- return merge(visitor, { "Program:exit"(program) {
2113
- for (const { id, name = "anonymous", node: component } of api.getAllComponents(program)) {
2114
- if (component.body.body.some((m) => core.isComponentDidCatch(m) || core.isGetDerivedStateFromError(m))) continue;
2115
- const classToken = context.sourceCode.getFirstToken(component, { filter: (token) => token.value === "class" });
2116
- context.report({
2117
- data: { name },
2118
- loc: (id ?? classToken ?? component).loc,
2119
- messageId: "default",
2120
- node: component
2121
- });
2122
- }
2123
- } });
2124
- }
2125
-
2126
- //#endregion
2127
- //#region src/rules/no-clone-element/no-clone-element.ts
2128
- const RULE_NAME$39 = "no-clone-element";
2129
- var no_clone_element_default = createRule({
2130
- meta: {
2131
- type: "suggestion",
2132
- docs: { description: "Disallows 'cloneElement'." },
2133
- messages: { default: "Using 'cloneElement' is uncommon and can lead to fragile code. Use alternatives instead." },
2134
- schema: []
2135
- },
2136
- name: RULE_NAME$39,
2137
- create: create$39,
2138
- defaultOptions: []
2139
- });
2140
- function create$39(context) {
2141
- return { CallExpression(node) {
2142
- if (core.isCloneElementCall(context, node)) context.report({
2143
- messageId: "default",
2144
- node
2145
- });
2146
- } };
2096
+ //#region ../../.pkgs/eff/dist/index.js
2097
+ function not(predicate) {
2098
+ return (data) => !predicate(data);
2147
2099
  }
2148
-
2149
- //#endregion
2150
- //#region src/rules/no-component-will-mount/no-component-will-mount.ts
2151
- const RULE_NAME$38 = "no-component-will-mount";
2152
- var no_component_will_mount_default = createRule({
2153
- meta: {
2154
- type: "problem",
2155
- docs: { description: "Replaces usage of 'componentWillMount' with 'UNSAFE_componentWillMount'." },
2156
- fixable: "code",
2157
- messages: { default: "[Deprecated] Use 'UNSAFE_componentWillMount' instead." },
2158
- schema: []
2159
- },
2160
- name: RULE_NAME$38,
2161
- create: create$38,
2162
- defaultOptions: []
2163
- });
2164
- function create$38(context) {
2165
- if (!context.sourceCode.text.includes("componentWillMount")) return {};
2166
- const { api, visitor } = core.getClassComponentCollector(context);
2167
- return merge(visitor, { "Program:exit"(program) {
2168
- for (const { node: component } of api.getAllComponents(program)) {
2169
- const { body } = component.body;
2170
- for (const member of body) if (core.isComponentWillMount(member)) context.report({
2171
- fix(fixer) {
2172
- if (!("key" in member)) return null;
2173
- return fixer.replaceText(member.key, "UNSAFE_componentWillMount");
2174
- },
2175
- messageId: "default",
2176
- node: member
2177
- });
2178
- }
2179
- } });
2100
+ function or(a, b) {
2101
+ return (data) => a(data) || b(data);
2180
2102
  }
2181
-
2182
- //#endregion
2183
- //#region src/rules/no-component-will-receive-props/no-component-will-receive-props.ts
2184
- const RULE_NAME$37 = "no-component-will-receive-props";
2185
- var no_component_will_receive_props_default = createRule({
2186
- meta: {
2187
- type: "problem",
2188
- docs: { description: "Replaces usage of 'componentWillReceiveProps' with 'UNSAFE_componentWillReceiveProps'." },
2189
- fixable: "code",
2190
- messages: { default: "[Deprecated] Use 'UNSAFE_componentWillReceiveProps' instead." },
2191
- schema: []
2192
- },
2193
- name: RULE_NAME$37,
2194
- create: create$37,
2195
- defaultOptions: []
2196
- });
2197
- function create$37(context) {
2198
- if (!context.sourceCode.text.includes("componentWillReceiveProps")) return {};
2199
- const { api, visitor } = core.getClassComponentCollector(context);
2200
- return merge(visitor, { "Program:exit"(program) {
2201
- for (const { node: component } of api.getAllComponents(program)) {
2202
- const { body } = component.body;
2203
- for (const member of body) if (core.isComponentWillReceiveProps(member)) context.report({
2204
- fix(fixer) {
2205
- if (!("key" in member)) return null;
2206
- return fixer.replaceText(member.key, "UNSAFE_componentWillReceiveProps");
2207
- },
2208
- messageId: "default",
2209
- node: member
2210
- });
2211
- }
2212
- } });
2103
+ /**
2104
+ * A function that checks if the passed parameter is a string and narrows its type accordingly.
2105
+ *
2106
+ * @param data - The variable to check.
2107
+ * @returns True if the passed input is a string, false otherwise.
2108
+ * @category guards
2109
+ */
2110
+ function isString(data) {
2111
+ return typeof data === "string";
2213
2112
  }
2214
-
2215
- //#endregion
2216
- //#region src/rules/no-component-will-update/no-component-will-update.ts
2217
- const RULE_NAME$36 = "no-component-will-update";
2218
- var no_component_will_update_default = createRule({
2219
- meta: {
2220
- type: "problem",
2221
- docs: { description: "Replaces usage of 'componentWillUpdate' with 'UNSAFE_componentWillUpdate'." },
2222
- fixable: "code",
2223
- messages: { default: "[Deprecated] Use 'UNSAFE_componentWillUpdate' instead." },
2224
- schema: []
2225
- },
2226
- name: RULE_NAME$36,
2227
- create: create$36,
2228
- defaultOptions: []
2229
- });
2230
- function create$36(context) {
2231
- if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
2232
- const { api, visitor } = core.getClassComponentCollector(context);
2233
- return merge(visitor, { "Program:exit"(program) {
2234
- for (const { node: component } of api.getAllComponents(program)) {
2235
- const { body } = component.body;
2236
- for (const member of body) if (core.isComponentWillUpdate(member)) context.report({
2237
- fix(fixer) {
2238
- if (!("key" in member)) return null;
2239
- return fixer.replaceText(member.key, "UNSAFE_componentWillUpdate");
2240
- },
2241
- messageId: "default",
2242
- node: member
2243
- });
2113
+ /**
2114
+ * Applies a `pipe` method's variadic arguments to an initial value from left
2115
+ * to right.
2116
+ *
2117
+ * **When to use**
2118
+ *
2119
+ * Use to implement a custom `.pipe(...)` method from JavaScript's `arguments`
2120
+ * object.
2121
+ *
2122
+ * **Details**
2123
+ *
2124
+ * This helper is intended for implementing `Pipeable.pipe` methods that
2125
+ * receive JavaScript's `arguments` object. With no functions it returns the
2126
+ * original value; otherwise it feeds each result into the next function.
2127
+ *
2128
+ * **Example** (Implementing a pipe method)
2129
+ *
2130
+ * ```ts
2131
+ * import { Pipeable } from "effect"
2132
+ *
2133
+ * class NumberBox {
2134
+ * constructor(readonly value: number) {}
2135
+ *
2136
+ * pipe(..._fns: ReadonlyArray<(value: number) => number>): number {
2137
+ * return Pipeable.pipeArguments(this.value, arguments) as number
2138
+ * }
2139
+ * }
2140
+ *
2141
+ * const result = new NumberBox(5).pipe(
2142
+ * (n) => n + 2,
2143
+ * (n) => n * 3
2144
+ * )
2145
+ * console.log(result) // 21
2146
+ * ```
2147
+ *
2148
+ * @category combinators
2149
+ * @since 2.0.0
2150
+ */
2151
+ const pipeArguments = (self, args) => {
2152
+ switch (args.length) {
2153
+ case 0: return self;
2154
+ case 1: return args[0](self);
2155
+ case 2: return args[1](args[0](self));
2156
+ case 3: return args[2](args[1](args[0](self)));
2157
+ case 4: return args[3](args[2](args[1](args[0](self))));
2158
+ case 5: return args[4](args[3](args[2](args[1](args[0](self)))));
2159
+ case 6: return args[5](args[4](args[3](args[2](args[1](args[0](self))))));
2160
+ case 7: return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))));
2161
+ case 8: return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))));
2162
+ case 9: return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))));
2163
+ default: {
2164
+ let ret = self;
2165
+ for (let i = 0, len = args.length; i < len; i++) ret = args[i](ret);
2166
+ return ret;
2244
2167
  }
2245
- } });
2246
- }
2247
-
2248
- //#endregion
2249
- //#region src/rules/no-context-provider/no-context-provider.ts
2250
- const RULE_NAME$35 = "no-context-provider";
2251
- var no_context_provider_default = createRule({
2252
- meta: {
2253
- type: "suggestion",
2254
- docs: { description: "Replaces usage of '<Context.Provider>' with '<Context>'." },
2255
- fixable: "code",
2256
- hasSuggestions: true,
2257
- messages: {
2258
- default: "In React 19, you can render '<Context>' as a provider instead of '<Context.Provider>'.",
2259
- replace: "Replace '<Context.Provider>' with '<Context>'."
2260
- },
2261
- schema: []
2262
- },
2263
- name: RULE_NAME$35,
2264
- create: create$35,
2265
- defaultOptions: []
2266
- });
2267
- function create$35(context) {
2268
- if (!context.sourceCode.text.includes("Provider")) return {};
2269
- const { version } = getSettingsFromContext(context);
2270
- if (compare(version, "19.0.0", "<")) return {};
2271
- return { JSXElement(node) {
2272
- const parts = getElementFullType(node).split(".");
2273
- const selfName = parts.pop();
2274
- const contextFullName = parts.join(".");
2275
- const contextSelfName = parts.pop();
2276
- if (selfName !== "Provider") return;
2277
- if (contextSelfName == null || !contextSelfName.endsWith("Context")) return;
2278
- context.report({
2279
- messageId: "default",
2280
- node,
2281
- suggest: [{
2282
- fix(fixer) {
2283
- if (!core.isFunctionComponentNameLoose(contextSelfName)) return null;
2284
- const openingElement = node.openingElement;
2285
- const closingElement = node.closingElement;
2286
- if (closingElement == null) return fixer.replaceText(openingElement.name, contextFullName);
2287
- return [fixer.replaceText(openingElement.name, contextFullName), fixer.replaceText(closingElement.name, contextFullName)];
2288
- },
2289
- messageId: "replace"
2290
- }]
2291
- });
2292
- } };
2293
- }
2294
-
2295
- //#endregion
2296
- //#region src/rules/no-create-ref/no-create-ref.ts
2297
- const RULE_NAME$34 = "no-create-ref";
2298
- var no_create_ref_default = createRule({
2299
- meta: {
2300
- type: "suggestion",
2301
- docs: { description: "Disallows 'createRef' in function components and Hooks." },
2302
- messages: { default: "[Deprecated] Use 'useRef' instead." },
2303
- schema: []
2304
- },
2305
- name: RULE_NAME$34,
2306
- create: create$34,
2307
- defaultOptions: []
2308
- });
2309
- function create$34(context) {
2310
- if (!context.sourceCode.text.includes("createRef")) return {};
2311
- const fc = core.getFunctionComponentCollector(context);
2312
- const hc = core.getHookCollector(context);
2313
- const createRefCalls = /* @__PURE__ */ new Set();
2314
- return merge(fc.visitor, hc.visitor, {
2315
- CallExpression(node) {
2316
- if (!core.isCreateRefCall(context, node)) return;
2317
- createRefCalls.add(node);
2318
- },
2319
- "Program:exit"(node) {
2320
- const comps = fc.api.getAllComponents(node);
2321
- const hooks = hc.api.getAllHooks(node);
2322
- const funcs = [...comps, ...hooks];
2323
- for (const call of createRefCalls) {
2324
- if (Traverse.findParent(call, (n) => funcs.some((f) => f.node === n)) == null) continue;
2325
- context.report({
2326
- messageId: "default",
2327
- node: call
2328
- });
2329
- }
2330
- }
2331
- });
2332
- }
2333
-
2334
- //#endregion
2335
- //#region src/rules/no-direct-mutation-state/no-direct-mutation-state.ts
2336
- const RULE_NAME$33 = "no-direct-mutation-state";
2337
- var no_direct_mutation_state_default = createRule({
2338
- meta: {
2339
- type: "problem",
2340
- docs: { description: "Disallows direct mutation of 'this.state'." },
2341
- messages: { default: "Do not mutate state directly. Use 'setState()' instead." },
2342
- schema: []
2343
- },
2344
- name: RULE_NAME$33,
2345
- create: create$33,
2346
- defaultOptions: []
2347
- });
2348
- function isConstructorFunction(node) {
2349
- return Check.isOneOf([AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression])(node) && Check.isPropertyOrMethod(node.parent) && Check.isIdentifier(node.parent.key, "constructor");
2350
- }
2351
- function isAssignmentToThisState(node) {
2352
- const { left } = node;
2353
- let current = Extract.unwrap(left);
2354
- while (current.type === AST_NODE_TYPES.MemberExpression) {
2355
- const object = Extract.unwrap(current.object);
2356
- const property = current.property;
2357
- if (object.type === AST_NODE_TYPES.ThisExpression && Check.isIdentifier(property, "state")) return true;
2358
- current = object;
2359
- }
2360
- return false;
2361
- }
2362
- function create$33(context) {
2363
- return { AssignmentExpression(node) {
2364
- if (!isAssignmentToThisState(node)) return;
2365
- const fact = Traverse.findParent(node, Check.isClass);
2366
- if (fact == null) return;
2367
- if (core.isClassComponent(fact) && context.sourceCode.getScope(node).block !== Traverse.findParent(node, isConstructorFunction)) context.report({
2368
- messageId: "default",
2369
- node
2370
- });
2371
- } };
2372
- }
2373
-
2374
- //#endregion
2375
- //#region src/rules/no-duplicate-key/no-duplicate-key.ts
2376
- const RULE_NAME$32 = "no-duplicate-key";
2377
- var no_duplicate_key_default = createRule({
2378
- meta: {
2379
- type: "problem",
2380
- docs: { description: "Prevents duplicate 'key' props on sibling elements when rendering lists." },
2381
- messages: { default: "The 'key' prop must be unique to its sibling elements." },
2382
- schema: []
2383
- },
2384
- name: RULE_NAME$32,
2385
- create: create$32,
2386
- defaultOptions: []
2387
- });
2388
- function create$32(context) {
2389
- if (!context.sourceCode.text.includes("key=")) return {};
2390
- const keyedEntries = /* @__PURE__ */ new Map();
2391
- function isKeyValueEqual(a, b) {
2392
- const aValue = a.value;
2393
- const bValue = b.value;
2394
- if (aValue == null || bValue == null) return false;
2395
- return Compare.isEqual(aValue, bValue);
2396
2168
  }
2397
- return {
2398
- "JSXAttribute[name.name='key']"(node) {
2399
- const jsxElement = node.parent.parent;
2400
- switch (jsxElement.parent.type) {
2401
- case AST_NODE_TYPES.ArrayExpression:
2402
- case AST_NODE_TYPES.JSXElement:
2403
- case AST_NODE_TYPES.JSXFragment: {
2404
- const root = jsxElement.parent;
2405
- const prevKeys = keyedEntries.get(root)?.keys ?? [];
2406
- keyedEntries.set(root, {
2407
- hasDuplicate: prevKeys.some((prevKey) => isKeyValueEqual(prevKey, node)),
2408
- keys: [...prevKeys, node],
2409
- root: jsxElement.parent
2410
- });
2411
- break;
2412
- }
2413
- default: {
2414
- const call = Traverse.findParent(jsxElement, (n) => {
2415
- if (n.type !== AST_NODE_TYPES.CallExpression) return false;
2416
- const callee = Extract.unwrap(n.callee);
2417
- if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;
2418
- return Check.isIdentifier(callee.property, "map");
2419
- });
2420
- const iter = Traverse.findParent(jsxElement, Check.isFunction, (n) => n === call);
2421
- if (!Check.isFunction(iter)) return;
2422
- const arg0 = call?.arguments[0];
2423
- if (call == null || arg0 == null) return;
2424
- if (Extract.unwrap(arg0) !== iter) return;
2425
- keyedEntries.set(call, {
2426
- hasDuplicate: node.value?.type === AST_NODE_TYPES.Literal,
2427
- keys: [node],
2428
- root: call
2429
- });
2430
- }
2431
- }
2432
- },
2433
- "Program:exit"() {
2434
- for (const { hasDuplicate, keys } of keyedEntries.values()) {
2435
- if (!hasDuplicate) continue;
2436
- for (const key of keys) context.report({
2437
- data: { value: context.sourceCode.getText(key) },
2438
- messageId: "default",
2439
- node: key
2440
- });
2441
- }
2442
- }
2443
- };
2444
- }
2445
-
2446
- //#endregion
2447
- //#region src/rules/no-forward-ref/no-forward-ref.ts
2448
- const RULE_NAME$31 = "no-forward-ref";
2449
- var no_forward_ref_default = createRule({
2450
- meta: {
2451
- type: "suggestion",
2452
- docs: { description: "Replaces usage of 'forwardRef' with passing 'ref' as a prop." },
2453
- fixable: "code",
2454
- hasSuggestions: true,
2455
- messages: {
2456
- default: "In React 19, 'forwardRef' is no longer necessary. Pass 'ref' as a prop instead.",
2457
- replace: "Replace 'forwardRef' with passing 'ref' as a prop."
2458
- },
2459
- schema: []
2460
- },
2461
- name: RULE_NAME$31,
2462
- create: create$31,
2463
- defaultOptions: []
2464
- });
2465
- function create$31(context) {
2466
- if (!context.sourceCode.text.includes("forwardRef")) return {};
2467
- const { version } = getSettingsFromContext(context);
2468
- if (compare(version, "19.0.0", "<")) return {};
2469
- return { CallExpression(node) {
2470
- if (!core.isForwardRefCall(context, node)) return;
2471
- const id = core.getFunctionId(node);
2472
- const suggest = couldFix(context, node) ? [{
2473
- fix: buildFix(context, node),
2474
- messageId: "replace"
2475
- }] : [];
2476
- context.report({
2477
- messageId: "default",
2478
- node: id ?? node,
2479
- suggest
2480
- });
2481
- } };
2482
- }
2169
+ };
2483
2170
  /**
2484
- * Determine whether the given CallExpression can be safely auto-fixed by replacing
2485
- * the usage of `forwardRef` with passing `ref` as a prop
2171
+ * Reusable prototype that implements `Pipeable.pipe`.
2486
2172
  *
2487
- * @param context The rule context object
2488
- * @param node The CallExpression node to check
2489
- * @returns True if the call can be auto-fixed, false otherwise
2173
+ * **When to use**
2174
+ *
2175
+ * Use when classes or object prototypes can reuse this value when they need the
2176
+ * standard pipe implementation backed by `pipeArguments`.
2177
+ *
2178
+ * @category prototypes
2179
+ * @since 3.15.0
2490
2180
  */
2491
- function couldFix(context, node) {
2492
- const { importSource } = getSettingsFromContext(context);
2493
- const initialScope = context.sourceCode.getScope(node);
2494
- const callee = Extract.unwrap(node.callee);
2495
- switch (callee.type) {
2496
- case AST_NODE_TYPES.Identifier: return isInitializedFromReact(callee.name, initialScope, importSource);
2497
- case AST_NODE_TYPES.MemberExpression: return Check.isIdentifier(callee.object) && isInitializedFromReact(callee.object.name, initialScope, importSource);
2498
- default: return false;
2499
- }
2500
- }
2181
+ const Prototype = { pipe() {
2182
+ return pipeArguments(this, arguments);
2183
+ } };
2501
2184
  /**
2502
- * Generates the fix for the `forwardRef` call
2503
- * @param context The rule context
2504
- * @param node The `forwardRef` call expression
2505
- * @returns A fixer function that applies the changes
2185
+ * Provides a base constructor whose instances implement the standard `Pipeable.pipe`
2186
+ * method.
2187
+ *
2188
+ * **When to use**
2189
+ *
2190
+ * Use when you need to define a class that supports Effect-style method
2191
+ * chaining through `.pipe(...)`.
2192
+ *
2193
+ * @category constructors
2194
+ * @since 3.15.0
2506
2195
  */
2507
- function buildFix(context, node) {
2508
- return (fixer) => {
2509
- const [componentNode] = node.arguments;
2510
- if (componentNode == null || !Check.isFunction(componentNode)) return [];
2511
- return [
2512
- fixer.removeRange([node.range[0], componentNode.range[0]]),
2513
- fixer.removeRange([componentNode.range[1], node.range[1]]),
2514
- ...buildFixForComponentProps(context, fixer, componentNode, node.typeArguments?.params ?? [])
2515
- ];
2516
- };
2517
- }
2196
+ const Class = (function() {
2197
+ function PipeableBase() {}
2198
+ PipeableBase.prototype = Prototype;
2199
+ return PipeableBase;
2200
+ })();
2518
2201
  /**
2519
- * Generates fixes for the component's props and ref arguments
2520
- * @param context The rule context
2521
- * @param fixer The rule fixer
2522
- * @param node The function component node
2523
- * @param typeArguments The type arguments from the `forwardRef` call
2524
- * @returns An array of fixes for the component's signature
2202
+ * Provides small helpers for defining and reusing TypeScript functions.
2203
+ *
2204
+ * The main helpers are `pipe` and `flow` for left-to-right composition and
2205
+ * `dual` for APIs that support both direct and pipe-friendly call styles. The
2206
+ * module also contains small identity, constant, tuple, type-level, and
2207
+ * memoization helpers used across the library.
2208
+ *
2209
+ * @since 2.0.0
2525
2210
  */
2526
- function buildFixForComponentProps(context, fixer, node, typeArguments) {
2527
- const getText = (node) => context.sourceCode.getText(node);
2528
- const [arg0, arg1] = node.params;
2529
- const [typeArg0, typeArg1] = typeArguments;
2530
- if (arg0 == null) {
2531
- const openParen = context.sourceCode.getFirstToken(node, { filter: (t) => t.value === "(" });
2532
- if (openParen == null) return [];
2533
- if (typeArg0 == null || typeArg1 == null) return [];
2534
- const typeArg0Text = getText(typeArg0);
2535
- const typeArg1Text = getText(typeArg1);
2536
- return [fixer.insertTextAfter(openParen, `{ ref }: ${typeArg1Text} & { ref?: React.RefObject<${typeArg0Text} | null> }`)];
2537
- }
2538
- const fixedArg0Text = match(arg0).with({ type: AST_NODE_TYPES.Identifier }, (n) => `...${n.name}`).with({ type: AST_NODE_TYPES.ObjectPattern }, (n) => n.properties.map(getText).join(", ")).otherwise(() => null);
2539
- const fixedArg1Text = match(arg1).with(P.nullish, () => "ref").with({
2540
- type: AST_NODE_TYPES.Identifier,
2541
- name: "ref"
2542
- }, () => "ref").with({
2543
- type: AST_NODE_TYPES.Identifier,
2544
- name: P.string
2545
- }, (n) => `ref: ${n.name}`).otherwise(() => null);
2546
- if (fixedArg0Text == null || fixedArg1Text == null) return [];
2547
- if (typeArg0 == null || typeArg1 == null) return [fixer.replaceText(arg0, [
2548
- "{",
2549
- fixedArg1Text + ",",
2550
- fixedArg0Text,
2551
- "}"
2552
- ].join(" ")), ...arg1 == null ? [] : [fixer.remove(arg1), fixer.removeRange([arg0.range[1], arg1.range[0]])]];
2553
- const typeArg0Text = getText(typeArg0);
2554
- const typeArg1Text = getText(typeArg1);
2555
- return [fixer.replaceText(arg0, [
2556
- "{",
2557
- fixedArg1Text + ",",
2558
- fixedArg0Text,
2559
- "}:",
2560
- typeArg1Text,
2561
- "&",
2562
- "{",
2563
- `ref?:`,
2564
- `React.RefObject<${typeArg0Text} | null>`,
2565
- "}"
2566
- ].join(" ")), ...arg1 == null ? [] : [fixer.remove(arg1), fixer.removeRange([arg0.range[1], arg1.range[0]])]];
2567
- }
2568
-
2569
- //#endregion
2570
- //#region src/utils/create-implicit-prop-listener.ts
2571
- /**
2572
- * Creates a listener that detects JSX spread attributes implicitly passing a given prop
2573
- * (ex: 'children', 'key', 'ref') to a component.
2574
- *
2575
- * For each union constituent of the spread argument's type, the prop is reported unless:
2576
- * 1. The prop symbol's fully qualified name is allowed (pass-through of React internally defined props)
2577
- * 2. The fully qualified name of the prop's type symbol (or its alias) is allowed (React type aliases)
2578
- *
2579
- * @param context The ESLint rule context
2580
- * @param options The prop name, the allow-list predicates (receive lowercased fully qualified names), and the report callback
2581
- * @param options.name The name of the prop to detect
2582
- * @param options.isAllowedProp A predicate that receives the prop symbol's lowercased fully qualified name and returns `true` if it is allowed
2583
- * @param options.isAllowedType A predicate that receives the prop's type symbol's lowercased fully qualified name and returns `true` if it is allowed
2584
- * @param options.onImplicitProp A callback invoked with the spread attribute node when an implicit prop is detected
2585
- * @returns A rule listener reporting on JSX spread attributes
2586
- */
2587
- function createImplicitPropListener(context, options) {
2588
- const { name, isAllowedProp, isAllowedType, onImplicitProp } = options;
2589
- const services = ESLintUtils.getParserServices(context, false);
2590
- const checker = services.program.getTypeChecker();
2591
- const getFqn = (symbol) => core.getFullyQualifiedNameEx(checker, symbol).toLowerCase();
2592
- return { JSXSpreadAttribute(node) {
2593
- for (const type of unionConstituents(getConstrainedTypeAtLocation(services, node.argument))) {
2594
- const prop = type.getProperty(name);
2595
- if (prop == null) continue;
2596
- if (isAllowedProp(getFqn(prop))) continue;
2597
- const propType = checker.getTypeOfSymbol(prop);
2598
- const propTypeSymbol = propType.aliasSymbol ?? propType.symbol;
2599
- if (propTypeSymbol != null && isAllowedType(getFqn(propTypeSymbol))) continue;
2600
- onImplicitProp(node);
2601
- }
2602
- } };
2603
- }
2604
-
2605
- //#endregion
2606
- //#region src/rules/no-implicit-children/no-implicit-children.ts
2607
- const RULE_NAME$30 = "no-implicit-children";
2608
- const RE_REACT_CHILDREN_TYPE = /react\.(reactnode|reactelement|reactportal)$/i;
2609
- var no_implicit_children_default = createRule({
2610
- meta: {
2611
- type: "problem",
2612
- docs: { description: "Prevents implicitly passing the 'children' prop to components." },
2613
- messages: { default: "This spread attribute implicitly passes the 'children' prop to a component, this could lead to unexpected behavior. If you intend to pass the 'children' prop, use 'children={value}'." },
2614
- schema: []
2615
- },
2616
- name: RULE_NAME$30,
2617
- create: create$30,
2618
- defaultOptions: []
2619
- });
2620
- function create$30(context) {
2621
- return createImplicitPropListener(context, {
2622
- name: "children",
2623
- isAllowedProp: (fqn) => fqn.endsWith("attributes.children") || fqn.endsWith("propswithchildren.children"),
2624
- isAllowedType: (fqn) => RE_REACT_CHILDREN_TYPE.test(fqn) || fqn === "jsx.element",
2625
- onImplicitProp(node) {
2626
- context.report({
2627
- messageId: "default",
2628
- node
2629
- });
2630
- }
2631
- });
2632
- }
2633
-
2634
- //#endregion
2635
- //#region src/rules/no-implicit-key/no-implicit-key.ts
2636
- const RULE_NAME$29 = "no-implicit-key";
2637
- var no_implicit_key_default = createRule({
2638
- meta: {
2639
- type: "problem",
2640
- docs: { description: "Prevents implicitly passing the 'key' prop to components." },
2641
- messages: { default: "This spread attribute implicitly passes the 'key' prop to a component, this could lead to unexpected behavior. If you intend to pass the 'key' prop, use 'key={value}'." },
2642
- schema: []
2643
- },
2644
- name: RULE_NAME$29,
2645
- create: create$29,
2646
- defaultOptions: []
2647
- });
2648
- function create$29(context) {
2649
- return createImplicitPropListener(context, {
2650
- name: "key",
2651
- isAllowedProp: (fqn) => fqn.endsWith("react.attributes.key"),
2652
- isAllowedType: (fqn) => fqn.endsWith("react.key"),
2653
- onImplicitProp(node) {
2654
- context.report({
2655
- messageId: "default",
2656
- node
2657
- });
2658
- }
2659
- });
2660
- }
2661
-
2662
- //#endregion
2663
- //#region src/rules/no-implicit-ref/no-implicit-ref.ts
2664
- const RULE_NAME$28 = "no-implicit-ref";
2665
- const RE_REACT_REF_TYPE = /react\.(ref|legacyref|refcallback|refobject)$/i;
2666
- var no_implicit_ref_default = createRule({
2667
- meta: {
2668
- type: "problem",
2669
- docs: { description: "Prevents implicitly passing the 'ref' prop to components." },
2670
- messages: { default: "This spread attribute implicitly passes the 'ref' prop to a component, this could lead to unexpected behavior. If you intend to pass the 'ref' prop, use 'ref={value}'." },
2671
- schema: []
2672
- },
2673
- name: RULE_NAME$28,
2674
- create: create$28,
2675
- defaultOptions: []
2676
- });
2677
- function create$28(context) {
2678
- return createImplicitPropListener(context, {
2679
- name: "ref",
2680
- isAllowedProp: (fqn) => fqn.endsWith("attributes.ref"),
2681
- isAllowedType: (fqn) => RE_REACT_REF_TYPE.test(fqn),
2682
- onImplicitProp(node) {
2683
- context.report({
2684
- messageId: "default",
2685
- node
2686
- });
2687
- }
2688
- });
2689
- }
2690
-
2691
- //#endregion
2692
- //#region ../../.pkgs/eff/dist/index.js
2693
- function not(predicate) {
2694
- return (data) => !predicate(data);
2695
- }
2696
2211
  /**
2697
- * Applies a `pipe` method's variadic arguments to an initial value from left
2698
- * to right.
2212
+ * Creates a function that can be called in data-first style or data-last
2213
+ * (`pipe`-friendly) style.
2699
2214
  *
2700
2215
  * **When to use**
2701
2216
  *
2702
- * Use to implement a custom `.pipe(...)` method from JavaScript's `arguments`
2703
- * object.
2217
+ * Use to expose one implementation through both direct and `pipe`-friendly
2218
+ * call styles.
2704
2219
  *
2705
2220
  * **Details**
2706
2221
  *
2707
- * This helper is intended for implementing `Pipeable.pipe` methods that
2708
- * receive JavaScript's `arguments` object. With no functions it returns the
2709
- * original value; otherwise it feeds each result into the next function.
2222
+ * Pass either the arity of the uncurried function or a predicate that decides
2223
+ * whether the current call is data-first. Arity is the common case. Use a
2224
+ * predicate when optional arguments make arity ambiguous.
2710
2225
  *
2711
- * **Example** (Implementing a pipe method)
2226
+ * **Example** (Selecting data-first or data-last style by arity)
2712
2227
  *
2713
2228
  * ```ts
2714
- * import { Pipeable } from "effect"
2715
- *
2716
- * class NumberBox {
2717
- * constructor(readonly value: number) {}
2229
+ * import { Function, pipe } from "effect"
2718
2230
  *
2719
- * pipe(..._fns: ReadonlyArray<(value: number) => number>): number {
2720
- * return Pipeable.pipeArguments(this.value, arguments) as number
2721
- * }
2722
- * }
2231
+ * const sum = Function.dual<
2232
+ * (that: number) => (self: number) => number,
2233
+ * (self: number, that: number) => number
2234
+ * >(2, (self, that) => self + that)
2723
2235
  *
2724
- * const result = new NumberBox(5).pipe(
2725
- * (n) => n + 2,
2726
- * (n) => n * 3
2727
- * )
2728
- * console.log(result) // 21
2236
+ * console.log(sum(2, 3)) // 5
2237
+ * console.log(pipe(2, sum(3))) // 5
2729
2238
  * ```
2730
2239
  *
2731
- * @category combinators
2732
- * @since 2.0.0
2733
- */
2734
- const pipeArguments = (self, args) => {
2735
- switch (args.length) {
2736
- case 0: return self;
2737
- case 1: return args[0](self);
2738
- case 2: return args[1](args[0](self));
2739
- case 3: return args[2](args[1](args[0](self)));
2740
- case 4: return args[3](args[2](args[1](args[0](self))));
2741
- case 5: return args[4](args[3](args[2](args[1](args[0](self)))));
2742
- case 6: return args[5](args[4](args[3](args[2](args[1](args[0](self))))));
2743
- case 7: return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))));
2744
- case 8: return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))));
2745
- case 9: return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))));
2746
- default: {
2747
- let ret = self;
2748
- for (let i = 0, len = args.length; i < len; i++) ret = args[i](ret);
2749
- return ret;
2750
- }
2751
- }
2752
- };
2753
- /**
2754
- * Reusable prototype that implements `Pipeable.pipe`.
2240
+ * **Example** (Defining overloads with call signatures)
2755
2241
  *
2756
- * **When to use**
2242
+ * ```ts
2243
+ * import { Function, pipe } from "effect"
2757
2244
  *
2758
- * Use when classes or object prototypes can reuse this value when they need the
2759
- * standard pipe implementation backed by `pipeArguments`.
2245
+ * const sum: {
2246
+ * (that: number): (self: number) => number
2247
+ * (self: number, that: number): number
2248
+ * } = Function.dual(2, (self: number, that: number): number => self + that)
2760
2249
  *
2761
- * @category prototypes
2762
- * @since 3.15.0
2763
- */
2764
- const Prototype = { pipe() {
2765
- return pipeArguments(this, arguments);
2766
- } };
2767
- /**
2768
- * Provides a base constructor whose instances implement the standard `Pipeable.pipe`
2769
- * method.
2250
+ * console.log(sum(2, 3)) // 5
2251
+ * console.log(pipe(2, sum(3))) // 5
2252
+ * ```
2770
2253
  *
2771
- * **When to use**
2772
- *
2773
- * Use when you need to define a class that supports Effect-style method
2774
- * chaining through `.pipe(...)`.
2775
- *
2776
- * @category constructors
2777
- * @since 3.15.0
2778
- */
2779
- const Class = (function() {
2780
- function PipeableBase() {}
2781
- PipeableBase.prototype = Prototype;
2782
- return PipeableBase;
2783
- })();
2784
- /**
2785
- * Provides small helpers for defining and reusing TypeScript functions.
2786
- *
2787
- * The main helpers are `pipe` and `flow` for left-to-right composition and
2788
- * `dual` for APIs that support both direct and pipe-friendly call styles. The
2789
- * module also contains small identity, constant, tuple, type-level, and
2790
- * memoization helpers used across the library.
2791
- *
2792
- * @since 2.0.0
2793
- */
2794
- /**
2795
- * Creates a function that can be called in data-first style or data-last
2796
- * (`pipe`-friendly) style.
2797
- *
2798
- * **When to use**
2799
- *
2800
- * Use to expose one implementation through both direct and `pipe`-friendly
2801
- * call styles.
2802
- *
2803
- * **Details**
2804
- *
2805
- * Pass either the arity of the uncurried function or a predicate that decides
2806
- * whether the current call is data-first. Arity is the common case. Use a
2807
- * predicate when optional arguments make arity ambiguous.
2808
- *
2809
- * **Example** (Selecting data-first or data-last style by arity)
2810
- *
2811
- * ```ts
2812
- * import { Function, pipe } from "effect"
2813
- *
2814
- * const sum = Function.dual<
2815
- * (that: number) => (self: number) => number,
2816
- * (self: number, that: number) => number
2817
- * >(2, (self, that) => self + that)
2818
- *
2819
- * console.log(sum(2, 3)) // 5
2820
- * console.log(pipe(2, sum(3))) // 5
2821
- * ```
2822
- *
2823
- * **Example** (Defining overloads with call signatures)
2824
- *
2825
- * ```ts
2826
- * import { Function, pipe } from "effect"
2827
- *
2828
- * const sum: {
2829
- * (that: number): (self: number) => number
2830
- * (self: number, that: number): number
2831
- * } = Function.dual(2, (self: number, that: number): number => self + that)
2832
- *
2833
- * console.log(sum(2, 3)) // 5
2834
- * console.log(pipe(2, sum(3))) // 5
2835
- * ```
2836
- *
2837
- * **Example** (Selecting data-first or data-last style with a predicate)
2254
+ * **Example** (Selecting data-first or data-last style with a predicate)
2838
2255
  *
2839
2256
  * ```ts
2840
2257
  * import { Function, pipe } from "effect"
@@ -3137,68 +2554,664 @@ function flow(ab, bc, cd, de, ef, fg, gh, hi, ij) {
3137
2554
  * console.log(typeof buildUser) // "function"
3138
2555
  * ```
3139
2556
  *
3140
- * @category utility types
3141
- * @since 2.0.0
2557
+ * @category utility types
2558
+ * @since 2.0.0
2559
+ */
2560
+ const hole = cast(absurd);
2561
+ function getOrInsertComputed(map, key, callback) {
2562
+ if (map.has(key)) return map.get(key);
2563
+ const value = callback(key);
2564
+ map.set(key, value);
2565
+ return value;
2566
+ }
2567
+ /**
2568
+ * Drops the longest prefix of elements from an array that satisfy the given predicate.
2569
+ *
2570
+ * Supports both data-first and data-last (`pipe`-friendly) call styles.
2571
+ *
2572
+ * @param pred - The predicate to test each element with.
2573
+ * @returns A new array without the matching prefix.
2574
+ * @example
2575
+ * ```ts
2576
+ * import * as assert from "node:assert"
2577
+ * import { dropWhile, pipe } from "@local/eff"
2578
+ *
2579
+ * // data-first
2580
+ * assert.deepStrictEqual(dropWhile([1, 2, 3, 2, 1], (n: number) => n < 3), [3, 2, 1])
2581
+ *
2582
+ * // data-last
2583
+ * assert.deepStrictEqual(pipe([1, 2, 3, 2, 1], dropWhile((n: number) => n < 3)), [3, 2, 1])
2584
+ * ```
2585
+ * @category array
2586
+ */
2587
+ const dropWhile = dual(2, (xs, pred) => {
2588
+ const len = xs.length;
2589
+ let idx = 0;
2590
+ while (idx < len && pred(xs[idx])) idx++;
2591
+ return xs.slice(idx);
2592
+ });
2593
+ /**
2594
+ * Takes the longest prefix of elements from an array that satisfy the given predicate.
2595
+ *
2596
+ * Supports both data-first and data-last (`pipe`-friendly) call styles.
2597
+ *
2598
+ * @param pred - The predicate to test each element with.
2599
+ * @returns A new array containing only the matching prefix.
2600
+ * @example
2601
+ * ```ts
2602
+ * import * as assert from "node:assert"
2603
+ * import { pipe, takeWhile } from "@local/eff"
2604
+ *
2605
+ * // data-first
2606
+ * assert.deepStrictEqual(takeWhile([1, 2, 3, 2, 1], (n: number) => n < 3), [1, 2])
2607
+ *
2608
+ * // data-last
2609
+ * assert.deepStrictEqual(pipe([1, 2, 3, 2, 1], takeWhile((n: number) => n < 3)), [1, 2])
2610
+ * ```
2611
+ * @category array
2612
+ */
2613
+ const takeWhile = dual(2, (xs, pred) => {
2614
+ const len = xs.length;
2615
+ let idx = 0;
2616
+ while (idx < len && pred(xs[idx])) idx++;
2617
+ return xs.slice(0, idx);
2618
+ });
2619
+
2620
+ //#endregion
2621
+ //#region src/rules/no-class-component/no-class-component.ts
2622
+ const RULE_NAME$40 = "no-class-component";
2623
+ var no_class_component_default = createRule({
2624
+ meta: {
2625
+ type: "suggestion",
2626
+ docs: { description: "Disallows class components except for error boundaries." },
2627
+ messages: { default: "Avoid using class components. Use function components instead." },
2628
+ schema: []
2629
+ },
2630
+ name: RULE_NAME$40,
2631
+ create: create$40,
2632
+ defaultOptions: []
2633
+ });
2634
+ function create$40(context) {
2635
+ if (!context.sourceCode.text.includes("Component")) return {};
2636
+ const { api, visitor } = core.getClassComponentCollector(context);
2637
+ return merge(visitor, { "Program:exit"(program) {
2638
+ for (const { id, name = "anonymous", node: component } of api.getAllComponents(program)) {
2639
+ if (component.body.body.some(or(core.isComponentDidCatch, core.isGetDerivedStateFromError))) continue;
2640
+ const classToken = context.sourceCode.getFirstToken(component, { filter: (token) => token.value === "class" });
2641
+ context.report({
2642
+ data: { name },
2643
+ loc: (id ?? classToken ?? component).loc,
2644
+ messageId: "default",
2645
+ node: component
2646
+ });
2647
+ }
2648
+ } });
2649
+ }
2650
+
2651
+ //#endregion
2652
+ //#region src/rules/no-clone-element/no-clone-element.ts
2653
+ const RULE_NAME$39 = "no-clone-element";
2654
+ var no_clone_element_default = createRule({
2655
+ meta: {
2656
+ type: "suggestion",
2657
+ docs: { description: "Disallows 'cloneElement'." },
2658
+ messages: { default: "Using 'cloneElement' is uncommon and can lead to fragile code. Use alternatives instead." },
2659
+ schema: []
2660
+ },
2661
+ name: RULE_NAME$39,
2662
+ create: create$39,
2663
+ defaultOptions: []
2664
+ });
2665
+ function create$39(context) {
2666
+ return { CallExpression(node) {
2667
+ if (core.isCloneElementCall(context, node)) context.report({
2668
+ messageId: "default",
2669
+ node
2670
+ });
2671
+ } };
2672
+ }
2673
+
2674
+ //#endregion
2675
+ //#region src/rules/no-component-will-mount/no-component-will-mount.ts
2676
+ const RULE_NAME$38 = "no-component-will-mount";
2677
+ var no_component_will_mount_default = createRule({
2678
+ meta: {
2679
+ type: "problem",
2680
+ docs: { description: "Replaces usage of 'componentWillMount' with 'UNSAFE_componentWillMount'." },
2681
+ fixable: "code",
2682
+ messages: { default: "[Deprecated] Use 'UNSAFE_componentWillMount' instead." },
2683
+ schema: []
2684
+ },
2685
+ name: RULE_NAME$38,
2686
+ create: create$38,
2687
+ defaultOptions: []
2688
+ });
2689
+ function create$38(context) {
2690
+ if (!context.sourceCode.text.includes("componentWillMount")) return {};
2691
+ const { api, visitor } = core.getClassComponentCollector(context);
2692
+ return merge(visitor, { "Program:exit"(program) {
2693
+ for (const { node: component } of api.getAllComponents(program)) {
2694
+ const { body } = component.body;
2695
+ for (const member of body) if (core.isComponentWillMount(member)) context.report({
2696
+ fix(fixer) {
2697
+ if (!("key" in member)) return null;
2698
+ return fixer.replaceText(member.key, "UNSAFE_componentWillMount");
2699
+ },
2700
+ messageId: "default",
2701
+ node: member
2702
+ });
2703
+ }
2704
+ } });
2705
+ }
2706
+
2707
+ //#endregion
2708
+ //#region src/rules/no-component-will-receive-props/no-component-will-receive-props.ts
2709
+ const RULE_NAME$37 = "no-component-will-receive-props";
2710
+ var no_component_will_receive_props_default = createRule({
2711
+ meta: {
2712
+ type: "problem",
2713
+ docs: { description: "Replaces usage of 'componentWillReceiveProps' with 'UNSAFE_componentWillReceiveProps'." },
2714
+ fixable: "code",
2715
+ messages: { default: "[Deprecated] Use 'UNSAFE_componentWillReceiveProps' instead." },
2716
+ schema: []
2717
+ },
2718
+ name: RULE_NAME$37,
2719
+ create: create$37,
2720
+ defaultOptions: []
2721
+ });
2722
+ function create$37(context) {
2723
+ if (!context.sourceCode.text.includes("componentWillReceiveProps")) return {};
2724
+ const { api, visitor } = core.getClassComponentCollector(context);
2725
+ return merge(visitor, { "Program:exit"(program) {
2726
+ for (const { node: component } of api.getAllComponents(program)) {
2727
+ const { body } = component.body;
2728
+ for (const member of body) if (core.isComponentWillReceiveProps(member)) context.report({
2729
+ fix(fixer) {
2730
+ if (!("key" in member)) return null;
2731
+ return fixer.replaceText(member.key, "UNSAFE_componentWillReceiveProps");
2732
+ },
2733
+ messageId: "default",
2734
+ node: member
2735
+ });
2736
+ }
2737
+ } });
2738
+ }
2739
+
2740
+ //#endregion
2741
+ //#region src/rules/no-component-will-update/no-component-will-update.ts
2742
+ const RULE_NAME$36 = "no-component-will-update";
2743
+ var no_component_will_update_default = createRule({
2744
+ meta: {
2745
+ type: "problem",
2746
+ docs: { description: "Replaces usage of 'componentWillUpdate' with 'UNSAFE_componentWillUpdate'." },
2747
+ fixable: "code",
2748
+ messages: { default: "[Deprecated] Use 'UNSAFE_componentWillUpdate' instead." },
2749
+ schema: []
2750
+ },
2751
+ name: RULE_NAME$36,
2752
+ create: create$36,
2753
+ defaultOptions: []
2754
+ });
2755
+ function create$36(context) {
2756
+ if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
2757
+ const { api, visitor } = core.getClassComponentCollector(context);
2758
+ return merge(visitor, { "Program:exit"(program) {
2759
+ for (const { node: component } of api.getAllComponents(program)) {
2760
+ const { body } = component.body;
2761
+ for (const member of body) if (core.isComponentWillUpdate(member)) context.report({
2762
+ fix(fixer) {
2763
+ if (!("key" in member)) return null;
2764
+ return fixer.replaceText(member.key, "UNSAFE_componentWillUpdate");
2765
+ },
2766
+ messageId: "default",
2767
+ node: member
2768
+ });
2769
+ }
2770
+ } });
2771
+ }
2772
+
2773
+ //#endregion
2774
+ //#region src/rules/no-context-provider/no-context-provider.ts
2775
+ const RULE_NAME$35 = "no-context-provider";
2776
+ var no_context_provider_default = createRule({
2777
+ meta: {
2778
+ type: "suggestion",
2779
+ docs: { description: "Replaces usage of '<Context.Provider>' with '<Context>'." },
2780
+ fixable: "code",
2781
+ hasSuggestions: true,
2782
+ messages: {
2783
+ default: "In React 19, you can render '<Context>' as a provider instead of '<Context.Provider>'.",
2784
+ replace: "Replace '<Context.Provider>' with '<Context>'."
2785
+ },
2786
+ schema: []
2787
+ },
2788
+ name: RULE_NAME$35,
2789
+ create: create$35,
2790
+ defaultOptions: []
2791
+ });
2792
+ function create$35(context) {
2793
+ if (!context.sourceCode.text.includes("Provider")) return {};
2794
+ const { version } = getSettingsFromContext(context);
2795
+ if (compare(version, "19.0.0", "<")) return {};
2796
+ return { JSXElement(node) {
2797
+ const parts = getElementFullType(node).split(".");
2798
+ const selfName = parts.pop();
2799
+ const contextFullName = parts.join(".");
2800
+ const contextSelfName = parts.pop();
2801
+ if (selfName !== "Provider") return;
2802
+ if (contextSelfName == null || !contextSelfName.endsWith("Context")) return;
2803
+ context.report({
2804
+ messageId: "default",
2805
+ node,
2806
+ suggest: [{
2807
+ fix(fixer) {
2808
+ if (!core.isFunctionComponentNameLoose(contextSelfName)) return null;
2809
+ const openingElement = node.openingElement;
2810
+ const closingElement = node.closingElement;
2811
+ if (closingElement == null) return fixer.replaceText(openingElement.name, contextFullName);
2812
+ return [fixer.replaceText(openingElement.name, contextFullName), fixer.replaceText(closingElement.name, contextFullName)];
2813
+ },
2814
+ messageId: "replace"
2815
+ }]
2816
+ });
2817
+ } };
2818
+ }
2819
+
2820
+ //#endregion
2821
+ //#region src/rules/no-create-ref/no-create-ref.ts
2822
+ const RULE_NAME$34 = "no-create-ref";
2823
+ var no_create_ref_default = createRule({
2824
+ meta: {
2825
+ type: "suggestion",
2826
+ docs: { description: "Disallows 'createRef' in function components and Hooks." },
2827
+ messages: { default: "[Deprecated] Use 'useRef' instead." },
2828
+ schema: []
2829
+ },
2830
+ name: RULE_NAME$34,
2831
+ create: create$34,
2832
+ defaultOptions: []
2833
+ });
2834
+ function create$34(context) {
2835
+ if (!context.sourceCode.text.includes("createRef")) return {};
2836
+ const fc = core.getFunctionComponentCollector(context);
2837
+ const hc = core.getHookCollector(context);
2838
+ const createRefCalls = /* @__PURE__ */ new Set();
2839
+ return merge(fc.visitor, hc.visitor, {
2840
+ CallExpression(node) {
2841
+ if (!core.isCreateRefCall(context, node)) return;
2842
+ createRefCalls.add(node);
2843
+ },
2844
+ "Program:exit"(node) {
2845
+ const comps = fc.api.getAllComponents(node);
2846
+ const hooks = hc.api.getAllHooks(node);
2847
+ const funcs = [...comps, ...hooks];
2848
+ for (const call of createRefCalls) {
2849
+ if (Traverse.findParent(call, (n) => funcs.some((f) => f.node === n)) == null) continue;
2850
+ context.report({
2851
+ messageId: "default",
2852
+ node: call
2853
+ });
2854
+ }
2855
+ }
2856
+ });
2857
+ }
2858
+
2859
+ //#endregion
2860
+ //#region src/rules/no-direct-mutation-state/no-direct-mutation-state.ts
2861
+ const RULE_NAME$33 = "no-direct-mutation-state";
2862
+ var no_direct_mutation_state_default = createRule({
2863
+ meta: {
2864
+ type: "problem",
2865
+ docs: { description: "Disallows direct mutation of 'this.state'." },
2866
+ messages: { default: "Do not mutate state directly. Use 'setState()' instead." },
2867
+ schema: []
2868
+ },
2869
+ name: RULE_NAME$33,
2870
+ create: create$33,
2871
+ defaultOptions: []
2872
+ });
2873
+ function isConstructorFunction(node) {
2874
+ return Check.isOneOf([AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.FunctionExpression])(node) && Check.isPropertyOrMethod(node.parent) && Check.isIdentifier(node.parent.key, "constructor");
2875
+ }
2876
+ function isAssignmentToThisState(node) {
2877
+ const { left } = node;
2878
+ let current = Extract.unwrap(left);
2879
+ while (current.type === AST_NODE_TYPES.MemberExpression) {
2880
+ const object = Extract.unwrap(current.object);
2881
+ const property = current.property;
2882
+ if (object.type === AST_NODE_TYPES.ThisExpression && Check.isIdentifier(property, "state")) return true;
2883
+ current = object;
2884
+ }
2885
+ return false;
2886
+ }
2887
+ function create$33(context) {
2888
+ return { AssignmentExpression(node) {
2889
+ if (!isAssignmentToThisState(node)) return;
2890
+ const fact = Traverse.findParent(node, Check.isClass);
2891
+ if (fact == null) return;
2892
+ if (core.isClassComponent(fact) && context.sourceCode.getScope(node).block !== Traverse.findParent(node, isConstructorFunction)) context.report({
2893
+ messageId: "default",
2894
+ node
2895
+ });
2896
+ } };
2897
+ }
2898
+
2899
+ //#endregion
2900
+ //#region src/rules/no-duplicate-key/no-duplicate-key.ts
2901
+ const RULE_NAME$32 = "no-duplicate-key";
2902
+ var no_duplicate_key_default = createRule({
2903
+ meta: {
2904
+ type: "problem",
2905
+ docs: { description: "Prevents duplicate 'key' props on sibling elements when rendering lists." },
2906
+ messages: { default: "The 'key' prop must be unique to its sibling elements." },
2907
+ schema: []
2908
+ },
2909
+ name: RULE_NAME$32,
2910
+ create: create$32,
2911
+ defaultOptions: []
2912
+ });
2913
+ function create$32(context) {
2914
+ if (!context.sourceCode.text.includes("key=")) return {};
2915
+ const keyedEntries = /* @__PURE__ */ new Map();
2916
+ function isKeyValueEqual(a, b) {
2917
+ const aValue = a.value;
2918
+ const bValue = b.value;
2919
+ if (aValue == null || bValue == null) return false;
2920
+ return Compare.isEqual(aValue, bValue);
2921
+ }
2922
+ return {
2923
+ "JSXAttribute[name.name='key']"(node) {
2924
+ const jsxElement = node.parent.parent;
2925
+ switch (jsxElement.parent.type) {
2926
+ case AST_NODE_TYPES.ArrayExpression:
2927
+ case AST_NODE_TYPES.JSXElement:
2928
+ case AST_NODE_TYPES.JSXFragment: {
2929
+ const root = jsxElement.parent;
2930
+ const prevKeys = keyedEntries.get(root)?.keys ?? [];
2931
+ keyedEntries.set(root, {
2932
+ hasDuplicate: prevKeys.some((prevKey) => isKeyValueEqual(prevKey, node)),
2933
+ keys: [...prevKeys, node],
2934
+ root: jsxElement.parent
2935
+ });
2936
+ break;
2937
+ }
2938
+ default: {
2939
+ const call = Traverse.findParent(jsxElement, (n) => {
2940
+ if (n.type !== AST_NODE_TYPES.CallExpression) return false;
2941
+ const callee = Extract.unwrap(n.callee);
2942
+ if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;
2943
+ return Check.isIdentifier(callee.property, "map");
2944
+ });
2945
+ const iter = Traverse.findParent(jsxElement, Check.isFunction, (n) => n === call);
2946
+ if (!Check.isFunction(iter)) return;
2947
+ const arg0 = call?.arguments[0];
2948
+ if (call == null || arg0 == null) return;
2949
+ if (Extract.unwrap(arg0) !== iter) return;
2950
+ keyedEntries.set(call, {
2951
+ hasDuplicate: node.value?.type === AST_NODE_TYPES.Literal,
2952
+ keys: [node],
2953
+ root: call
2954
+ });
2955
+ }
2956
+ }
2957
+ },
2958
+ "Program:exit"() {
2959
+ for (const { hasDuplicate, keys } of keyedEntries.values()) {
2960
+ if (!hasDuplicate) continue;
2961
+ for (const key of keys) context.report({
2962
+ data: { value: context.sourceCode.getText(key) },
2963
+ messageId: "default",
2964
+ node: key
2965
+ });
2966
+ }
2967
+ }
2968
+ };
2969
+ }
2970
+
2971
+ //#endregion
2972
+ //#region src/rules/no-forward-ref/no-forward-ref.ts
2973
+ const RULE_NAME$31 = "no-forward-ref";
2974
+ var no_forward_ref_default = createRule({
2975
+ meta: {
2976
+ type: "suggestion",
2977
+ docs: { description: "Replaces usage of 'forwardRef' with passing 'ref' as a prop." },
2978
+ fixable: "code",
2979
+ hasSuggestions: true,
2980
+ messages: {
2981
+ default: "In React 19, 'forwardRef' is no longer necessary. Pass 'ref' as a prop instead.",
2982
+ replace: "Replace 'forwardRef' with passing 'ref' as a prop."
2983
+ },
2984
+ schema: []
2985
+ },
2986
+ name: RULE_NAME$31,
2987
+ create: create$31,
2988
+ defaultOptions: []
2989
+ });
2990
+ function create$31(context) {
2991
+ if (!context.sourceCode.text.includes("forwardRef")) return {};
2992
+ const { version } = getSettingsFromContext(context);
2993
+ if (compare(version, "19.0.0", "<")) return {};
2994
+ return { CallExpression(node) {
2995
+ if (!core.isForwardRefCall(context, node)) return;
2996
+ const id = core.getFunctionId(node);
2997
+ const suggest = couldFix(context, node) ? [{
2998
+ fix: buildFix(context, node),
2999
+ messageId: "replace"
3000
+ }] : [];
3001
+ context.report({
3002
+ messageId: "default",
3003
+ node: id ?? node,
3004
+ suggest
3005
+ });
3006
+ } };
3007
+ }
3008
+ /**
3009
+ * Determine whether the given CallExpression can be safely auto-fixed by replacing
3010
+ * the usage of `forwardRef` with passing `ref` as a prop
3011
+ *
3012
+ * @param context The rule context object
3013
+ * @param node The CallExpression node to check
3014
+ * @returns True if the call can be auto-fixed, false otherwise
3142
3015
  */
3143
- const hole = cast(absurd);
3144
- function getOrInsertComputed(map, key, callback) {
3145
- if (map.has(key)) return map.get(key);
3146
- const value = callback(key);
3147
- map.set(key, value);
3148
- return value;
3016
+ function couldFix(context, node) {
3017
+ const { importSource } = getSettingsFromContext(context);
3018
+ const initialScope = context.sourceCode.getScope(node);
3019
+ const callee = Extract.unwrap(node.callee);
3020
+ switch (callee.type) {
3021
+ case AST_NODE_TYPES.Identifier: return isInitializedFromReact(callee.name, initialScope, importSource);
3022
+ case AST_NODE_TYPES.MemberExpression: return Check.isIdentifier(callee.object) && isInitializedFromReact(callee.object.name, initialScope, importSource);
3023
+ default: return false;
3024
+ }
3149
3025
  }
3150
3026
  /**
3151
- * Drops the longest prefix of elements from an array that satisfy the given predicate.
3152
- *
3153
- * Supports both data-first and data-last (`pipe`-friendly) call styles.
3154
- *
3155
- * @param pred - The predicate to test each element with.
3156
- * @returns A new array without the matching prefix.
3157
- * @example
3158
- * ```ts
3159
- * import * as assert from "node:assert"
3160
- * import { dropWhile, pipe } from "@local/eff"
3161
- *
3162
- * // data-first
3163
- * assert.deepStrictEqual(dropWhile([1, 2, 3, 2, 1], (n: number) => n < 3), [3, 2, 1])
3164
- *
3165
- * // data-last
3166
- * assert.deepStrictEqual(pipe([1, 2, 3, 2, 1], dropWhile((n: number) => n < 3)), [3, 2, 1])
3167
- * ```
3168
- * @category array
3027
+ * Generates the fix for the `forwardRef` call
3028
+ * @param context The rule context
3029
+ * @param node The `forwardRef` call expression
3030
+ * @returns A fixer function that applies the changes
3169
3031
  */
3170
- const dropWhile = dual(2, (xs, pred) => {
3171
- const len = xs.length;
3172
- let idx = 0;
3173
- while (idx < len && pred(xs[idx])) idx++;
3174
- return xs.slice(idx);
3175
- });
3032
+ function buildFix(context, node) {
3033
+ return (fixer) => {
3034
+ const [componentNode] = node.arguments;
3035
+ if (componentNode == null || !Check.isFunction(componentNode)) return [];
3036
+ return [
3037
+ fixer.removeRange([node.range[0], componentNode.range[0]]),
3038
+ fixer.removeRange([componentNode.range[1], node.range[1]]),
3039
+ ...buildFixForComponentProps(context, fixer, componentNode, node.typeArguments?.params ?? [])
3040
+ ];
3041
+ };
3042
+ }
3176
3043
  /**
3177
- * Takes the longest prefix of elements from an array that satisfy the given predicate.
3178
- *
3179
- * Supports both data-first and data-last (`pipe`-friendly) call styles.
3180
- *
3181
- * @param pred - The predicate to test each element with.
3182
- * @returns A new array containing only the matching prefix.
3183
- * @example
3184
- * ```ts
3185
- * import * as assert from "node:assert"
3186
- * import { pipe, takeWhile } from "@local/eff"
3044
+ * Generates fixes for the component's props and ref arguments
3045
+ * @param context The rule context
3046
+ * @param fixer The rule fixer
3047
+ * @param node The function component node
3048
+ * @param typeArguments The type arguments from the `forwardRef` call
3049
+ * @returns An array of fixes for the component's signature
3050
+ */
3051
+ function buildFixForComponentProps(context, fixer, node, typeArguments) {
3052
+ const getText = (node) => context.sourceCode.getText(node);
3053
+ const [arg0, arg1] = node.params;
3054
+ const [typeArg0, typeArg1] = typeArguments;
3055
+ if (arg0 == null) {
3056
+ const openParen = context.sourceCode.getFirstToken(node, { filter: (t) => t.value === "(" });
3057
+ if (openParen == null) return [];
3058
+ if (typeArg0 == null || typeArg1 == null) return [];
3059
+ const typeArg0Text = getText(typeArg0);
3060
+ const typeArg1Text = getText(typeArg1);
3061
+ return [fixer.insertTextAfter(openParen, `{ ref }: ${typeArg1Text} & { ref?: React.RefObject<${typeArg0Text} | null> }`)];
3062
+ }
3063
+ const fixedArg0Text = match(arg0).with({ type: AST_NODE_TYPES.Identifier }, (n) => `...${n.name}`).with({ type: AST_NODE_TYPES.ObjectPattern }, (n) => n.properties.map(getText).join(", ")).otherwise(() => null);
3064
+ const fixedArg1Text = match(arg1).with(P.nullish, () => "ref").with({
3065
+ type: AST_NODE_TYPES.Identifier,
3066
+ name: "ref"
3067
+ }, () => "ref").with({
3068
+ type: AST_NODE_TYPES.Identifier,
3069
+ name: P.string
3070
+ }, (n) => `ref: ${n.name}`).otherwise(() => null);
3071
+ if (fixedArg0Text == null || fixedArg1Text == null) return [];
3072
+ if (typeArg0 == null || typeArg1 == null) return [fixer.replaceText(arg0, [
3073
+ "{",
3074
+ fixedArg1Text + ",",
3075
+ fixedArg0Text,
3076
+ "}"
3077
+ ].join(" ")), ...arg1 == null ? [] : [fixer.remove(arg1), fixer.removeRange([arg0.range[1], arg1.range[0]])]];
3078
+ const typeArg0Text = getText(typeArg0);
3079
+ const typeArg1Text = getText(typeArg1);
3080
+ return [fixer.replaceText(arg0, [
3081
+ "{",
3082
+ fixedArg1Text + ",",
3083
+ fixedArg0Text,
3084
+ "}:",
3085
+ typeArg1Text,
3086
+ "&",
3087
+ "{",
3088
+ `ref?:`,
3089
+ `React.RefObject<${typeArg0Text} | null>`,
3090
+ "}"
3091
+ ].join(" ")), ...arg1 == null ? [] : [fixer.remove(arg1), fixer.removeRange([arg0.range[1], arg1.range[0]])]];
3092
+ }
3093
+
3094
+ //#endregion
3095
+ //#region src/utils/create-implicit-prop-listener.ts
3096
+ /**
3097
+ * Creates a listener that detects JSX spread attributes implicitly passing a given prop
3098
+ * (ex: 'children', 'key', 'ref') to a component.
3187
3099
  *
3188
- * // data-first
3189
- * assert.deepStrictEqual(takeWhile([1, 2, 3, 2, 1], (n: number) => n < 3), [1, 2])
3100
+ * For each union constituent of the spread argument's type, the prop is reported unless:
3101
+ * 1. The prop symbol's fully qualified name is allowed (pass-through of React internally defined props)
3102
+ * 2. The fully qualified name of the prop's type symbol (or its alias) is allowed (React type aliases)
3190
3103
  *
3191
- * // data-last
3192
- * assert.deepStrictEqual(pipe([1, 2, 3, 2, 1], takeWhile((n: number) => n < 3)), [1, 2])
3193
- * ```
3194
- * @category array
3104
+ * @param context The ESLint rule context
3105
+ * @param options The prop name, the allow-list predicates (receive lowercased fully qualified names), and the report callback
3106
+ * @param options.name The name of the prop to detect
3107
+ * @param options.isAllowedProp A predicate that receives the prop symbol's lowercased fully qualified name and returns `true` if it is allowed
3108
+ * @param options.isAllowedType A predicate that receives the prop's type symbol's lowercased fully qualified name and returns `true` if it is allowed
3109
+ * @param options.onImplicitProp A callback invoked with the spread attribute node when an implicit prop is detected
3110
+ * @returns A rule listener reporting on JSX spread attributes
3195
3111
  */
3196
- const takeWhile = dual(2, (xs, pred) => {
3197
- const len = xs.length;
3198
- let idx = 0;
3199
- while (idx < len && pred(xs[idx])) idx++;
3200
- return xs.slice(0, idx);
3112
+ function createImplicitPropListener(context, options) {
3113
+ const { name, isAllowedProp, isAllowedType, onImplicitProp } = options;
3114
+ const services = ESLintUtils.getParserServices(context, false);
3115
+ const checker = services.program.getTypeChecker();
3116
+ const getFqn = (symbol) => core.getFullyQualifiedNameEx(checker, symbol).toLowerCase();
3117
+ return { JSXSpreadAttribute(node) {
3118
+ for (const type of unionConstituents(getConstrainedTypeAtLocation(services, node.argument))) {
3119
+ const prop = type.getProperty(name);
3120
+ if (prop == null) continue;
3121
+ if (isAllowedProp(getFqn(prop))) continue;
3122
+ const propType = checker.getTypeOfSymbol(prop);
3123
+ const propTypeSymbol = propType.aliasSymbol ?? propType.symbol;
3124
+ if (propTypeSymbol != null && isAllowedType(getFqn(propTypeSymbol))) continue;
3125
+ onImplicitProp(node);
3126
+ }
3127
+ } };
3128
+ }
3129
+
3130
+ //#endregion
3131
+ //#region src/rules/no-implicit-children/no-implicit-children.ts
3132
+ const RULE_NAME$30 = "no-implicit-children";
3133
+ const RE_REACT_CHILDREN_TYPE = /react\.(reactnode|reactelement|reactportal)$/i;
3134
+ var no_implicit_children_default = createRule({
3135
+ meta: {
3136
+ type: "problem",
3137
+ docs: { description: "Prevents implicitly passing the 'children' prop to components." },
3138
+ messages: { default: "This spread attribute implicitly passes the 'children' prop to a component, this could lead to unexpected behavior. If you intend to pass the 'children' prop, use 'children={value}'." },
3139
+ schema: []
3140
+ },
3141
+ name: RULE_NAME$30,
3142
+ create: create$30,
3143
+ defaultOptions: []
3144
+ });
3145
+ function create$30(context) {
3146
+ return createImplicitPropListener(context, {
3147
+ name: "children",
3148
+ isAllowedProp: (fqn) => fqn.endsWith("attributes.children") || fqn.endsWith("propswithchildren.children"),
3149
+ isAllowedType: (fqn) => RE_REACT_CHILDREN_TYPE.test(fqn) || fqn === "jsx.element",
3150
+ onImplicitProp(node) {
3151
+ context.report({
3152
+ messageId: "default",
3153
+ node
3154
+ });
3155
+ }
3156
+ });
3157
+ }
3158
+
3159
+ //#endregion
3160
+ //#region src/rules/no-implicit-key/no-implicit-key.ts
3161
+ const RULE_NAME$29 = "no-implicit-key";
3162
+ var no_implicit_key_default = createRule({
3163
+ meta: {
3164
+ type: "problem",
3165
+ docs: { description: "Prevents implicitly passing the 'key' prop to components." },
3166
+ messages: { default: "This spread attribute implicitly passes the 'key' prop to a component, this could lead to unexpected behavior. If you intend to pass the 'key' prop, use 'key={value}'." },
3167
+ schema: []
3168
+ },
3169
+ name: RULE_NAME$29,
3170
+ create: create$29,
3171
+ defaultOptions: []
3172
+ });
3173
+ function create$29(context) {
3174
+ return createImplicitPropListener(context, {
3175
+ name: "key",
3176
+ isAllowedProp: (fqn) => fqn.endsWith("react.attributes.key"),
3177
+ isAllowedType: (fqn) => fqn.endsWith("react.key"),
3178
+ onImplicitProp(node) {
3179
+ context.report({
3180
+ messageId: "default",
3181
+ node
3182
+ });
3183
+ }
3184
+ });
3185
+ }
3186
+
3187
+ //#endregion
3188
+ //#region src/rules/no-implicit-ref/no-implicit-ref.ts
3189
+ const RULE_NAME$28 = "no-implicit-ref";
3190
+ const RE_REACT_REF_TYPE = /react\.(ref|legacyref|refcallback|refobject)$/i;
3191
+ var no_implicit_ref_default = createRule({
3192
+ meta: {
3193
+ type: "problem",
3194
+ docs: { description: "Prevents implicitly passing the 'ref' prop to components." },
3195
+ messages: { default: "This spread attribute implicitly passes the 'ref' prop to a component, this could lead to unexpected behavior. If you intend to pass the 'ref' prop, use 'ref={value}'." },
3196
+ schema: []
3197
+ },
3198
+ name: RULE_NAME$28,
3199
+ create: create$28,
3200
+ defaultOptions: []
3201
3201
  });
3202
+ function create$28(context) {
3203
+ return createImplicitPropListener(context, {
3204
+ name: "ref",
3205
+ isAllowedProp: (fqn) => fqn.endsWith("attributes.ref"),
3206
+ isAllowedType: (fqn) => RE_REACT_REF_TYPE.test(fqn),
3207
+ onImplicitProp(node) {
3208
+ context.report({
3209
+ messageId: "default",
3210
+ node
3211
+ });
3212
+ }
3213
+ });
3214
+ }
3202
3215
 
3203
3216
  //#endregion
3204
3217
  //#region src/rules/no-leaked-conditional-rendering/no-leaked-conditional-rendering.ts
@@ -3442,6 +3455,12 @@ function create$24(context) {
3442
3455
  */
3443
3456
  function visitItemExpression(node) {
3444
3457
  switch (node.type) {
3458
+ case AST_NODE_TYPES.ChainExpression:
3459
+ case AST_NODE_TYPES.TSAsExpression:
3460
+ case AST_NODE_TYPES.TSTypeAssertion:
3461
+ case AST_NODE_TYPES.TSNonNullExpression:
3462
+ case AST_NODE_TYPES.TSSatisfiesExpression:
3463
+ case AST_NODE_TYPES.TSInstantiationExpression: return visitItemExpression(node.expression);
3445
3464
  case AST_NODE_TYPES.JSXElement: return hasAttribute(context, node, "key") ? [] : [{
3446
3465
  messageId: "default",
3447
3466
  node
@@ -4358,7 +4377,7 @@ function collectUsedPropKeysOfReference(context, usedPropKeys, ref) {
4358
4377
  function getKeyOfExpression(expr) {
4359
4378
  switch (expr.type) {
4360
4379
  case AST_NODE_TYPES.Identifier: return expr.name;
4361
- case AST_NODE_TYPES.Literal: if (typeof expr.value === "string") return expr.value;
4380
+ case AST_NODE_TYPES.Literal: if (isString(expr.value)) return expr.value;
4362
4381
  }
4363
4382
  return null;
4364
4383
  }
@@ -8219,6 +8238,7 @@ function inferViolations$2(context, facts) {
8219
8238
  const resolver = createSetStateResolver$1(context);
8220
8239
  const getText = (n) => context.sourceCode.getText(n);
8221
8240
  const isUseEffectCall = (node) => core.isUseEffectLikeCall(node, additionalEffectHooks);
8241
+ const isUseStateOrThenCall = or(resolver.isUseStateCall, isThenCall);
8222
8242
  const setStateCallsByFn = /* @__PURE__ */ new Map();
8223
8243
  const setStateInHookCallbacks = /* @__PURE__ */ new Map();
8224
8244
  const setStateInEffectArg = /* @__PURE__ */ new Map();
@@ -8226,7 +8246,7 @@ function inferViolations$2(context, facts) {
8226
8246
  const trackedFnCalls = [];
8227
8247
  const violations = [];
8228
8248
  for (const { enclosingFunction, enclosingFunctionKind, node, setupFunction } of facts.calls) {
8229
- if (resolver.isUseStateCall(node) || isThenCall(node)) continue;
8249
+ if (isUseStateOrThenCall(node)) continue;
8230
8250
  if (!resolver.isSetStateCall(node)) {
8231
8251
  if (setupFunction != null && enclosingFunction === setupFunction) trackedFnCalls.push(node);
8232
8252
  continue;
@@ -8342,11 +8362,12 @@ function create$5(context) {
8342
8362
 
8343
8363
  //#endregion
8344
8364
  //#region src/rules/set-state-in-render/helpers.ts
8365
+ const isComponentOrHookName = or(core.isFunctionComponentName, core.isHookName);
8345
8366
  function isComponentOrHookLikeFunction(node) {
8346
8367
  const id = core.getFunctionId(node);
8347
8368
  if (id == null) return false;
8348
- if (Check.isIdentifier(id)) return core.isFunctionComponentName(id.name) || core.isHookName(id.name);
8349
- if (id.type === AST_NODE_TYPES.MemberExpression && Check.isIdentifier(id.property)) return core.isFunctionComponentName(id.property.name) || core.isHookName(id.property.name);
8369
+ if (Check.isIdentifier(id)) return isComponentOrHookName(id.name);
8370
+ if (id.type === AST_NODE_TYPES.MemberExpression && Check.isIdentifier(id.property)) return isComponentOrHookName(id.property.name);
8350
8371
  return false;
8351
8372
  }
8352
8373
  function isInsideConditional(node, stopAt) {