@eslint-react/core 1.28.0-next.1 → 1.28.0-next.3
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.mts +22 -25
- package/dist/index.d.ts +22 -25
- package/dist/index.js +156 -133
- package/dist/index.mjs +152 -134
- package/package.json +6 -6
package/dist/index.d.mts
CHANGED
|
@@ -237,6 +237,9 @@ declare function isDeclaredInRenderPropLoose(node: TSESTree.Node): boolean;
|
|
|
237
237
|
type ERStateKind = "actionState" | "state";
|
|
238
238
|
declare function isThisSetState(node: TSESTree.CallExpression): boolean;
|
|
239
239
|
|
|
240
|
+
/** internal */
|
|
241
|
+
declare function hasValidHierarchy(node: AST.TSESTreeFunction, context: RuleContext, hint: bigint): boolean;
|
|
242
|
+
|
|
240
243
|
/**
|
|
241
244
|
* Check if a node is a React class component
|
|
242
245
|
* @param node The AST node to check
|
|
@@ -326,30 +329,6 @@ interface ERSemanticEntry {
|
|
|
326
329
|
phase: ERPhaseKind;
|
|
327
330
|
}
|
|
328
331
|
|
|
329
|
-
/**
|
|
330
|
-
* The ESQuery selector for a component display name assignment expression
|
|
331
|
-
*/
|
|
332
|
-
declare const DISPLAY_NAME_ASSIGNMENT_SELECTOR: string;
|
|
333
|
-
/**
|
|
334
|
-
* Check if the node is a component display name assignment expression
|
|
335
|
-
* @param node The AST node
|
|
336
|
-
* @returns `true` if the node is a component display name assignment
|
|
337
|
-
*/
|
|
338
|
-
declare function isDisplayNameAssignment(node: TSESTree.Node | _): node is TSESTree.AssignmentExpression;
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Checks if the given node is a call expression to the given function or method of the pragma
|
|
342
|
-
* @param name The name of the function or method to check
|
|
343
|
-
* @returns A predicate that checks if the given node is a call expression to the given function or method
|
|
344
|
-
*/
|
|
345
|
-
declare function isFromReact(name: string): (node: TSESTree.Identifier | TSESTree.MemberExpression, context: RuleContext) => boolean;
|
|
346
|
-
/**
|
|
347
|
-
* @internal
|
|
348
|
-
* @param memberName The name of the member object
|
|
349
|
-
* @param name The name of the member property
|
|
350
|
-
* @returns A function that checks if a given node is a member expression of a Pragma member.
|
|
351
|
-
*/
|
|
352
|
-
declare function isFromReactMember(memberName: string, name: string): (node: TSESTree.MemberExpression, context: RuleContext) => boolean;
|
|
353
332
|
declare namespace isCallFromReact {
|
|
354
333
|
type ReturnType = {
|
|
355
334
|
(context: RuleContext): (node: TSESTree.Node) => node is TSESTree.CallExpression;
|
|
@@ -369,6 +348,24 @@ declare namespace isCallFromReactMember {
|
|
|
369
348
|
}
|
|
370
349
|
declare function isCallFromReactMember(pragmaMemberName: string, name: string): isCallFromReactMember.ReturnType;
|
|
371
350
|
|
|
351
|
+
/**
|
|
352
|
+
* The ESQuery selector for a component display name assignment expression
|
|
353
|
+
*/
|
|
354
|
+
declare const DISPLAY_NAME_ASSIGNMENT_SELECTOR: string;
|
|
355
|
+
/**
|
|
356
|
+
* Check if the node is a component display name assignment expression
|
|
357
|
+
* @param node The AST node
|
|
358
|
+
* @returns `true` if the node is a component display name assignment
|
|
359
|
+
*/
|
|
360
|
+
declare function isDisplayNameAssignment(node: TSESTree.Node | _): node is TSESTree.AssignmentExpression;
|
|
361
|
+
|
|
362
|
+
declare function isFromReactLoose(node: TSESTree.Identifier | TSESTree.MemberExpression, name: string): boolean;
|
|
363
|
+
declare function isFromReactStrict(node: TSESTree.Identifier | TSESTree.MemberExpression, name: string, importSource: string, initialScope: Scope): boolean;
|
|
364
|
+
declare function isFromReact(name: string): (node: TSESTree.Identifier | TSESTree.MemberExpression, context: RuleContext) => boolean;
|
|
365
|
+
declare function isFromReactMemberLoose(node: TSESTree.MemberExpression, memberName: string, name: string): boolean;
|
|
366
|
+
declare function isFromReactMemberStrict(node: TSESTree.MemberExpression, memberName: string, name: string, importSource: string, initialScope: Scope): boolean;
|
|
367
|
+
declare function isFromReactMember(memberName: string, name: string): (node: TSESTree.MemberExpression, context: RuleContext) => boolean;
|
|
368
|
+
|
|
372
369
|
/**
|
|
373
370
|
* Check if an identifier is initialized from react
|
|
374
371
|
* @param name The top-level identifier's name
|
|
@@ -2424,4 +2421,4 @@ declare const isCreateRefCall: isCallFromReact.ReturnType;
|
|
|
2424
2421
|
declare const isForwardRefCall: isCallFromReact.ReturnType;
|
|
2425
2422
|
declare const isMemoCall: isCallFromReact.ReturnType;
|
|
2426
2423
|
|
|
2427
|
-
export { DEFAULT_COMPONENT_HINT, DISPLAY_NAME_ASSIGNMENT_SELECTOR, type ERClassComponent, type ERComponent, ERComponentFlag, ERComponentHint, type ERComponentKind, type EREffectKind, type EREffectPhaseKind, type ERFunctionComponent, type ERHook, type ERHookKind, type ERLifecyclePhaseKind, type ERPhaseKind, ERPhaseRelevance, type ERSemanticEntry, type ERSemanticNode, type ERStateKind, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier, getFunctionComponentIdentifier, hasNoneOrValidComponentName, isCallFromReact, isCallFromReactMember, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentName, isComponentWillUnmount, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isDisplayNameAssignment, isForwardRef, isForwardRefCall, isFromReact, isFromReactMember, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfRenderMethod, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInsideCreateElementProps, isInsideReactHook, isInsideRenderMethod, isInversePhase, isMemo, isMemoCall, isPureComponent, isReactAPICallWithName, isReactAPIWithName, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookName, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isThisSetState, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
|
|
2424
|
+
export { DEFAULT_COMPONENT_HINT, DISPLAY_NAME_ASSIGNMENT_SELECTOR, type ERClassComponent, type ERComponent, ERComponentFlag, ERComponentHint, type ERComponentKind, type EREffectKind, type EREffectPhaseKind, type ERFunctionComponent, type ERHook, type ERHookKind, type ERLifecyclePhaseKind, type ERPhaseKind, ERPhaseRelevance, type ERSemanticEntry, type ERSemanticNode, type ERStateKind, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier, getFunctionComponentIdentifier, hasNoneOrValidComponentName, hasValidHierarchy, isCallFromReact, isCallFromReactMember, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentName, isComponentWillUnmount, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isDisplayNameAssignment, isForwardRef, isForwardRefCall, isFromReact, isFromReactLoose, isFromReactMember, isFromReactMemberLoose, isFromReactMemberStrict, isFromReactStrict, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfRenderMethod, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInsideCreateElementProps, isInsideReactHook, isInsideRenderMethod, isInversePhase, isMemo, isMemoCall, isPureComponent, isReactAPICallWithName, isReactAPIWithName, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookName, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isThisSetState, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
|
package/dist/index.d.ts
CHANGED
|
@@ -237,6 +237,9 @@ declare function isDeclaredInRenderPropLoose(node: TSESTree.Node): boolean;
|
|
|
237
237
|
type ERStateKind = "actionState" | "state";
|
|
238
238
|
declare function isThisSetState(node: TSESTree.CallExpression): boolean;
|
|
239
239
|
|
|
240
|
+
/** internal */
|
|
241
|
+
declare function hasValidHierarchy(node: AST.TSESTreeFunction, context: RuleContext, hint: bigint): boolean;
|
|
242
|
+
|
|
240
243
|
/**
|
|
241
244
|
* Check if a node is a React class component
|
|
242
245
|
* @param node The AST node to check
|
|
@@ -326,30 +329,6 @@ interface ERSemanticEntry {
|
|
|
326
329
|
phase: ERPhaseKind;
|
|
327
330
|
}
|
|
328
331
|
|
|
329
|
-
/**
|
|
330
|
-
* The ESQuery selector for a component display name assignment expression
|
|
331
|
-
*/
|
|
332
|
-
declare const DISPLAY_NAME_ASSIGNMENT_SELECTOR: string;
|
|
333
|
-
/**
|
|
334
|
-
* Check if the node is a component display name assignment expression
|
|
335
|
-
* @param node The AST node
|
|
336
|
-
* @returns `true` if the node is a component display name assignment
|
|
337
|
-
*/
|
|
338
|
-
declare function isDisplayNameAssignment(node: TSESTree.Node | _): node is TSESTree.AssignmentExpression;
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Checks if the given node is a call expression to the given function or method of the pragma
|
|
342
|
-
* @param name The name of the function or method to check
|
|
343
|
-
* @returns A predicate that checks if the given node is a call expression to the given function or method
|
|
344
|
-
*/
|
|
345
|
-
declare function isFromReact(name: string): (node: TSESTree.Identifier | TSESTree.MemberExpression, context: RuleContext) => boolean;
|
|
346
|
-
/**
|
|
347
|
-
* @internal
|
|
348
|
-
* @param memberName The name of the member object
|
|
349
|
-
* @param name The name of the member property
|
|
350
|
-
* @returns A function that checks if a given node is a member expression of a Pragma member.
|
|
351
|
-
*/
|
|
352
|
-
declare function isFromReactMember(memberName: string, name: string): (node: TSESTree.MemberExpression, context: RuleContext) => boolean;
|
|
353
332
|
declare namespace isCallFromReact {
|
|
354
333
|
type ReturnType = {
|
|
355
334
|
(context: RuleContext): (node: TSESTree.Node) => node is TSESTree.CallExpression;
|
|
@@ -369,6 +348,24 @@ declare namespace isCallFromReactMember {
|
|
|
369
348
|
}
|
|
370
349
|
declare function isCallFromReactMember(pragmaMemberName: string, name: string): isCallFromReactMember.ReturnType;
|
|
371
350
|
|
|
351
|
+
/**
|
|
352
|
+
* The ESQuery selector for a component display name assignment expression
|
|
353
|
+
*/
|
|
354
|
+
declare const DISPLAY_NAME_ASSIGNMENT_SELECTOR: string;
|
|
355
|
+
/**
|
|
356
|
+
* Check if the node is a component display name assignment expression
|
|
357
|
+
* @param node The AST node
|
|
358
|
+
* @returns `true` if the node is a component display name assignment
|
|
359
|
+
*/
|
|
360
|
+
declare function isDisplayNameAssignment(node: TSESTree.Node | _): node is TSESTree.AssignmentExpression;
|
|
361
|
+
|
|
362
|
+
declare function isFromReactLoose(node: TSESTree.Identifier | TSESTree.MemberExpression, name: string): boolean;
|
|
363
|
+
declare function isFromReactStrict(node: TSESTree.Identifier | TSESTree.MemberExpression, name: string, importSource: string, initialScope: Scope): boolean;
|
|
364
|
+
declare function isFromReact(name: string): (node: TSESTree.Identifier | TSESTree.MemberExpression, context: RuleContext) => boolean;
|
|
365
|
+
declare function isFromReactMemberLoose(node: TSESTree.MemberExpression, memberName: string, name: string): boolean;
|
|
366
|
+
declare function isFromReactMemberStrict(node: TSESTree.MemberExpression, memberName: string, name: string, importSource: string, initialScope: Scope): boolean;
|
|
367
|
+
declare function isFromReactMember(memberName: string, name: string): (node: TSESTree.MemberExpression, context: RuleContext) => boolean;
|
|
368
|
+
|
|
372
369
|
/**
|
|
373
370
|
* Check if an identifier is initialized from react
|
|
374
371
|
* @param name The top-level identifier's name
|
|
@@ -2424,4 +2421,4 @@ declare const isCreateRefCall: isCallFromReact.ReturnType;
|
|
|
2424
2421
|
declare const isForwardRefCall: isCallFromReact.ReturnType;
|
|
2425
2422
|
declare const isMemoCall: isCallFromReact.ReturnType;
|
|
2426
2423
|
|
|
2427
|
-
export { DEFAULT_COMPONENT_HINT, DISPLAY_NAME_ASSIGNMENT_SELECTOR, type ERClassComponent, type ERComponent, ERComponentFlag, ERComponentHint, type ERComponentKind, type EREffectKind, type EREffectPhaseKind, type ERFunctionComponent, type ERHook, type ERHookKind, type ERLifecyclePhaseKind, type ERPhaseKind, ERPhaseRelevance, type ERSemanticEntry, type ERSemanticNode, type ERStateKind, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier, getFunctionComponentIdentifier, hasNoneOrValidComponentName, isCallFromReact, isCallFromReactMember, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentName, isComponentWillUnmount, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isDisplayNameAssignment, isForwardRef, isForwardRefCall, isFromReact, isFromReactMember, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfRenderMethod, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInsideCreateElementProps, isInsideReactHook, isInsideRenderMethod, isInversePhase, isMemo, isMemoCall, isPureComponent, isReactAPICallWithName, isReactAPIWithName, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookName, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isThisSetState, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
|
|
2424
|
+
export { DEFAULT_COMPONENT_HINT, DISPLAY_NAME_ASSIGNMENT_SELECTOR, type ERClassComponent, type ERComponent, ERComponentFlag, ERComponentHint, type ERComponentKind, type EREffectKind, type EREffectPhaseKind, type ERFunctionComponent, type ERHook, type ERHookKind, type ERLifecyclePhaseKind, type ERPhaseKind, ERPhaseRelevance, type ERSemanticEntry, type ERSemanticNode, type ERStateKind, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier, getFunctionComponentIdentifier, hasNoneOrValidComponentName, hasValidHierarchy, isCallFromReact, isCallFromReactMember, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentName, isComponentWillUnmount, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isDisplayNameAssignment, isForwardRef, isForwardRefCall, isFromReact, isFromReactLoose, isFromReactMember, isFromReactMemberLoose, isFromReactMemberStrict, isFromReactStrict, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfRenderMethod, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInsideCreateElementProps, isInsideReactHook, isInsideRenderMethod, isInversePhase, isMemo, isMemoCall, isPureComponent, isReactAPICallWithName, isReactAPIWithName, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookName, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isThisSetState, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var AST8 = require('@eslint-react/ast');
|
|
4
4
|
var eff = require('@eslint-react/eff');
|
|
5
5
|
var JSX3 = require('@eslint-react/jsx');
|
|
6
6
|
var shared = require('@eslint-react/shared');
|
|
@@ -29,23 +29,12 @@ function _interopNamespace(e) {
|
|
|
29
29
|
return Object.freeze(n);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
var
|
|
32
|
+
var AST8__namespace = /*#__PURE__*/_interopNamespace(AST8);
|
|
33
33
|
var JSX3__namespace = /*#__PURE__*/_interopNamespace(JSX3);
|
|
34
34
|
var VAR__namespace = /*#__PURE__*/_interopNamespace(VAR);
|
|
35
35
|
var birecord__default = /*#__PURE__*/_interopDefault(birecord);
|
|
36
36
|
|
|
37
37
|
// src/component/component-collector.ts
|
|
38
|
-
var DISPLAY_NAME_ASSIGNMENT_SELECTOR = [
|
|
39
|
-
"AssignmentExpression",
|
|
40
|
-
"[type]",
|
|
41
|
-
"[operator='=']",
|
|
42
|
-
"[left.type='MemberExpression']",
|
|
43
|
-
"[left.property.name='displayName']"
|
|
44
|
-
].join("");
|
|
45
|
-
function isDisplayNameAssignment(node) {
|
|
46
|
-
if (node == null) return false;
|
|
47
|
-
return node.type === types.AST_NODE_TYPES.AssignmentExpression && node.operator === "=" && node.left.type === types.AST_NODE_TYPES.MemberExpression && node.left.property.type === types.AST_NODE_TYPES.Identifier && node.left.property.name === "displayName";
|
|
48
|
-
}
|
|
49
38
|
function getRequireExpressionArguments(node) {
|
|
50
39
|
return tsPattern.match(node).with({ type: types.AST_NODE_TYPES.CallExpression, arguments: tsPattern.P.select(), callee: { type: types.AST_NODE_TYPES.Identifier, name: "require" } }, eff.identity).with({ type: types.AST_NODE_TYPES.MemberExpression, object: tsPattern.P.select() }, getRequireExpressionArguments).otherwise(() => eff._);
|
|
51
40
|
}
|
|
@@ -64,7 +53,7 @@ function isInitializedFromReact(name, source, initialScope) {
|
|
|
64
53
|
}
|
|
65
54
|
const args = getRequireExpressionArguments(init);
|
|
66
55
|
const arg0 = args?.[0];
|
|
67
|
-
if (arg0 == null || !
|
|
56
|
+
if (arg0 == null || !AST8__namespace.isKindOfLiteral(arg0, "string")) {
|
|
68
57
|
return false;
|
|
69
58
|
}
|
|
70
59
|
return arg0.value === source || arg0.value.startsWith(`${source}/`);
|
|
@@ -73,65 +62,85 @@ function isInitializedFromReact(name, source, initialScope) {
|
|
|
73
62
|
}
|
|
74
63
|
|
|
75
64
|
// src/utils/is-from-react.ts
|
|
65
|
+
var defaultImportSource = shared.DEFAULT_ESLINT_REACT_SETTINGS.importSource;
|
|
66
|
+
function isFromReactLoose(node, name) {
|
|
67
|
+
if (node.type === types.AST_NODE_TYPES.MemberExpression) {
|
|
68
|
+
return node.object.type === types.AST_NODE_TYPES.Identifier && node.property.type === types.AST_NODE_TYPES.Identifier && node.property.name === name;
|
|
69
|
+
}
|
|
70
|
+
return node.name === name;
|
|
71
|
+
}
|
|
72
|
+
function isFromReactStrict(node, name, importSource, initialScope) {
|
|
73
|
+
if (node.type === types.AST_NODE_TYPES.MemberExpression) {
|
|
74
|
+
return node.object.type === types.AST_NODE_TYPES.Identifier && node.property.type === types.AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name, importSource, initialScope);
|
|
75
|
+
}
|
|
76
|
+
if (node.name === name) {
|
|
77
|
+
return isInitializedFromReact(name, importSource, initialScope);
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
76
81
|
function isFromReact(name) {
|
|
77
82
|
return (node, context) => {
|
|
78
|
-
const
|
|
79
|
-
if (!
|
|
80
|
-
|
|
81
|
-
return node.object.type === types.AST_NODE_TYPES.Identifier && node.property.type === types.AST_NODE_TYPES.Identifier && node.property.name === name;
|
|
82
|
-
}
|
|
83
|
-
return node.name === name;
|
|
84
|
-
}
|
|
85
|
-
const importSource = settings.importSource ?? shared.DEFAULT_ESLINT_REACT_SETTINGS.importSource;
|
|
86
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
87
|
-
if (node.type === types.AST_NODE_TYPES.MemberExpression) {
|
|
88
|
-
return node.object.type === types.AST_NODE_TYPES.Identifier && node.property.type === types.AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name, importSource, initialScope);
|
|
89
|
-
}
|
|
90
|
-
if (node.name === name) {
|
|
91
|
-
return isInitializedFromReact(name, importSource, initialScope);
|
|
92
|
-
}
|
|
93
|
-
return false;
|
|
83
|
+
const { importSource = defaultImportSource, strictImportCheck = false } = shared.unsafeDecodeSettings(context.settings);
|
|
84
|
+
if (!strictImportCheck) return isFromReactLoose(node, name);
|
|
85
|
+
return isFromReactStrict(node, name, importSource, context.sourceCode.getScope(node));
|
|
94
86
|
};
|
|
95
87
|
}
|
|
88
|
+
function isFromReactMemberLoose(node, memberName, name) {
|
|
89
|
+
const { object, property } = node;
|
|
90
|
+
if (property.type !== types.AST_NODE_TYPES.Identifier || property.name !== name) return false;
|
|
91
|
+
if (object.type === types.AST_NODE_TYPES.Identifier && object.name === memberName) return true;
|
|
92
|
+
if (object.type === types.AST_NODE_TYPES.MemberExpression && object.object.type === types.AST_NODE_TYPES.Identifier && object.property.type === types.AST_NODE_TYPES.Identifier) {
|
|
93
|
+
return object.property.name === memberName;
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
function isFromReactMemberStrict(node, memberName, name, importSource, initialScope) {
|
|
98
|
+
const { object, property } = node;
|
|
99
|
+
if (property.type !== types.AST_NODE_TYPES.Identifier || property.name !== name) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
if (object.type === types.AST_NODE_TYPES.Identifier && object.name === memberName) {
|
|
103
|
+
return isInitializedFromReact(object.name, importSource, initialScope);
|
|
104
|
+
}
|
|
105
|
+
if (object.type === types.AST_NODE_TYPES.MemberExpression && object.object.type === types.AST_NODE_TYPES.Identifier && isInitializedFromReact(object.object.name, importSource, initialScope) && object.property.type === types.AST_NODE_TYPES.Identifier) {
|
|
106
|
+
return object.property.name === memberName;
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
96
110
|
function isFromReactMember(memberName, name) {
|
|
97
111
|
return (node, context) => {
|
|
98
|
-
const
|
|
99
|
-
if (!
|
|
100
|
-
|
|
101
|
-
if (node.object.type === types.AST_NODE_TYPES.Identifier && node.object.name === memberName) return true;
|
|
102
|
-
if (node.object.type === types.AST_NODE_TYPES.MemberExpression && node.object.object.type === types.AST_NODE_TYPES.Identifier && node.object.property.type === types.AST_NODE_TYPES.Identifier) {
|
|
103
|
-
return node.object.property.name === memberName;
|
|
104
|
-
}
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
const importSource = settings.importSource ?? shared.DEFAULT_ESLINT_REACT_SETTINGS.importSource;
|
|
108
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
109
|
-
if (node.property.type !== types.AST_NODE_TYPES.Identifier || node.property.name !== name) {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
if (node.object.type === types.AST_NODE_TYPES.Identifier && node.object.name === memberName) {
|
|
113
|
-
return isInitializedFromReact(node.object.name, importSource, initialScope);
|
|
114
|
-
}
|
|
115
|
-
if (node.object.type === types.AST_NODE_TYPES.MemberExpression && node.object.object.type === types.AST_NODE_TYPES.Identifier && isInitializedFromReact(node.object.object.name, importSource, initialScope) && node.object.property.type === types.AST_NODE_TYPES.Identifier) {
|
|
116
|
-
return node.object.property.name === memberName;
|
|
117
|
-
}
|
|
118
|
-
return false;
|
|
112
|
+
const { importSource = defaultImportSource, strictImportCheck = false } = shared.unsafeDecodeSettings(context.settings);
|
|
113
|
+
if (!strictImportCheck) return isFromReactMemberLoose(node, memberName, name);
|
|
114
|
+
return isFromReactMemberStrict(node, memberName, name, importSource, context.sourceCode.getScope(node));
|
|
119
115
|
};
|
|
120
116
|
}
|
|
117
|
+
|
|
118
|
+
// src/utils/is-call-from-react.ts
|
|
121
119
|
function isCallFromReact(name) {
|
|
122
120
|
return eff.dual(2, (node, context) => {
|
|
123
121
|
if (node.type !== types.AST_NODE_TYPES.CallExpression) return false;
|
|
124
|
-
if (!
|
|
122
|
+
if (!AST8__namespace.isOneOf([types.AST_NODE_TYPES.Identifier, types.AST_NODE_TYPES.MemberExpression])(node.callee)) return false;
|
|
125
123
|
return isFromReact(name)(node.callee, context);
|
|
126
124
|
});
|
|
127
125
|
}
|
|
128
126
|
function isCallFromReactMember(pragmaMemberName, name) {
|
|
129
127
|
return eff.dual(2, (node, context) => {
|
|
130
128
|
if (node.type !== types.AST_NODE_TYPES.CallExpression) return false;
|
|
131
|
-
if (!
|
|
129
|
+
if (!AST8__namespace.is(types.AST_NODE_TYPES.MemberExpression)(node.callee)) return false;
|
|
132
130
|
return isFromReactMember(pragmaMemberName, name)(node.callee, context);
|
|
133
131
|
});
|
|
134
132
|
}
|
|
133
|
+
var DISPLAY_NAME_ASSIGNMENT_SELECTOR = [
|
|
134
|
+
"AssignmentExpression",
|
|
135
|
+
"[type]",
|
|
136
|
+
"[operator='=']",
|
|
137
|
+
"[left.type='MemberExpression']",
|
|
138
|
+
"[left.property.name='displayName']"
|
|
139
|
+
].join("");
|
|
140
|
+
function isDisplayNameAssignment(node) {
|
|
141
|
+
if (node == null) return false;
|
|
142
|
+
return node.type === types.AST_NODE_TYPES.AssignmentExpression && node.operator === "=" && node.left.type === types.AST_NODE_TYPES.MemberExpression && node.left.property.type === types.AST_NODE_TYPES.Identifier && node.left.property.name === "displayName";
|
|
143
|
+
}
|
|
135
144
|
|
|
136
145
|
// src/utils/is-react-api.ts
|
|
137
146
|
function isReactAPIWithName(name, member) {
|
|
@@ -163,21 +172,6 @@ var isCreateRefCall = isReactAPICallWithName("createRef");
|
|
|
163
172
|
var isForwardRefCall = isReactAPICallWithName("forwardRef");
|
|
164
173
|
var isMemoCall = isReactAPICallWithName("memo");
|
|
165
174
|
|
|
166
|
-
// src/element/hierarchy.ts
|
|
167
|
-
function isInsideCreateElementProps(node, context) {
|
|
168
|
-
const call = AST9__namespace.findParentNode(node, isCreateElementCall(context));
|
|
169
|
-
if (call == null) return false;
|
|
170
|
-
const prop = AST9__namespace.findParentNode(node, AST9__namespace.is(types.AST_NODE_TYPES.ObjectExpression));
|
|
171
|
-
if (prop == null) return false;
|
|
172
|
-
return prop === call.arguments[1];
|
|
173
|
-
}
|
|
174
|
-
function isChildrenOfCreateElement(node, context) {
|
|
175
|
-
const parent = node.parent;
|
|
176
|
-
if (parent == null || parent.type !== types.AST_NODE_TYPES.CallExpression) return false;
|
|
177
|
-
if (!isCreateElementCall(parent, context)) return false;
|
|
178
|
-
return parent.arguments.slice(2).some((arg) => arg === node);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
175
|
// src/hook/hook-name.ts
|
|
182
176
|
var RE_HOOK_NAME = /^use[A-Z\d]/u;
|
|
183
177
|
function isReactHookName(name) {
|
|
@@ -187,7 +181,7 @@ function isReactHookName(name) {
|
|
|
187
181
|
// src/hook/is.ts
|
|
188
182
|
function isReactHook(node) {
|
|
189
183
|
if (node == null) return eff._;
|
|
190
|
-
const id =
|
|
184
|
+
const id = AST8__namespace.getFunctionIdentifier(node);
|
|
191
185
|
return id?.name != null && isReactHookName(id.name);
|
|
192
186
|
}
|
|
193
187
|
function isReactHookCall(node) {
|
|
@@ -279,13 +273,13 @@ var isUseTransitionCall = eff.flip(isReactHookCallWithName)("useTransition");
|
|
|
279
273
|
|
|
280
274
|
// src/hook/hierarchy.ts
|
|
281
275
|
function isInsideReactHook(node) {
|
|
282
|
-
return isReactHook(
|
|
276
|
+
return isReactHook(AST8__namespace.findParentNode(node, AST8__namespace.isFunction));
|
|
283
277
|
}
|
|
284
278
|
function useHookCollector() {
|
|
285
279
|
const hooks = /* @__PURE__ */ new Map();
|
|
286
280
|
const functionEntries = [];
|
|
287
281
|
const onFunctionEnter = (node) => {
|
|
288
|
-
const id =
|
|
282
|
+
const id = AST8__namespace.getFunctionIdentifier(node);
|
|
289
283
|
const key = shared.getId();
|
|
290
284
|
const name = id?.name;
|
|
291
285
|
if (name != null && isReactHookName(name)) {
|
|
@@ -381,7 +375,7 @@ function isComponentWrapperCall(node, context) {
|
|
|
381
375
|
return isMemoCall(node, context) || isForwardRefCall(node, context) || isReactHookCallWithNameLoose(node)("useCallback");
|
|
382
376
|
}
|
|
383
377
|
function getFunctionComponentIdentifier(node, context) {
|
|
384
|
-
const functionId =
|
|
378
|
+
const functionId = AST8__namespace.getFunctionIdentifier(node);
|
|
385
379
|
if (functionId != null) {
|
|
386
380
|
return functionId;
|
|
387
381
|
}
|
|
@@ -394,6 +388,33 @@ function getFunctionComponentIdentifier(node, context) {
|
|
|
394
388
|
}
|
|
395
389
|
return eff._;
|
|
396
390
|
}
|
|
391
|
+
var RE_COMPONENT_NAME = /^_?[A-Z]/u;
|
|
392
|
+
function getComponentNameFromIdentifier(node) {
|
|
393
|
+
if (node == null) return eff._;
|
|
394
|
+
return Array.isArray(node) ? node.map((n) => n.name).join(".") : node.name;
|
|
395
|
+
}
|
|
396
|
+
function isComponentName(name) {
|
|
397
|
+
return RE_COMPONENT_NAME.test(name);
|
|
398
|
+
}
|
|
399
|
+
function hasNoneOrValidComponentName(node, context) {
|
|
400
|
+
const id = getFunctionComponentIdentifier(node, context);
|
|
401
|
+
if (id == null) return true;
|
|
402
|
+
const name = Array.isArray(id) ? id.at(-1)?.name : id.name;
|
|
403
|
+
return name != null && isComponentName(name);
|
|
404
|
+
}
|
|
405
|
+
function isInsideCreateElementProps(node, context) {
|
|
406
|
+
const call = AST8__namespace.findParentNode(node, isCreateElementCall(context));
|
|
407
|
+
if (call == null) return false;
|
|
408
|
+
const prop = AST8__namespace.findParentNode(node, AST8__namespace.is(types.AST_NODE_TYPES.ObjectExpression));
|
|
409
|
+
if (prop == null) return false;
|
|
410
|
+
return prop === call.arguments[1];
|
|
411
|
+
}
|
|
412
|
+
function isChildrenOfCreateElement(node, context) {
|
|
413
|
+
const parent = node.parent;
|
|
414
|
+
if (parent == null || parent.type !== types.AST_NODE_TYPES.CallExpression) return false;
|
|
415
|
+
if (!isCreateElementCall(parent, context)) return false;
|
|
416
|
+
return parent.arguments.slice(2).some((arg) => arg === node);
|
|
417
|
+
}
|
|
397
418
|
function isClassComponent(node) {
|
|
398
419
|
if ("superClass" in node && node.superClass != null) {
|
|
399
420
|
const re = /^(?:Pure)?Component$/u;
|
|
@@ -421,28 +442,28 @@ function isPureComponent(node) {
|
|
|
421
442
|
|
|
422
443
|
// src/component/component-lifecycle.ts
|
|
423
444
|
function isComponentDidMount(node) {
|
|
424
|
-
return
|
|
445
|
+
return AST8__namespace.isMethodOrProperty(node) && node.key.type === types.AST_NODE_TYPES.Identifier && node.key.name === "componentDidMount";
|
|
425
446
|
}
|
|
426
447
|
function isComponentWillUnmount(node) {
|
|
427
|
-
return
|
|
448
|
+
return AST8__namespace.isMethodOrProperty(node) && node.key.type === types.AST_NODE_TYPES.Identifier && node.key.name === "componentWillUnmount";
|
|
428
449
|
}
|
|
429
450
|
function isComponentDidCatch(node) {
|
|
430
|
-
return
|
|
451
|
+
return AST8__namespace.isMethodOrProperty(node) && !node.static && node.key.type === types.AST_NODE_TYPES.Identifier && node.key.name === "componentDidCatch";
|
|
431
452
|
}
|
|
432
453
|
function isGetDerivedStateFromError(node) {
|
|
433
|
-
return
|
|
454
|
+
return AST8__namespace.isMethodOrProperty(node) && node.static && node.key.type === types.AST_NODE_TYPES.Identifier && node.key.name === "getDerivedStateFromError";
|
|
434
455
|
}
|
|
435
456
|
function isGetDerivedStateFromProps(node) {
|
|
436
|
-
return
|
|
457
|
+
return AST8__namespace.isMethodOrProperty(node) && node.static && node.key.type === types.AST_NODE_TYPES.Identifier && node.key.name === "getDerivedStateFromProps";
|
|
437
458
|
}
|
|
438
459
|
function isFunctionOfComponentDidMount(node) {
|
|
439
|
-
return
|
|
460
|
+
return AST8__namespace.isFunction(node) && isComponentDidMount(node.parent) && node.parent.value === node;
|
|
440
461
|
}
|
|
441
462
|
function isFunctionOfComponentWillUnmount(node) {
|
|
442
|
-
return
|
|
463
|
+
return AST8__namespace.isFunction(node) && isComponentWillUnmount(node.parent) && node.parent.value === node;
|
|
443
464
|
}
|
|
444
465
|
function isRenderMethodLike(node) {
|
|
445
|
-
return
|
|
466
|
+
return AST8__namespace.isMethodOrProperty(node) && node.key.type === types.AST_NODE_TYPES.Identifier && node.key.name === "render" && node.parent.parent.type === types.AST_NODE_TYPES.ClassDeclaration;
|
|
446
467
|
}
|
|
447
468
|
function isFunctionOfRenderMethod(node) {
|
|
448
469
|
if (!isRenderMethodLike(node.parent)) {
|
|
@@ -451,21 +472,46 @@ function isFunctionOfRenderMethod(node) {
|
|
|
451
472
|
return isClassComponent(node.parent.parent.parent);
|
|
452
473
|
}
|
|
453
474
|
function isInsideRenderMethod(node) {
|
|
454
|
-
return
|
|
475
|
+
return AST8__namespace.findParentNode(node, (node2) => isRenderMethodLike(node2) && isClassComponent(node2.parent.parent)) != null;
|
|
455
476
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
477
|
+
|
|
478
|
+
// src/component/hierarchy.ts
|
|
479
|
+
function hasValidHierarchy(node, context, hint) {
|
|
480
|
+
if (isChildrenOfCreateElement(node, context) || isFunctionOfRenderMethod(node)) {
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
if (hint & ERComponentHint.SkipMapCallback && AST8__namespace.isMapCallLoose(node.parent)) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
if (hint & ERComponentHint.SkipObjectMethod && isFunctionOfObjectMethod(node.parent)) {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
if (hint & ERComponentHint.SkipClassMethod && isFunctionOfClassMethod(node.parent)) {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
if (hint & ERComponentHint.SkipClassProperty && isFunctionOfClassProperty(node.parent)) {
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
const boundaryNode = AST8__namespace.findParentNode(
|
|
496
|
+
node,
|
|
497
|
+
AST8__namespace.isOneOf([
|
|
498
|
+
types.AST_NODE_TYPES.JSXExpressionContainer,
|
|
499
|
+
types.AST_NODE_TYPES.ArrowFunctionExpression,
|
|
500
|
+
types.AST_NODE_TYPES.FunctionExpression,
|
|
501
|
+
types.AST_NODE_TYPES.Property,
|
|
502
|
+
types.AST_NODE_TYPES.ClassBody
|
|
503
|
+
])
|
|
504
|
+
);
|
|
505
|
+
return boundaryNode == null || boundaryNode.type !== types.AST_NODE_TYPES.JSXExpressionContainer;
|
|
460
506
|
}
|
|
461
|
-
function
|
|
462
|
-
return
|
|
507
|
+
function isFunctionOfClassMethod(node) {
|
|
508
|
+
return (node.type === types.AST_NODE_TYPES.FunctionExpression || node.type === types.AST_NODE_TYPES.ArrowFunctionExpression) && node.parent.type === types.AST_NODE_TYPES.MethodDefinition;
|
|
463
509
|
}
|
|
464
|
-
function
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
return
|
|
510
|
+
function isFunctionOfClassProperty(node) {
|
|
511
|
+
return (node.type === types.AST_NODE_TYPES.FunctionExpression || node.type === types.AST_NODE_TYPES.ArrowFunctionExpression) && node.parent.type === types.AST_NODE_TYPES.Property;
|
|
512
|
+
}
|
|
513
|
+
function isFunctionOfObjectMethod(node) {
|
|
514
|
+
return (node.type === types.AST_NODE_TYPES.FunctionExpression || node.type === types.AST_NODE_TYPES.ArrowFunctionExpression) && node.parent.type === types.AST_NODE_TYPES.Property && node.parent.parent.type === types.AST_NODE_TYPES.ObjectExpression;
|
|
469
515
|
}
|
|
470
516
|
|
|
471
517
|
// src/component/component-collector.ts
|
|
@@ -483,7 +529,7 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT, options =
|
|
|
483
529
|
const entry = functionEntries.at(-1);
|
|
484
530
|
if (entry == null) return;
|
|
485
531
|
if (!entry.isComponent) return functionEntries.pop();
|
|
486
|
-
const shouldDrop =
|
|
532
|
+
const shouldDrop = AST8__namespace.getNestedReturnStatements(entry.node.body).slice().reverse().some((r) => {
|
|
487
533
|
return context.sourceCode.getScope(r).block === entry.node && r.argument != null && !JSX3__namespace.isJSXValue(r.argument, jsxCtx, hint);
|
|
488
534
|
});
|
|
489
535
|
if (shouldDrop) {
|
|
@@ -510,7 +556,7 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT, options =
|
|
|
510
556
|
const { body } = entry.node;
|
|
511
557
|
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX3__namespace.isJSXValue(body, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
512
558
|
if (!isComponent) return;
|
|
513
|
-
const initPath =
|
|
559
|
+
const initPath = AST8__namespace.getFunctionInitPath(entry.node);
|
|
514
560
|
const id = getFunctionComponentIdentifier(entry.node, context);
|
|
515
561
|
const name = getComponentNameFromIdentifier(id);
|
|
516
562
|
const key = shared.getId();
|
|
@@ -551,7 +597,7 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT, options =
|
|
|
551
597
|
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX3__namespace.isJSXValue(node.argument, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
552
598
|
if (!isComponent) return;
|
|
553
599
|
entry.isComponent = true;
|
|
554
|
-
const initPath =
|
|
600
|
+
const initPath = AST8__namespace.getFunctionInitPath(entry.node);
|
|
555
601
|
const id = getFunctionComponentIdentifier(entry.node, context);
|
|
556
602
|
const name = getComponentNameFromIdentifier(id);
|
|
557
603
|
components.set(entry.key, {
|
|
@@ -570,40 +616,12 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT, options =
|
|
|
570
616
|
};
|
|
571
617
|
return { ctx, listeners };
|
|
572
618
|
}
|
|
573
|
-
function hasValidHierarchy(node, context, hint) {
|
|
574
|
-
if (isChildrenOfCreateElement(node, context) || isFunctionOfRenderMethod(node)) {
|
|
575
|
-
return false;
|
|
576
|
-
}
|
|
577
|
-
if (hint & ERComponentHint.SkipMapCallback && AST9__namespace.isMapCallLoose(node.parent)) {
|
|
578
|
-
return false;
|
|
579
|
-
}
|
|
580
|
-
if (hint & ERComponentHint.SkipObjectMethod && AST9__namespace.isFunctionOfObjectMethod(node.parent)) {
|
|
581
|
-
return false;
|
|
582
|
-
}
|
|
583
|
-
if (hint & ERComponentHint.SkipClassMethod && AST9__namespace.isFunctionOfClassMethod(node.parent)) {
|
|
584
|
-
return false;
|
|
585
|
-
}
|
|
586
|
-
if (hint & ERComponentHint.SkipClassProperty && AST9__namespace.isFunctionOfClassProperty(node.parent)) {
|
|
587
|
-
return false;
|
|
588
|
-
}
|
|
589
|
-
const boundaryNode = AST9__namespace.findParentNode(
|
|
590
|
-
node,
|
|
591
|
-
AST9__namespace.isOneOf([
|
|
592
|
-
types.AST_NODE_TYPES.JSXExpressionContainer,
|
|
593
|
-
types.AST_NODE_TYPES.ArrowFunctionExpression,
|
|
594
|
-
types.AST_NODE_TYPES.FunctionExpression,
|
|
595
|
-
types.AST_NODE_TYPES.Property,
|
|
596
|
-
types.AST_NODE_TYPES.ClassBody
|
|
597
|
-
])
|
|
598
|
-
);
|
|
599
|
-
return boundaryNode == null || boundaryNode.type !== types.AST_NODE_TYPES.JSXExpressionContainer;
|
|
600
|
-
}
|
|
601
619
|
function getComponentFlag(initPath) {
|
|
602
620
|
let flag = ERComponentFlag.None;
|
|
603
|
-
if (initPath != null &&
|
|
621
|
+
if (initPath != null && AST8__namespace.hasCallInFunctionInitPath("memo", initPath)) {
|
|
604
622
|
flag |= ERComponentFlag.Memo;
|
|
605
623
|
}
|
|
606
|
-
if (initPath != null &&
|
|
624
|
+
if (initPath != null && AST8__namespace.hasCallInFunctionInitPath("forwardRef", initPath)) {
|
|
607
625
|
flag |= ERComponentFlag.ForwardRef;
|
|
608
626
|
}
|
|
609
627
|
return flag;
|
|
@@ -620,7 +638,7 @@ function useComponentCollectorLegacy() {
|
|
|
620
638
|
if (!isClassComponent(node)) {
|
|
621
639
|
return;
|
|
622
640
|
}
|
|
623
|
-
const id =
|
|
641
|
+
const id = AST8__namespace.getClassIdentifier(node);
|
|
624
642
|
const key = shared.getId();
|
|
625
643
|
const flag = isPureComponent(node) ? ERComponentFlag.PureComponent : ERComponentFlag.None;
|
|
626
644
|
components.set(
|
|
@@ -653,7 +671,7 @@ var ERPhaseRelevance = birecord__default.default({
|
|
|
653
671
|
var isInversePhase = eff.dual(2, (a, b) => ERPhaseRelevance.get(a) === b);
|
|
654
672
|
function isRenderFunctionLoose(node, context) {
|
|
655
673
|
const { body, parent } = node;
|
|
656
|
-
if (
|
|
674
|
+
if (AST8__namespace.getFunctionIdentifier(node)?.name.startsWith("render")) {
|
|
657
675
|
return parent.type === types.AST_NODE_TYPES.JSXExpressionContainer && parent.parent.type === types.AST_NODE_TYPES.JSXAttribute && parent.parent.name.type === types.AST_NODE_TYPES.JSXIdentifier && parent.parent.name.name.startsWith("render");
|
|
658
676
|
}
|
|
659
677
|
return JSX3__namespace.isJSXValue(
|
|
@@ -668,7 +686,7 @@ function isRenderPropLoose(node, context) {
|
|
|
668
686
|
if (node.name.type !== types.AST_NODE_TYPES.JSXIdentifier) {
|
|
669
687
|
return false;
|
|
670
688
|
}
|
|
671
|
-
return node.name.name.startsWith("render") && node.value?.type === types.AST_NODE_TYPES.JSXExpressionContainer &&
|
|
689
|
+
return node.name.name.startsWith("render") && node.value?.type === types.AST_NODE_TYPES.JSXExpressionContainer && AST8__namespace.isFunction(node.value.expression) && isRenderFunctionLoose(node.value.expression, context);
|
|
672
690
|
}
|
|
673
691
|
function isDirectValueOfRenderPropertyLoose(node) {
|
|
674
692
|
const matching = (node2) => {
|
|
@@ -680,7 +698,7 @@ function isDeclaredInRenderPropLoose(node) {
|
|
|
680
698
|
if (isDirectValueOfRenderPropertyLoose(node)) {
|
|
681
699
|
return true;
|
|
682
700
|
}
|
|
683
|
-
const parent =
|
|
701
|
+
const parent = AST8__namespace.findParentNode(node, AST8__namespace.is(types.AST_NODE_TYPES.JSXExpressionContainer))?.parent;
|
|
684
702
|
if (parent?.type !== types.AST_NODE_TYPES.JSXAttribute) {
|
|
685
703
|
return false;
|
|
686
704
|
}
|
|
@@ -688,16 +706,16 @@ function isDeclaredInRenderPropLoose(node) {
|
|
|
688
706
|
}
|
|
689
707
|
function isThisSetState(node) {
|
|
690
708
|
const { callee } = node;
|
|
691
|
-
return callee.type === types.AST_NODE_TYPES.MemberExpression &&
|
|
709
|
+
return callee.type === types.AST_NODE_TYPES.MemberExpression && AST8__namespace.isThisExpression(callee.object) && callee.property.type === types.AST_NODE_TYPES.Identifier && callee.property.name === "setState";
|
|
692
710
|
}
|
|
693
711
|
function isFunctionOfUseEffectSetup(node) {
|
|
694
712
|
if (node == null) return eff._;
|
|
695
713
|
return node.parent?.type === types.AST_NODE_TYPES.CallExpression && node.parent.callee !== node && node.parent.callee.type === types.AST_NODE_TYPES.Identifier && node.parent.arguments.at(0) === node && isUseEffectCallLoose(node.parent);
|
|
696
714
|
}
|
|
697
715
|
function isFunctionOfUseEffectCleanup(node) {
|
|
698
|
-
const nearReturn =
|
|
699
|
-
const nearFunction =
|
|
700
|
-
const nearFunctionOfReturn =
|
|
716
|
+
const nearReturn = AST8__namespace.findParentNode(node, AST8__namespace.is(types.AST_NODE_TYPES.ReturnStatement));
|
|
717
|
+
const nearFunction = AST8__namespace.findParentNode(node, AST8__namespace.isFunction);
|
|
718
|
+
const nearFunctionOfReturn = AST8__namespace.findParentNode(nearReturn, AST8__namespace.isFunction);
|
|
701
719
|
return nearFunction === nearFunctionOfReturn && isFunctionOfUseEffectSetup(nearFunction);
|
|
702
720
|
}
|
|
703
721
|
|
|
@@ -711,6 +729,7 @@ exports.RE_HOOK_NAME = RE_HOOK_NAME;
|
|
|
711
729
|
exports.getComponentNameFromIdentifier = getComponentNameFromIdentifier;
|
|
712
730
|
exports.getFunctionComponentIdentifier = getFunctionComponentIdentifier;
|
|
713
731
|
exports.hasNoneOrValidComponentName = hasNoneOrValidComponentName;
|
|
732
|
+
exports.hasValidHierarchy = hasValidHierarchy;
|
|
714
733
|
exports.isCallFromReact = isCallFromReact;
|
|
715
734
|
exports.isCallFromReactMember = isCallFromReactMember;
|
|
716
735
|
exports.isChildrenCount = isChildrenCount;
|
|
@@ -743,7 +762,11 @@ exports.isDisplayNameAssignment = isDisplayNameAssignment;
|
|
|
743
762
|
exports.isForwardRef = isForwardRef;
|
|
744
763
|
exports.isForwardRefCall = isForwardRefCall;
|
|
745
764
|
exports.isFromReact = isFromReact;
|
|
765
|
+
exports.isFromReactLoose = isFromReactLoose;
|
|
746
766
|
exports.isFromReactMember = isFromReactMember;
|
|
767
|
+
exports.isFromReactMemberLoose = isFromReactMemberLoose;
|
|
768
|
+
exports.isFromReactMemberStrict = isFromReactMemberStrict;
|
|
769
|
+
exports.isFromReactStrict = isFromReactStrict;
|
|
747
770
|
exports.isFunctionOfComponentDidMount = isFunctionOfComponentDidMount;
|
|
748
771
|
exports.isFunctionOfComponentWillUnmount = isFunctionOfComponentWillUnmount;
|
|
749
772
|
exports.isFunctionOfRenderMethod = isFunctionOfRenderMethod;
|
package/dist/index.mjs
CHANGED
|
@@ -1,24 +1,13 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as AST8 from '@eslint-react/ast';
|
|
2
2
|
import { flip, dual, constFalse, identity, _ } from '@eslint-react/eff';
|
|
3
3
|
import * as JSX3 from '@eslint-react/jsx';
|
|
4
|
-
import {
|
|
4
|
+
import { DEFAULT_ESLINT_REACT_SETTINGS, unsafeDecodeSettings, getId } from '@eslint-react/shared';
|
|
5
5
|
import { AST_NODE_TYPES } from '@typescript-eslint/types';
|
|
6
6
|
import * as VAR from '@eslint-react/var';
|
|
7
7
|
import { match, P } from 'ts-pattern';
|
|
8
8
|
import birecord from 'birecord';
|
|
9
9
|
|
|
10
10
|
// src/component/component-collector.ts
|
|
11
|
-
var DISPLAY_NAME_ASSIGNMENT_SELECTOR = [
|
|
12
|
-
"AssignmentExpression",
|
|
13
|
-
"[type]",
|
|
14
|
-
"[operator='=']",
|
|
15
|
-
"[left.type='MemberExpression']",
|
|
16
|
-
"[left.property.name='displayName']"
|
|
17
|
-
].join("");
|
|
18
|
-
function isDisplayNameAssignment(node) {
|
|
19
|
-
if (node == null) return false;
|
|
20
|
-
return node.type === AST_NODE_TYPES.AssignmentExpression && node.operator === "=" && node.left.type === AST_NODE_TYPES.MemberExpression && node.left.property.type === AST_NODE_TYPES.Identifier && node.left.property.name === "displayName";
|
|
21
|
-
}
|
|
22
11
|
function getRequireExpressionArguments(node) {
|
|
23
12
|
return match(node).with({ type: AST_NODE_TYPES.CallExpression, arguments: P.select(), callee: { type: AST_NODE_TYPES.Identifier, name: "require" } }, identity).with({ type: AST_NODE_TYPES.MemberExpression, object: P.select() }, getRequireExpressionArguments).otherwise(() => _);
|
|
24
13
|
}
|
|
@@ -37,7 +26,7 @@ function isInitializedFromReact(name, source, initialScope) {
|
|
|
37
26
|
}
|
|
38
27
|
const args = getRequireExpressionArguments(init);
|
|
39
28
|
const arg0 = args?.[0];
|
|
40
|
-
if (arg0 == null || !
|
|
29
|
+
if (arg0 == null || !AST8.isKindOfLiteral(arg0, "string")) {
|
|
41
30
|
return false;
|
|
42
31
|
}
|
|
43
32
|
return arg0.value === source || arg0.value.startsWith(`${source}/`);
|
|
@@ -46,65 +35,85 @@ function isInitializedFromReact(name, source, initialScope) {
|
|
|
46
35
|
}
|
|
47
36
|
|
|
48
37
|
// src/utils/is-from-react.ts
|
|
38
|
+
var defaultImportSource = DEFAULT_ESLINT_REACT_SETTINGS.importSource;
|
|
39
|
+
function isFromReactLoose(node, name) {
|
|
40
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
41
|
+
return node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === name;
|
|
42
|
+
}
|
|
43
|
+
return node.name === name;
|
|
44
|
+
}
|
|
45
|
+
function isFromReactStrict(node, name, importSource, initialScope) {
|
|
46
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
47
|
+
return node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name, importSource, initialScope);
|
|
48
|
+
}
|
|
49
|
+
if (node.name === name) {
|
|
50
|
+
return isInitializedFromReact(name, importSource, initialScope);
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
49
54
|
function isFromReact(name) {
|
|
50
55
|
return (node, context) => {
|
|
51
|
-
const
|
|
52
|
-
if (!
|
|
53
|
-
|
|
54
|
-
return node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === name;
|
|
55
|
-
}
|
|
56
|
-
return node.name === name;
|
|
57
|
-
}
|
|
58
|
-
const importSource = settings.importSource ?? DEFAULT_ESLINT_REACT_SETTINGS.importSource;
|
|
59
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
60
|
-
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
61
|
-
return node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name, importSource, initialScope);
|
|
62
|
-
}
|
|
63
|
-
if (node.name === name) {
|
|
64
|
-
return isInitializedFromReact(name, importSource, initialScope);
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
56
|
+
const { importSource = defaultImportSource, strictImportCheck = false } = unsafeDecodeSettings(context.settings);
|
|
57
|
+
if (!strictImportCheck) return isFromReactLoose(node, name);
|
|
58
|
+
return isFromReactStrict(node, name, importSource, context.sourceCode.getScope(node));
|
|
67
59
|
};
|
|
68
60
|
}
|
|
61
|
+
function isFromReactMemberLoose(node, memberName, name) {
|
|
62
|
+
const { object, property } = node;
|
|
63
|
+
if (property.type !== AST_NODE_TYPES.Identifier || property.name !== name) return false;
|
|
64
|
+
if (object.type === AST_NODE_TYPES.Identifier && object.name === memberName) return true;
|
|
65
|
+
if (object.type === AST_NODE_TYPES.MemberExpression && object.object.type === AST_NODE_TYPES.Identifier && object.property.type === AST_NODE_TYPES.Identifier) {
|
|
66
|
+
return object.property.name === memberName;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
function isFromReactMemberStrict(node, memberName, name, importSource, initialScope) {
|
|
71
|
+
const { object, property } = node;
|
|
72
|
+
if (property.type !== AST_NODE_TYPES.Identifier || property.name !== name) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
if (object.type === AST_NODE_TYPES.Identifier && object.name === memberName) {
|
|
76
|
+
return isInitializedFromReact(object.name, importSource, initialScope);
|
|
77
|
+
}
|
|
78
|
+
if (object.type === AST_NODE_TYPES.MemberExpression && object.object.type === AST_NODE_TYPES.Identifier && isInitializedFromReact(object.object.name, importSource, initialScope) && object.property.type === AST_NODE_TYPES.Identifier) {
|
|
79
|
+
return object.property.name === memberName;
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
69
83
|
function isFromReactMember(memberName, name) {
|
|
70
84
|
return (node, context) => {
|
|
71
|
-
const
|
|
72
|
-
if (!
|
|
73
|
-
|
|
74
|
-
if (node.object.type === AST_NODE_TYPES.Identifier && node.object.name === memberName) return true;
|
|
75
|
-
if (node.object.type === AST_NODE_TYPES.MemberExpression && node.object.object.type === AST_NODE_TYPES.Identifier && node.object.property.type === AST_NODE_TYPES.Identifier) {
|
|
76
|
-
return node.object.property.name === memberName;
|
|
77
|
-
}
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
const importSource = settings.importSource ?? DEFAULT_ESLINT_REACT_SETTINGS.importSource;
|
|
81
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
82
|
-
if (node.property.type !== AST_NODE_TYPES.Identifier || node.property.name !== name) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
if (node.object.type === AST_NODE_TYPES.Identifier && node.object.name === memberName) {
|
|
86
|
-
return isInitializedFromReact(node.object.name, importSource, initialScope);
|
|
87
|
-
}
|
|
88
|
-
if (node.object.type === AST_NODE_TYPES.MemberExpression && node.object.object.type === AST_NODE_TYPES.Identifier && isInitializedFromReact(node.object.object.name, importSource, initialScope) && node.object.property.type === AST_NODE_TYPES.Identifier) {
|
|
89
|
-
return node.object.property.name === memberName;
|
|
90
|
-
}
|
|
91
|
-
return false;
|
|
85
|
+
const { importSource = defaultImportSource, strictImportCheck = false } = unsafeDecodeSettings(context.settings);
|
|
86
|
+
if (!strictImportCheck) return isFromReactMemberLoose(node, memberName, name);
|
|
87
|
+
return isFromReactMemberStrict(node, memberName, name, importSource, context.sourceCode.getScope(node));
|
|
92
88
|
};
|
|
93
89
|
}
|
|
90
|
+
|
|
91
|
+
// src/utils/is-call-from-react.ts
|
|
94
92
|
function isCallFromReact(name) {
|
|
95
93
|
return dual(2, (node, context) => {
|
|
96
94
|
if (node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
97
|
-
if (!
|
|
95
|
+
if (!AST8.isOneOf([AST_NODE_TYPES.Identifier, AST_NODE_TYPES.MemberExpression])(node.callee)) return false;
|
|
98
96
|
return isFromReact(name)(node.callee, context);
|
|
99
97
|
});
|
|
100
98
|
}
|
|
101
99
|
function isCallFromReactMember(pragmaMemberName, name) {
|
|
102
100
|
return dual(2, (node, context) => {
|
|
103
101
|
if (node.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
104
|
-
if (!
|
|
102
|
+
if (!AST8.is(AST_NODE_TYPES.MemberExpression)(node.callee)) return false;
|
|
105
103
|
return isFromReactMember(pragmaMemberName, name)(node.callee, context);
|
|
106
104
|
});
|
|
107
105
|
}
|
|
106
|
+
var DISPLAY_NAME_ASSIGNMENT_SELECTOR = [
|
|
107
|
+
"AssignmentExpression",
|
|
108
|
+
"[type]",
|
|
109
|
+
"[operator='=']",
|
|
110
|
+
"[left.type='MemberExpression']",
|
|
111
|
+
"[left.property.name='displayName']"
|
|
112
|
+
].join("");
|
|
113
|
+
function isDisplayNameAssignment(node) {
|
|
114
|
+
if (node == null) return false;
|
|
115
|
+
return node.type === AST_NODE_TYPES.AssignmentExpression && node.operator === "=" && node.left.type === AST_NODE_TYPES.MemberExpression && node.left.property.type === AST_NODE_TYPES.Identifier && node.left.property.name === "displayName";
|
|
116
|
+
}
|
|
108
117
|
|
|
109
118
|
// src/utils/is-react-api.ts
|
|
110
119
|
function isReactAPIWithName(name, member) {
|
|
@@ -136,21 +145,6 @@ var isCreateRefCall = isReactAPICallWithName("createRef");
|
|
|
136
145
|
var isForwardRefCall = isReactAPICallWithName("forwardRef");
|
|
137
146
|
var isMemoCall = isReactAPICallWithName("memo");
|
|
138
147
|
|
|
139
|
-
// src/element/hierarchy.ts
|
|
140
|
-
function isInsideCreateElementProps(node, context) {
|
|
141
|
-
const call = AST9.findParentNode(node, isCreateElementCall(context));
|
|
142
|
-
if (call == null) return false;
|
|
143
|
-
const prop = AST9.findParentNode(node, AST9.is(AST_NODE_TYPES.ObjectExpression));
|
|
144
|
-
if (prop == null) return false;
|
|
145
|
-
return prop === call.arguments[1];
|
|
146
|
-
}
|
|
147
|
-
function isChildrenOfCreateElement(node, context) {
|
|
148
|
-
const parent = node.parent;
|
|
149
|
-
if (parent == null || parent.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
150
|
-
if (!isCreateElementCall(parent, context)) return false;
|
|
151
|
-
return parent.arguments.slice(2).some((arg) => arg === node);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
148
|
// src/hook/hook-name.ts
|
|
155
149
|
var RE_HOOK_NAME = /^use[A-Z\d]/u;
|
|
156
150
|
function isReactHookName(name) {
|
|
@@ -160,7 +154,7 @@ function isReactHookName(name) {
|
|
|
160
154
|
// src/hook/is.ts
|
|
161
155
|
function isReactHook(node) {
|
|
162
156
|
if (node == null) return _;
|
|
163
|
-
const id =
|
|
157
|
+
const id = AST8.getFunctionIdentifier(node);
|
|
164
158
|
return id?.name != null && isReactHookName(id.name);
|
|
165
159
|
}
|
|
166
160
|
function isReactHookCall(node) {
|
|
@@ -252,13 +246,13 @@ var isUseTransitionCall = flip(isReactHookCallWithName)("useTransition");
|
|
|
252
246
|
|
|
253
247
|
// src/hook/hierarchy.ts
|
|
254
248
|
function isInsideReactHook(node) {
|
|
255
|
-
return isReactHook(
|
|
249
|
+
return isReactHook(AST8.findParentNode(node, AST8.isFunction));
|
|
256
250
|
}
|
|
257
251
|
function useHookCollector() {
|
|
258
252
|
const hooks = /* @__PURE__ */ new Map();
|
|
259
253
|
const functionEntries = [];
|
|
260
254
|
const onFunctionEnter = (node) => {
|
|
261
|
-
const id =
|
|
255
|
+
const id = AST8.getFunctionIdentifier(node);
|
|
262
256
|
const key = getId();
|
|
263
257
|
const name = id?.name;
|
|
264
258
|
if (name != null && isReactHookName(name)) {
|
|
@@ -354,7 +348,7 @@ function isComponentWrapperCall(node, context) {
|
|
|
354
348
|
return isMemoCall(node, context) || isForwardRefCall(node, context) || isReactHookCallWithNameLoose(node)("useCallback");
|
|
355
349
|
}
|
|
356
350
|
function getFunctionComponentIdentifier(node, context) {
|
|
357
|
-
const functionId =
|
|
351
|
+
const functionId = AST8.getFunctionIdentifier(node);
|
|
358
352
|
if (functionId != null) {
|
|
359
353
|
return functionId;
|
|
360
354
|
}
|
|
@@ -367,6 +361,33 @@ function getFunctionComponentIdentifier(node, context) {
|
|
|
367
361
|
}
|
|
368
362
|
return _;
|
|
369
363
|
}
|
|
364
|
+
var RE_COMPONENT_NAME = /^_?[A-Z]/u;
|
|
365
|
+
function getComponentNameFromIdentifier(node) {
|
|
366
|
+
if (node == null) return _;
|
|
367
|
+
return Array.isArray(node) ? node.map((n) => n.name).join(".") : node.name;
|
|
368
|
+
}
|
|
369
|
+
function isComponentName(name) {
|
|
370
|
+
return RE_COMPONENT_NAME.test(name);
|
|
371
|
+
}
|
|
372
|
+
function hasNoneOrValidComponentName(node, context) {
|
|
373
|
+
const id = getFunctionComponentIdentifier(node, context);
|
|
374
|
+
if (id == null) return true;
|
|
375
|
+
const name = Array.isArray(id) ? id.at(-1)?.name : id.name;
|
|
376
|
+
return name != null && isComponentName(name);
|
|
377
|
+
}
|
|
378
|
+
function isInsideCreateElementProps(node, context) {
|
|
379
|
+
const call = AST8.findParentNode(node, isCreateElementCall(context));
|
|
380
|
+
if (call == null) return false;
|
|
381
|
+
const prop = AST8.findParentNode(node, AST8.is(AST_NODE_TYPES.ObjectExpression));
|
|
382
|
+
if (prop == null) return false;
|
|
383
|
+
return prop === call.arguments[1];
|
|
384
|
+
}
|
|
385
|
+
function isChildrenOfCreateElement(node, context) {
|
|
386
|
+
const parent = node.parent;
|
|
387
|
+
if (parent == null || parent.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
388
|
+
if (!isCreateElementCall(parent, context)) return false;
|
|
389
|
+
return parent.arguments.slice(2).some((arg) => arg === node);
|
|
390
|
+
}
|
|
370
391
|
function isClassComponent(node) {
|
|
371
392
|
if ("superClass" in node && node.superClass != null) {
|
|
372
393
|
const re = /^(?:Pure)?Component$/u;
|
|
@@ -394,28 +415,28 @@ function isPureComponent(node) {
|
|
|
394
415
|
|
|
395
416
|
// src/component/component-lifecycle.ts
|
|
396
417
|
function isComponentDidMount(node) {
|
|
397
|
-
return
|
|
418
|
+
return AST8.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "componentDidMount";
|
|
398
419
|
}
|
|
399
420
|
function isComponentWillUnmount(node) {
|
|
400
|
-
return
|
|
421
|
+
return AST8.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "componentWillUnmount";
|
|
401
422
|
}
|
|
402
423
|
function isComponentDidCatch(node) {
|
|
403
|
-
return
|
|
424
|
+
return AST8.isMethodOrProperty(node) && !node.static && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "componentDidCatch";
|
|
404
425
|
}
|
|
405
426
|
function isGetDerivedStateFromError(node) {
|
|
406
|
-
return
|
|
427
|
+
return AST8.isMethodOrProperty(node) && node.static && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "getDerivedStateFromError";
|
|
407
428
|
}
|
|
408
429
|
function isGetDerivedStateFromProps(node) {
|
|
409
|
-
return
|
|
430
|
+
return AST8.isMethodOrProperty(node) && node.static && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "getDerivedStateFromProps";
|
|
410
431
|
}
|
|
411
432
|
function isFunctionOfComponentDidMount(node) {
|
|
412
|
-
return
|
|
433
|
+
return AST8.isFunction(node) && isComponentDidMount(node.parent) && node.parent.value === node;
|
|
413
434
|
}
|
|
414
435
|
function isFunctionOfComponentWillUnmount(node) {
|
|
415
|
-
return
|
|
436
|
+
return AST8.isFunction(node) && isComponentWillUnmount(node.parent) && node.parent.value === node;
|
|
416
437
|
}
|
|
417
438
|
function isRenderMethodLike(node) {
|
|
418
|
-
return
|
|
439
|
+
return AST8.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "render" && node.parent.parent.type === AST_NODE_TYPES.ClassDeclaration;
|
|
419
440
|
}
|
|
420
441
|
function isFunctionOfRenderMethod(node) {
|
|
421
442
|
if (!isRenderMethodLike(node.parent)) {
|
|
@@ -424,21 +445,46 @@ function isFunctionOfRenderMethod(node) {
|
|
|
424
445
|
return isClassComponent(node.parent.parent.parent);
|
|
425
446
|
}
|
|
426
447
|
function isInsideRenderMethod(node) {
|
|
427
|
-
return
|
|
448
|
+
return AST8.findParentNode(node, (node2) => isRenderMethodLike(node2) && isClassComponent(node2.parent.parent)) != null;
|
|
428
449
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
450
|
+
|
|
451
|
+
// src/component/hierarchy.ts
|
|
452
|
+
function hasValidHierarchy(node, context, hint) {
|
|
453
|
+
if (isChildrenOfCreateElement(node, context) || isFunctionOfRenderMethod(node)) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
if (hint & ERComponentHint.SkipMapCallback && AST8.isMapCallLoose(node.parent)) {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
if (hint & ERComponentHint.SkipObjectMethod && isFunctionOfObjectMethod(node.parent)) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
if (hint & ERComponentHint.SkipClassMethod && isFunctionOfClassMethod(node.parent)) {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
if (hint & ERComponentHint.SkipClassProperty && isFunctionOfClassProperty(node.parent)) {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
const boundaryNode = AST8.findParentNode(
|
|
469
|
+
node,
|
|
470
|
+
AST8.isOneOf([
|
|
471
|
+
AST_NODE_TYPES.JSXExpressionContainer,
|
|
472
|
+
AST_NODE_TYPES.ArrowFunctionExpression,
|
|
473
|
+
AST_NODE_TYPES.FunctionExpression,
|
|
474
|
+
AST_NODE_TYPES.Property,
|
|
475
|
+
AST_NODE_TYPES.ClassBody
|
|
476
|
+
])
|
|
477
|
+
);
|
|
478
|
+
return boundaryNode == null || boundaryNode.type !== AST_NODE_TYPES.JSXExpressionContainer;
|
|
433
479
|
}
|
|
434
|
-
function
|
|
435
|
-
return
|
|
480
|
+
function isFunctionOfClassMethod(node) {
|
|
481
|
+
return (node.type === AST_NODE_TYPES.FunctionExpression || node.type === AST_NODE_TYPES.ArrowFunctionExpression) && node.parent.type === AST_NODE_TYPES.MethodDefinition;
|
|
436
482
|
}
|
|
437
|
-
function
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
return
|
|
483
|
+
function isFunctionOfClassProperty(node) {
|
|
484
|
+
return (node.type === AST_NODE_TYPES.FunctionExpression || node.type === AST_NODE_TYPES.ArrowFunctionExpression) && node.parent.type === AST_NODE_TYPES.Property;
|
|
485
|
+
}
|
|
486
|
+
function isFunctionOfObjectMethod(node) {
|
|
487
|
+
return (node.type === AST_NODE_TYPES.FunctionExpression || node.type === AST_NODE_TYPES.ArrowFunctionExpression) && node.parent.type === AST_NODE_TYPES.Property && node.parent.parent.type === AST_NODE_TYPES.ObjectExpression;
|
|
442
488
|
}
|
|
443
489
|
|
|
444
490
|
// src/component/component-collector.ts
|
|
@@ -456,7 +502,7 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT, options =
|
|
|
456
502
|
const entry = functionEntries.at(-1);
|
|
457
503
|
if (entry == null) return;
|
|
458
504
|
if (!entry.isComponent) return functionEntries.pop();
|
|
459
|
-
const shouldDrop =
|
|
505
|
+
const shouldDrop = AST8.getNestedReturnStatements(entry.node.body).slice().reverse().some((r) => {
|
|
460
506
|
return context.sourceCode.getScope(r).block === entry.node && r.argument != null && !JSX3.isJSXValue(r.argument, jsxCtx, hint);
|
|
461
507
|
});
|
|
462
508
|
if (shouldDrop) {
|
|
@@ -483,7 +529,7 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT, options =
|
|
|
483
529
|
const { body } = entry.node;
|
|
484
530
|
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX3.isJSXValue(body, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
485
531
|
if (!isComponent) return;
|
|
486
|
-
const initPath =
|
|
532
|
+
const initPath = AST8.getFunctionInitPath(entry.node);
|
|
487
533
|
const id = getFunctionComponentIdentifier(entry.node, context);
|
|
488
534
|
const name = getComponentNameFromIdentifier(id);
|
|
489
535
|
const key = getId();
|
|
@@ -524,7 +570,7 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT, options =
|
|
|
524
570
|
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX3.isJSXValue(node.argument, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
525
571
|
if (!isComponent) return;
|
|
526
572
|
entry.isComponent = true;
|
|
527
|
-
const initPath =
|
|
573
|
+
const initPath = AST8.getFunctionInitPath(entry.node);
|
|
528
574
|
const id = getFunctionComponentIdentifier(entry.node, context);
|
|
529
575
|
const name = getComponentNameFromIdentifier(id);
|
|
530
576
|
components.set(entry.key, {
|
|
@@ -543,40 +589,12 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT, options =
|
|
|
543
589
|
};
|
|
544
590
|
return { ctx, listeners };
|
|
545
591
|
}
|
|
546
|
-
function hasValidHierarchy(node, context, hint) {
|
|
547
|
-
if (isChildrenOfCreateElement(node, context) || isFunctionOfRenderMethod(node)) {
|
|
548
|
-
return false;
|
|
549
|
-
}
|
|
550
|
-
if (hint & ERComponentHint.SkipMapCallback && AST9.isMapCallLoose(node.parent)) {
|
|
551
|
-
return false;
|
|
552
|
-
}
|
|
553
|
-
if (hint & ERComponentHint.SkipObjectMethod && AST9.isFunctionOfObjectMethod(node.parent)) {
|
|
554
|
-
return false;
|
|
555
|
-
}
|
|
556
|
-
if (hint & ERComponentHint.SkipClassMethod && AST9.isFunctionOfClassMethod(node.parent)) {
|
|
557
|
-
return false;
|
|
558
|
-
}
|
|
559
|
-
if (hint & ERComponentHint.SkipClassProperty && AST9.isFunctionOfClassProperty(node.parent)) {
|
|
560
|
-
return false;
|
|
561
|
-
}
|
|
562
|
-
const boundaryNode = AST9.findParentNode(
|
|
563
|
-
node,
|
|
564
|
-
AST9.isOneOf([
|
|
565
|
-
AST_NODE_TYPES.JSXExpressionContainer,
|
|
566
|
-
AST_NODE_TYPES.ArrowFunctionExpression,
|
|
567
|
-
AST_NODE_TYPES.FunctionExpression,
|
|
568
|
-
AST_NODE_TYPES.Property,
|
|
569
|
-
AST_NODE_TYPES.ClassBody
|
|
570
|
-
])
|
|
571
|
-
);
|
|
572
|
-
return boundaryNode == null || boundaryNode.type !== AST_NODE_TYPES.JSXExpressionContainer;
|
|
573
|
-
}
|
|
574
592
|
function getComponentFlag(initPath) {
|
|
575
593
|
let flag = ERComponentFlag.None;
|
|
576
|
-
if (initPath != null &&
|
|
594
|
+
if (initPath != null && AST8.hasCallInFunctionInitPath("memo", initPath)) {
|
|
577
595
|
flag |= ERComponentFlag.Memo;
|
|
578
596
|
}
|
|
579
|
-
if (initPath != null &&
|
|
597
|
+
if (initPath != null && AST8.hasCallInFunctionInitPath("forwardRef", initPath)) {
|
|
580
598
|
flag |= ERComponentFlag.ForwardRef;
|
|
581
599
|
}
|
|
582
600
|
return flag;
|
|
@@ -593,7 +611,7 @@ function useComponentCollectorLegacy() {
|
|
|
593
611
|
if (!isClassComponent(node)) {
|
|
594
612
|
return;
|
|
595
613
|
}
|
|
596
|
-
const id =
|
|
614
|
+
const id = AST8.getClassIdentifier(node);
|
|
597
615
|
const key = getId();
|
|
598
616
|
const flag = isPureComponent(node) ? ERComponentFlag.PureComponent : ERComponentFlag.None;
|
|
599
617
|
components.set(
|
|
@@ -626,7 +644,7 @@ var ERPhaseRelevance = birecord({
|
|
|
626
644
|
var isInversePhase = dual(2, (a, b) => ERPhaseRelevance.get(a) === b);
|
|
627
645
|
function isRenderFunctionLoose(node, context) {
|
|
628
646
|
const { body, parent } = node;
|
|
629
|
-
if (
|
|
647
|
+
if (AST8.getFunctionIdentifier(node)?.name.startsWith("render")) {
|
|
630
648
|
return parent.type === AST_NODE_TYPES.JSXExpressionContainer && parent.parent.type === AST_NODE_TYPES.JSXAttribute && parent.parent.name.type === AST_NODE_TYPES.JSXIdentifier && parent.parent.name.name.startsWith("render");
|
|
631
649
|
}
|
|
632
650
|
return JSX3.isJSXValue(
|
|
@@ -641,7 +659,7 @@ function isRenderPropLoose(node, context) {
|
|
|
641
659
|
if (node.name.type !== AST_NODE_TYPES.JSXIdentifier) {
|
|
642
660
|
return false;
|
|
643
661
|
}
|
|
644
|
-
return node.name.name.startsWith("render") && node.value?.type === AST_NODE_TYPES.JSXExpressionContainer &&
|
|
662
|
+
return node.name.name.startsWith("render") && node.value?.type === AST_NODE_TYPES.JSXExpressionContainer && AST8.isFunction(node.value.expression) && isRenderFunctionLoose(node.value.expression, context);
|
|
645
663
|
}
|
|
646
664
|
function isDirectValueOfRenderPropertyLoose(node) {
|
|
647
665
|
const matching = (node2) => {
|
|
@@ -653,7 +671,7 @@ function isDeclaredInRenderPropLoose(node) {
|
|
|
653
671
|
if (isDirectValueOfRenderPropertyLoose(node)) {
|
|
654
672
|
return true;
|
|
655
673
|
}
|
|
656
|
-
const parent =
|
|
674
|
+
const parent = AST8.findParentNode(node, AST8.is(AST_NODE_TYPES.JSXExpressionContainer))?.parent;
|
|
657
675
|
if (parent?.type !== AST_NODE_TYPES.JSXAttribute) {
|
|
658
676
|
return false;
|
|
659
677
|
}
|
|
@@ -661,17 +679,17 @@ function isDeclaredInRenderPropLoose(node) {
|
|
|
661
679
|
}
|
|
662
680
|
function isThisSetState(node) {
|
|
663
681
|
const { callee } = node;
|
|
664
|
-
return callee.type === AST_NODE_TYPES.MemberExpression &&
|
|
682
|
+
return callee.type === AST_NODE_TYPES.MemberExpression && AST8.isThisExpression(callee.object) && callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === "setState";
|
|
665
683
|
}
|
|
666
684
|
function isFunctionOfUseEffectSetup(node) {
|
|
667
685
|
if (node == null) return _;
|
|
668
686
|
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && node.parent.callee.type === AST_NODE_TYPES.Identifier && node.parent.arguments.at(0) === node && isUseEffectCallLoose(node.parent);
|
|
669
687
|
}
|
|
670
688
|
function isFunctionOfUseEffectCleanup(node) {
|
|
671
|
-
const nearReturn =
|
|
672
|
-
const nearFunction =
|
|
673
|
-
const nearFunctionOfReturn =
|
|
689
|
+
const nearReturn = AST8.findParentNode(node, AST8.is(AST_NODE_TYPES.ReturnStatement));
|
|
690
|
+
const nearFunction = AST8.findParentNode(node, AST8.isFunction);
|
|
691
|
+
const nearFunctionOfReturn = AST8.findParentNode(nearReturn, AST8.isFunction);
|
|
674
692
|
return nearFunction === nearFunctionOfReturn && isFunctionOfUseEffectSetup(nearFunction);
|
|
675
693
|
}
|
|
676
694
|
|
|
677
|
-
export { DEFAULT_COMPONENT_HINT, DISPLAY_NAME_ASSIGNMENT_SELECTOR, ERComponentFlag, ERComponentHint, ERPhaseRelevance, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier, getFunctionComponentIdentifier, hasNoneOrValidComponentName, isCallFromReact, isCallFromReactMember, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentName, isComponentWillUnmount, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isDisplayNameAssignment, isForwardRef, isForwardRefCall, isFromReact, isFromReactMember, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfRenderMethod, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInsideCreateElementProps, isInsideReactHook, isInsideRenderMethod, isInversePhase, isMemo, isMemoCall, isPureComponent, isReactAPICallWithName, isReactAPIWithName, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookName, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isThisSetState, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
|
|
695
|
+
export { DEFAULT_COMPONENT_HINT, DISPLAY_NAME_ASSIGNMENT_SELECTOR, ERComponentFlag, ERComponentHint, ERPhaseRelevance, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier, getFunctionComponentIdentifier, hasNoneOrValidComponentName, hasValidHierarchy, isCallFromReact, isCallFromReactMember, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentName, isComponentWillUnmount, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isDisplayNameAssignment, isForwardRef, isForwardRefCall, isFromReact, isFromReactLoose, isFromReactMember, isFromReactMemberLoose, isFromReactMemberStrict, isFromReactStrict, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfRenderMethod, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInsideCreateElementProps, isInsideReactHook, isInsideRenderMethod, isInversePhase, isMemo, isMemoCall, isPureComponent, isReactAPICallWithName, isReactAPIWithName, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookName, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isThisSetState, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/core",
|
|
3
|
-
"version": "1.28.0-next.
|
|
3
|
+
"version": "1.28.0-next.3",
|
|
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": {
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
"@typescript-eslint/utils": "^8.25.0",
|
|
42
42
|
"birecord": "^0.1.1",
|
|
43
43
|
"ts-pattern": "^5.6.2",
|
|
44
|
-
"@eslint-react/ast": "1.28.0-next.
|
|
45
|
-
"@eslint-react/eff": "1.28.0-next.
|
|
46
|
-
"@eslint-react/
|
|
47
|
-
"@eslint-react/
|
|
48
|
-
"@eslint-react/var": "1.28.0-next.
|
|
44
|
+
"@eslint-react/ast": "1.28.0-next.3",
|
|
45
|
+
"@eslint-react/eff": "1.28.0-next.3",
|
|
46
|
+
"@eslint-react/shared": "1.28.0-next.3",
|
|
47
|
+
"@eslint-react/jsx": "1.28.0-next.3",
|
|
48
|
+
"@eslint-react/var": "1.28.0-next.3"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"tsup": "^8.3.6",
|