@eslint-react/core 4.0.2-beta.2 → 4.0.2-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -295,7 +295,7 @@ declare namespace getComponentCollectorLegacy {
295
295
  };
296
296
  }
297
297
  /**
298
- * Get an api and visitor object for the rule to collect class componentss
298
+ * Get an api and visitor object for the rule to collect class components
299
299
  * @param context The ESLint rule context
300
300
  * @returns The api and visitor of the collector
301
301
  */
@@ -308,6 +308,7 @@ declare function getComponentCollectorLegacy(context: RuleContext): getComponent
308
308
  * @returns `true` if the node is a class component, `false` otherwise
309
309
  */
310
310
  declare function isClassComponent(node: TSESTree.Node): node is ast.TSESTreeClass;
311
+ declare function isClassComponent(node: TSESTree.Node, context: RuleContext): node is ast.TSESTreeClass;
311
312
  /**
312
313
  * Check if a node is a React PureComponent
313
314
  * @param node The AST node to check
@@ -376,7 +377,7 @@ declare function isRenderMethodCallback(node: ast.TSESTreeFunction): boolean;
376
377
  * @param node The node to check
377
378
  * @internal
378
379
  */
379
- declare function isThisSetState(node: TSESTree.CallExpression): boolean;
380
+ declare function isThisSetStateCall(node: TSESTree.CallExpression): boolean;
380
381
  /**
381
382
  * Check whether the given node is an assignment to this.state
382
383
  * @param node The node to check
@@ -439,6 +440,12 @@ declare function isFunctionWithLooseComponentName(context: RuleContext, fn: ast.
439
440
  * @returns `true` if the node is a call expression for a component wrapper
440
441
  */
441
442
  declare function isComponentWrapperCall(context: RuleContext, node: TSESTree.Node): boolean;
443
+ /**
444
+ * Check if the node is a callback function passed to a component wrapper
445
+ * @param context The ESLint rule context
446
+ * @param node The node to check
447
+ * @returns `true` if the node is a callback function passed to a component wrapper
448
+ */
442
449
  /**
443
450
  * Check if the node is a call expression for a component wrapper loosely
444
451
  * @param context The ESLint rule context
@@ -520,7 +527,7 @@ interface HookSemanticNode extends SemanticNode {
520
527
  /** The other hooks called by the hook */
521
528
  hookCalls: TSESTree.CallExpression[];
522
529
  /** The directives used in the function (ex: "use strict", "use client", etc.) */
523
- directives: TSESTree.StringLiteral[];
530
+ directives: ast.TSESTreeDirective[];
524
531
  }
525
532
  //#endregion
526
533
  //#region src/hook/hook-collector.d.ts
@@ -553,20 +560,13 @@ declare function isHookId(id: TSESTree.Node): id is TSESTree.Identifier | TSESTr
553
560
  * @param node The function node to check
554
561
  * @returns True if the function is a React Hook, false otherwise
555
562
  */
556
- declare function isHook(node: ast.TSESTreeFunction | null): boolean;
563
+ declare function isHookDefinition(node: ast.TSESTreeFunction | null): boolean;
557
564
  /**
558
565
  * Check if the given node is a React Hook call by its name.
559
566
  * @param node The node to check.
560
567
  * @returns `true` if the node is a React Hook call, `false` otherwise.
561
568
  */
562
569
  declare function isHookCall(node: TSESTree.Node | null): node is TSESTree.CallExpression;
563
- /**
564
- * Check if a node is a call to a specific React hook.
565
- * Returns a function that accepts a hook name to check against.
566
- * @param node The AST node to check
567
- * @returns A function that takes a hook name and returns boolean
568
- */
569
- declare function isHookCallWithName(node: TSESTree.Node | null): (name: string) => boolean;
570
570
  /**
571
571
  * Detect useEffect calls and variations (useLayoutEffect, etc.) using a regex pattern
572
572
  * @param node The AST node to check
@@ -611,4 +611,4 @@ declare const REACT_BUILTIN_HOOK_NAMES: readonly ["use", "useActionState", "useC
611
611
  */
612
612
  declare function isHookName(name: string): boolean;
613
613
  //#endregion
614
- export { ClassComponentSemanticNode, ClientFunctionSemanticNode, ComponentDetectionHint, ComponentFlag, ComponentSemanticNode, DEFAULT_COMPONENT_DETECTION_HINT, FunctionComponentSemanticNode, FunctionKind, FunctionSemanticNode, HookSemanticNode, REACT_BUILTIN_HOOK_NAMES, SemanticFunc, SemanticNode, ServerFunctionSemanticNode, findImportSource, getComponentCollector, getComponentCollectorLegacy, getComponentFlagFromInitPath, getFunctionComponentId, getHookCollector, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isForwardRef, isForwardRefCall, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHook, isHookCall, isHookCallWithName, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRender, isRenderMethodCallback, isRenderMethodLike, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall };
614
+ export { ClassComponentSemanticNode, ClientFunctionSemanticNode, ComponentDetectionHint, ComponentFlag, ComponentSemanticNode, DEFAULT_COMPONENT_DETECTION_HINT, FunctionComponentSemanticNode, FunctionKind, FunctionSemanticNode, HookSemanticNode, REACT_BUILTIN_HOOK_NAMES, SemanticFunc, SemanticNode, ServerFunctionSemanticNode, findImportSource, getComponentCollector, getComponentCollectorLegacy, getComponentFlagFromInitPath, getFunctionComponentId, getHookCollector, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isForwardRef, isForwardRefCall, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHookCall, isHookDefinition, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRender, isRenderMethodCallback, isRenderMethodLike, isShouldComponentUpdate, isThisSetStateCall, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall };
package/dist/index.js CHANGED
@@ -185,13 +185,18 @@ function getRequireExpressionArguments(node) {
185
185
  * @returns The import source or null if not found
186
186
  */
187
187
  function findImportSource(name, initialScope) {
188
+ return findImportSourceImpl(name, initialScope, /* @__PURE__ */ new Set());
189
+ }
190
+ function findImportSourceImpl(name, initialScope, visited) {
191
+ if (visited.has(name)) return null;
192
+ visited.add(name);
188
193
  const latestDef = findVariable(initialScope, name)?.defs.at(-1);
189
194
  if (latestDef == null) return null;
190
195
  const { node, parent } = latestDef;
191
196
  if (node.type === AST_NODE_TYPES.VariableDeclarator && node.init != null) {
192
197
  const { init } = node;
193
- if (init.type === AST_NODE_TYPES.MemberExpression && init.object.type === AST_NODE_TYPES.Identifier) return findImportSource(init.object.name, initialScope);
194
- if (init.type === AST_NODE_TYPES.Identifier) return findImportSource(init.name, initialScope);
198
+ if (init.type === AST_NODE_TYPES.MemberExpression && init.object.type === AST_NODE_TYPES.Identifier) return findImportSourceImpl(init.object.name, initialScope, visited);
199
+ if (init.type === AST_NODE_TYPES.Identifier) return findImportSourceImpl(init.name, initialScope, visited);
195
200
  const arg0 = getRequireExpressionArguments(init)?.[0];
196
201
  if (arg0 == null || !ast.isLiteral(arg0, "string")) return null;
197
202
  return arg0.value;
@@ -243,7 +248,7 @@ function isReactAPI(api) {
243
248
  const getText = (n) => context.sourceCode.getText(n);
244
249
  const name = ast.getFullyQualifiedName(node, getText);
245
250
  if (name === api) return true;
246
- if (name.substring(name.indexOf(".") + 1) === api) return true;
251
+ if (name.endsWith(`.${api}`)) return true;
247
252
  return false;
248
253
  };
249
254
  return dual(2, func);
@@ -328,7 +333,7 @@ function isHookName(name) {
328
333
  * @param node The function node to check
329
334
  * @returns True if the function is a React Hook, false otherwise
330
335
  */
331
- function isHook(node) {
336
+ function isHookDefinition(node) {
332
337
  if (node == null) return false;
333
338
  const id = ast.getFunctionId(node);
334
339
  switch (id?.type) {
@@ -507,17 +512,19 @@ function getHookCollector(context) {
507
512
 
508
513
  //#endregion
509
514
  //#region src/component/component-detection-legacy.ts
510
- /**
511
- * Check if a node is a React class component
512
- * @param node The AST node to check
513
- * @returns `true` if the node is a class component, `false` otherwise
514
- */
515
- function isClassComponent(node) {
515
+ function isClassComponent(node, context) {
516
516
  if ("superClass" in node && node.superClass != null) {
517
517
  const re = /^(?:Pure)?Component$/u;
518
518
  switch (true) {
519
- case node.superClass.type === AST_NODE_TYPES.Identifier: return re.test(node.superClass.name);
520
- case node.superClass.type === AST_NODE_TYPES.MemberExpression && node.superClass.property.type === AST_NODE_TYPES.Identifier: return re.test(node.superClass.property.name);
519
+ case node.superClass.type === AST_NODE_TYPES.Identifier:
520
+ if (!re.test(node.superClass.name)) return false;
521
+ if (context == null) return true;
522
+ return isInitializedFromReact(node.superClass.name, context.sourceCode.getScope(node), "react");
523
+ case node.superClass.type === AST_NODE_TYPES.MemberExpression && node.superClass.property.type === AST_NODE_TYPES.Identifier:
524
+ if (!re.test(node.superClass.property.name)) return false;
525
+ if (context == null) return true;
526
+ if (node.superClass.object.type === AST_NODE_TYPES.Identifier) return isInitializedFromReact(node.superClass.object.name, context.sourceCode.getScope(node), "react");
527
+ return true;
521
528
  }
522
529
  }
523
530
  return false;
@@ -592,7 +599,7 @@ function isComponentWillUnmountCallback(node) {
592
599
  * @returns `true` if node is a render function, `false` if not
593
600
  */
594
601
  function isRenderMethodLike(node) {
595
- return ast.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name.startsWith("render") && node.parent.parent.type === AST_NODE_TYPES.ClassDeclaration;
602
+ return ast.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name.startsWith("render") && ast.isOneOf([AST_NODE_TYPES.ClassDeclaration, AST_NODE_TYPES.ClassExpression])(node.parent.parent);
596
603
  }
597
604
  /**
598
605
  * Check if the given node is a function within a render method of a class component
@@ -617,7 +624,7 @@ function isRenderMethodCallback(node) {
617
624
  * @param node The node to check
618
625
  * @internal
619
626
  */
620
- function isThisSetState(node) {
627
+ function isThisSetStateCall(node) {
621
628
  const { callee } = node;
622
629
  return callee.type === AST_NODE_TYPES.MemberExpression && ast.isThisExpressionLoose(callee.object) && callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === "setState";
623
630
  }
@@ -644,6 +651,12 @@ function isComponentWrapperCall(context, node) {
644
651
  return isMemoCall(context, node) || isForwardRefCall(context, node);
645
652
  }
646
653
  /**
654
+ * Check if the node is a callback function passed to a component wrapper
655
+ * @param context The ESLint rule context
656
+ * @param node The node to check
657
+ * @returns `true` if the node is a callback function passed to a component wrapper
658
+ */
659
+ /**
647
660
  * Check if the node is a call expression for a component wrapper loosely
648
661
  * @param context The ESLint rule context
649
662
  * @param node The node to check
@@ -852,7 +865,7 @@ function getComponentCollector(context, options = {}) {
852
865
  const initPath = ast.getFunctionInitPath(node);
853
866
  const directives = ast.getFunctionDirectives(node);
854
867
  const entry = {
855
- id: getFunctionComponentId(context, node),
868
+ id,
856
869
  key,
857
870
  kind: "component",
858
871
  name,
@@ -925,7 +938,7 @@ function getComponentCollector(context, options = {}) {
925
938
  //#region src/component/component-collector-legacy.ts
926
939
  const idGen = new IdGenerator("class-component:");
927
940
  /**
928
- * Get an api and visitor object for the rule to collect class componentss
941
+ * Get an api and visitor object for the rule to collect class components
929
942
  * @param context The ESLint rule context
930
943
  * @returns The api and visitor of the collector
931
944
  */
@@ -963,4 +976,4 @@ function getComponentCollectorLegacy(context) {
963
976
  }
964
977
 
965
978
  //#endregion
966
- export { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, REACT_BUILTIN_HOOK_NAMES, findImportSource, getComponentCollector, getComponentCollectorLegacy, getComponentFlagFromInitPath, getFunctionComponentId, getHookCollector, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isForwardRef, isForwardRefCall, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHook, isHookCall, isHookCallWithName, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRender, isRenderMethodCallback, isRenderMethodLike, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall };
979
+ export { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, REACT_BUILTIN_HOOK_NAMES, findImportSource, getComponentCollector, getComponentCollectorLegacy, getComponentFlagFromInitPath, getFunctionComponentId, getHookCollector, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isForwardRef, isForwardRefCall, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHookCall, isHookDefinition, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRender, isRenderMethodCallback, isRenderMethodLike, isShouldComponentUpdate, isThisSetStateCall, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-react/core",
3
- "version": "4.0.2-beta.2",
3
+ "version": "4.0.2-beta.4",
4
4
  "description": "ESLint React's ESLint utility module for static analysis of React core APIs and patterns.",
5
5
  "homepage": "https://github.com/Rel1cx/eslint-react",
6
6
  "bugs": {
@@ -34,13 +34,13 @@
34
34
  "@typescript-eslint/types": "^8.57.2",
35
35
  "@typescript-eslint/utils": "^8.57.2",
36
36
  "ts-pattern": "^5.9.0",
37
- "@eslint-react/ast": "4.0.2-beta.2",
38
- "@eslint-react/jsx": "4.0.2-beta.2",
39
- "@eslint-react/var": "4.0.2-beta.2",
40
- "@eslint-react/shared": "4.0.2-beta.2"
37
+ "@eslint-react/ast": "4.0.2-beta.4",
38
+ "@eslint-react/shared": "4.0.2-beta.4",
39
+ "@eslint-react/var": "4.0.2-beta.4",
40
+ "@eslint-react/jsx": "4.0.2-beta.4"
41
41
  },
42
42
  "devDependencies": {
43
- "tsdown": "^0.21.6",
43
+ "tsdown": "^0.21.7",
44
44
  "@local/configs": "0.0.0",
45
45
  "@local/eff": "3.0.0-beta.72"
46
46
  },