@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 +5 -6
- package/dist/index.js +100 -97
- package/package.json +5 -5
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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:
|
|
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
|
-
|
|
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.
|
|
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.
|
|
38
|
-
"@eslint-react/eff": "2.
|
|
39
|
-
"@eslint-react/shared": "2.
|
|
40
|
-
"@eslint-react/var": "2.
|
|
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",
|