@eslint-react/core 2.7.5-next.9 → 2.8.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.
package/dist/index.d.ts CHANGED
@@ -251,13 +251,12 @@ interface ClassComponentSemanticNode extends SemanticNode {
251
251
  type ComponentSemanticNode = ClassComponentSemanticNode | FunctionComponentSemanticNode;
252
252
  //#endregion
253
253
  //#region src/component/component-collector.d.ts
254
- type FunctionEntry$1 = FunctionComponentSemanticNode & {
254
+ interface FunctionEntry$1 extends FunctionComponentSemanticNode {
255
255
  isComponentDefinition: boolean;
256
- };
256
+ }
257
257
  declare namespace useComponentCollector {
258
258
  type Options = {
259
259
  collectDisplayName?: boolean;
260
- collectHookCalls?: boolean;
261
260
  hint?: ComponentDetectionHint;
262
261
  };
263
262
  type ReturnType = {
@@ -533,7 +532,7 @@ type FindEnclosingComponentOrHookFilter = (n: TSESTree.Node, name: string | null
533
532
  * @param test Optional test function to customize component or hook identification
534
533
  * @returns The enclosing component or hook node, or `null` if none is found
535
534
  */
536
- declare function findEnclosingComponentOrHook(node: TSESTree.Node | unit, test?: FindEnclosingComponentOrHookFilter): TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | TSESTree.FunctionDeclarationWithName | TSESTree.FunctionDeclarationWithOptionalName | undefined;
535
+ declare function findEnclosingComponentOrHook(node: TSESTree.Node | unit, test?: FindEnclosingComponentOrHookFilter): TSESTree.ArrowFunctionExpression | TSESTree.FunctionDeclarationWithName | TSESTree.FunctionDeclarationWithOptionalName | TSESTree.FunctionExpression | undefined;
537
536
  //#endregion
538
537
  //#region src/hierarchy/is-inside-component-or-hook.d.ts
539
538
  /**
@@ -716,7 +715,7 @@ declare function resolveJsxAttributeValue(context: RuleContext, attribute: AST.T
716
715
  readonly toStatic: () => string | number | bigint | boolean | RegExp | null;
717
716
  } | {
718
717
  readonly kind: "expression";
719
- readonly node: TSESTree.Expression | TSESTree.JSXEmptyExpression;
718
+ readonly node: TSESTree.JSXEmptyExpression | TSESTree.Expression;
720
719
  readonly toStatic: () => unknown;
721
720
  } | {
722
721
  readonly kind: "element";
@@ -724,7 +723,7 @@ declare function resolveJsxAttributeValue(context: RuleContext, attribute: AST.T
724
723
  readonly toStatic: () => undefined;
725
724
  } | {
726
725
  readonly kind: "spreadChild";
727
- readonly node: TSESTree.Expression | TSESTree.JSXEmptyExpression;
726
+ readonly node: TSESTree.JSXEmptyExpression | TSESTree.Expression;
728
727
  readonly toStatic: () => undefined;
729
728
  } | {
730
729
  readonly kind: "spreadProps";
package/dist/index.js CHANGED
@@ -711,6 +711,99 @@ function isPureComponent(node) {
711
711
  return false;
712
712
  }
713
713
 
714
+ //#endregion
715
+ //#region src/component/component-wrapper.ts
716
+ /**
717
+ * Check if the node is a call expression for a component wrapper
718
+ * @param context The ESLint rule context
719
+ * @param node The node to check
720
+ * @returns `true` if the node is a call expression for a component wrapper
721
+ */
722
+ function isComponentWrapperCall(context, node) {
723
+ if (node.type !== AST_NODE_TYPES.CallExpression) return false;
724
+ return isMemoCall(context, node) || isForwardRefCall(context, node);
725
+ }
726
+ /**
727
+ * Check if the node is a call expression for a component wrapper loosely
728
+ * @param context The ESLint rule context
729
+ * @param node The node to check
730
+ * @returns `true` if the node is a call expression for a component wrapper loosely
731
+ */
732
+ function isComponentWrapperCallLoose(context, node) {
733
+ if (node.type !== AST_NODE_TYPES.CallExpression) return false;
734
+ return isComponentWrapperCall(context, node) || isUseCallbackCall(node);
735
+ }
736
+ /**
737
+ * Check if the node is a callback function passed to a component wrapper
738
+ * @param context The ESLint rule context
739
+ * @param node The node to check
740
+ * @returns `true` if the node is a callback function passed to a component wrapper
741
+ */
742
+ function isComponentWrapperCallback(context, node) {
743
+ if (!AST.isFunction(node)) return false;
744
+ const parent = node.parent;
745
+ if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
746
+ return isComponentWrapperCall(context, parent);
747
+ }
748
+ /**
749
+ * Check if the node is a callback function passed to a component wrapper loosely
750
+ * @param context The ESLint rule context
751
+ * @param node The node to check
752
+ * @returns `true` if the node is a callback function passed to a component wrapper loosely
753
+ */
754
+ function isComponentWrapperCallbackLoose(context, node) {
755
+ if (!AST.isFunction(node)) return false;
756
+ const parent = node.parent;
757
+ if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
758
+ return isComponentWrapperCallLoose(context, parent);
759
+ }
760
+
761
+ //#endregion
762
+ //#region src/component/component-id.ts
763
+ /**
764
+ * Get function component identifier from `const Component = memo(() => {});`
765
+ * @param context The rule context
766
+ * @param node The function node to analyze
767
+ * @returns The function identifier or `unit` if not found
768
+ */
769
+ function getFunctionComponentId(context, node) {
770
+ const functionId = AST.getFunctionId(node);
771
+ if (functionId != null) return functionId;
772
+ const { parent } = node;
773
+ if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === AST_NODE_TYPES.VariableDeclarator) return parent.parent.id;
774
+ if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent.parent) && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator) return parent.parent.parent.id;
775
+ return unit;
776
+ }
777
+
778
+ //#endregion
779
+ //#region src/component/component-name.ts
780
+ /**
781
+ * Check if a string matches the strict component name pattern
782
+ * @param name The name to check
783
+ */
784
+ function isComponentName(name) {
785
+ return RE_COMPONENT_NAME.test(name);
786
+ }
787
+ /**
788
+ * Check if a string matches the loose component name pattern
789
+ * @param name The name to check
790
+ */
791
+ function isComponentNameLoose(name) {
792
+ return RE_COMPONENT_NAME_LOOSE.test(name);
793
+ }
794
+ /**
795
+ * Check if the function has no name or a loose component name
796
+ * @param context The rule context
797
+ * @param fn The function node
798
+ */
799
+ function hasNoneOrLooseComponentName(context, fn) {
800
+ const id = getFunctionComponentId(context, fn);
801
+ if (id == null) return true;
802
+ if (id.type === AST_NODE_TYPES.Identifier) return isComponentNameLoose(id.name);
803
+ if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) return isComponentNameLoose(id.property.name);
804
+ return false;
805
+ }
806
+
714
807
  //#endregion
715
808
  //#region src/component/component-render-method.ts
716
809
  /**
@@ -789,6 +882,7 @@ function isChildrenOfCreateElement(context, node) {
789
882
  * @returns `true` if the node is considered a component definition
790
883
  */
791
884
  function isComponentDefinition(context, node, hint) {
885
+ if (!hasNoneOrLooseComponentName(context, node)) return false;
792
886
  if (isChildrenOfCreateElement(context, node) || isRenderMethodCallback(node)) return false;
793
887
  if (shouldExcludeBasedOnHint(node, hint)) return false;
794
888
  const significantParent = AST.findParentNode(node, AST.isOneOf([
@@ -803,70 +897,6 @@ function isComponentDefinition(context, node, hint) {
803
897
  return true;
804
898
  }
805
899
 
806
- //#endregion
807
- //#region src/component/component-wrapper.ts
808
- /**
809
- * Check if the node is a call expression for a component wrapper
810
- * @param context The ESLint rule context
811
- * @param node The node to check
812
- * @returns `true` if the node is a call expression for a component wrapper
813
- */
814
- function isComponentWrapperCall(context, node) {
815
- if (node.type !== AST_NODE_TYPES.CallExpression) return false;
816
- return isMemoCall(context, node) || isForwardRefCall(context, node);
817
- }
818
- /**
819
- * Check if the node is a call expression for a component wrapper loosely
820
- * @param context The ESLint rule context
821
- * @param node The node to check
822
- * @returns `true` if the node is a call expression for a component wrapper loosely
823
- */
824
- function isComponentWrapperCallLoose(context, node) {
825
- if (node.type !== AST_NODE_TYPES.CallExpression) return false;
826
- return isComponentWrapperCall(context, node) || isUseCallbackCall(node);
827
- }
828
- /**
829
- * Check if the node is a callback function passed to a component wrapper
830
- * @param context The ESLint rule context
831
- * @param node The node to check
832
- * @returns `true` if the node is a callback function passed to a component wrapper
833
- */
834
- function isComponentWrapperCallback(context, node) {
835
- if (!AST.isFunction(node)) return false;
836
- const parent = node.parent;
837
- if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
838
- return isComponentWrapperCall(context, parent);
839
- }
840
- /**
841
- * Check if the node is a callback function passed to a component wrapper loosely
842
- * @param context The ESLint rule context
843
- * @param node The node to check
844
- * @returns `true` if the node is a callback function passed to a component wrapper loosely
845
- */
846
- function isComponentWrapperCallbackLoose(context, node) {
847
- if (!AST.isFunction(node)) return false;
848
- const parent = node.parent;
849
- if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
850
- return isComponentWrapperCallLoose(context, parent);
851
- }
852
-
853
- //#endregion
854
- //#region src/component/component-id.ts
855
- /**
856
- * Get function component identifier from `const Component = memo(() => {});`
857
- * @param context The rule context
858
- * @param node The function node to analyze
859
- * @returns The function identifier or `unit` if not found
860
- */
861
- function getFunctionComponentId(context, node) {
862
- const functionId = AST.getFunctionId(node);
863
- if (functionId != null) return functionId;
864
- const { parent } = node;
865
- if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === AST_NODE_TYPES.VariableDeclarator) return parent.parent.id;
866
- if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent.parent) && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator) return parent.parent.parent.id;
867
- return unit;
868
- }
869
-
870
900
  //#endregion
871
901
  //#region src/component/component-flag.ts
872
902
  /**
@@ -894,35 +924,6 @@ function getComponentFlagFromInitPath(initPath) {
894
924
  return flag;
895
925
  }
896
926
 
897
- //#endregion
898
- //#region src/component/component-name.ts
899
- /**
900
- * Check if a string matches the strict component name pattern
901
- * @param name The name to check
902
- */
903
- function isComponentName(name) {
904
- return RE_COMPONENT_NAME.test(name);
905
- }
906
- /**
907
- * Check if a string matches the loose component name pattern
908
- * @param name The name to check
909
- */
910
- function isComponentNameLoose(name) {
911
- return RE_COMPONENT_NAME_LOOSE.test(name);
912
- }
913
- /**
914
- * Check if the function has no name or a loose component name
915
- * @param context The rule context
916
- * @param fn The function node
917
- */
918
- function hasNoneOrLooseComponentName(context, fn) {
919
- const id = getFunctionComponentId(context, fn);
920
- if (id == null) return true;
921
- if (id.type === AST_NODE_TYPES.Identifier) return isComponentNameLoose(id.name);
922
- if (id.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier) return isComponentNameLoose(id.property.name);
923
- return false;
924
- }
925
-
926
927
  //#endregion
927
928
  //#region src/component/component-collector.ts
928
929
  const idGen$1 = new IdGenerator("function_component_");
@@ -933,7 +934,7 @@ const idGen$1 = new IdGenerator("function_component_");
933
934
  * @returns The ctx and visitor of the collector
934
935
  */
935
936
  function useComponentCollector(context, options = {}) {
936
- const { collectDisplayName = false, collectHookCalls = false, hint = DEFAULT_COMPONENT_DETECTION_HINT } = options;
937
+ const { collectDisplayName = false, hint = DEFAULT_COMPONENT_DETECTION_HINT } = options;
937
938
  const functionEntries = [];
938
939
  const components = /* @__PURE__ */ new Map();
939
940
  const getText = (n) => context.sourceCode.getText(n);
@@ -957,7 +958,7 @@ function useComponentCollector(context, options = {}) {
957
958
  hint,
958
959
  hookCalls: [],
959
960
  initPath,
960
- isComponentDefinition: hasNoneOrLooseComponentName(context, node) && isComponentDefinition(context, node, hint),
961
+ isComponentDefinition: isComponentDefinition(context, node, hint),
961
962
  isExportDefault,
962
963
  isExportDefaultDeclaration,
963
964
  rets: []
@@ -997,12 +998,14 @@ function useComponentCollector(context, options = {}) {
997
998
  if (component == null) return;
998
999
  component.displayName = right;
999
1000
  } } : {},
1000
- ...collectHookCalls ? { "CallExpression:exit"(node) {
1001
+ CallExpression(node) {
1001
1002
  if (!isHookCall(node)) return;
1002
1003
  const entry = getCurrentEntry();
1003
1004
  if (entry == null) return;
1004
1005
  entry.hookCalls.push(node);
1005
- } } : {},
1006
+ if (!entry.isComponentDefinition) return;
1007
+ components.set(entry.key, entry);
1008
+ },
1006
1009
  ReturnStatement(node) {
1007
1010
  const entry = getCurrentEntry();
1008
1011
  if (entry == null) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-react/core",
3
- "version": "2.7.5-next.9",
3
+ "version": "2.8.0",
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,10 +34,10 @@
34
34
  "@typescript-eslint/types": "^8.54.0",
35
35
  "@typescript-eslint/utils": "^8.54.0",
36
36
  "ts-pattern": "^5.9.0",
37
- "@eslint-react/ast": "2.7.5-next.9",
38
- "@eslint-react/eff": "2.7.5-next.9",
39
- "@eslint-react/shared": "2.7.5-next.9",
40
- "@eslint-react/var": "2.7.5-next.9"
37
+ "@eslint-react/ast": "2.8.0",
38
+ "@eslint-react/eff": "2.8.0",
39
+ "@eslint-react/shared": "2.8.0",
40
+ "@eslint-react/var": "2.8.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "tsdown": "^0.20.1",