@eslint-react/core 2.8.1-next.4 → 2.8.2-beta.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 +41 -41
- package/dist/index.js +42 -42
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as ast from "@eslint-react/ast";
|
|
2
2
|
import { unit } from "@eslint-react/eff";
|
|
3
3
|
import { TSESTree } from "@typescript-eslint/types";
|
|
4
4
|
import { RegExpLike, RuleContext } from "@eslint-react/shared";
|
|
@@ -139,8 +139,8 @@ interface SemanticNode {
|
|
|
139
139
|
//#endregion
|
|
140
140
|
//#region src/semantic/semantic-func.d.ts
|
|
141
141
|
interface SemanticFunc extends SemanticNode {
|
|
142
|
-
id:
|
|
143
|
-
node:
|
|
142
|
+
id: ast.FunctionID | unit;
|
|
143
|
+
node: ast.TSESTreeFunction;
|
|
144
144
|
name: string | unit;
|
|
145
145
|
type: TSESTree.TSTypeAnnotation | unit;
|
|
146
146
|
body: TSESTree.BlockStatement | TSESTree.Expression;
|
|
@@ -170,7 +170,7 @@ interface FunctionComponentSemanticNode extends SemanticNode {
|
|
|
170
170
|
/**
|
|
171
171
|
* The identifier or identifier sequence of the component
|
|
172
172
|
*/
|
|
173
|
-
id: unit |
|
|
173
|
+
id: unit | ast.FunctionID;
|
|
174
174
|
/**
|
|
175
175
|
* The kind of component
|
|
176
176
|
*/
|
|
@@ -178,7 +178,7 @@ interface FunctionComponentSemanticNode extends SemanticNode {
|
|
|
178
178
|
/**
|
|
179
179
|
* The AST node of the function
|
|
180
180
|
*/
|
|
181
|
-
node:
|
|
181
|
+
node: ast.TSESTreeFunction;
|
|
182
182
|
/**
|
|
183
183
|
* Flags describing the component's characteristics
|
|
184
184
|
*/
|
|
@@ -194,7 +194,7 @@ interface FunctionComponentSemanticNode extends SemanticNode {
|
|
|
194
194
|
/**
|
|
195
195
|
* The initialization path of the function
|
|
196
196
|
*/
|
|
197
|
-
initPath: unit |
|
|
197
|
+
initPath: unit | ast.FunctionInitPath;
|
|
198
198
|
/**
|
|
199
199
|
* Indicates if the component is inside an export default declaration
|
|
200
200
|
*/
|
|
@@ -231,7 +231,7 @@ interface ClassComponentSemanticNode extends SemanticNode {
|
|
|
231
231
|
/**
|
|
232
232
|
* The AST node of the class
|
|
233
233
|
*/
|
|
234
|
-
node:
|
|
234
|
+
node: ast.TSESTreeClass;
|
|
235
235
|
/**
|
|
236
236
|
* Flags describing the component's characteristics
|
|
237
237
|
*/
|
|
@@ -243,7 +243,7 @@ interface ClassComponentSemanticNode extends SemanticNode {
|
|
|
243
243
|
/**
|
|
244
244
|
* List of methods and properties in the class
|
|
245
245
|
*/
|
|
246
|
-
methods:
|
|
246
|
+
methods: ast.TSESTreeMethodOrProperty[];
|
|
247
247
|
/**
|
|
248
248
|
* The display name of the component
|
|
249
249
|
*/
|
|
@@ -317,7 +317,7 @@ declare function isAssignmentToThisState(node: TSESTree$1.AssignmentExpression):
|
|
|
317
317
|
* @param hint Component detection hints (bit flags) to customize detection logic
|
|
318
318
|
* @returns `true` if the node is considered a component definition
|
|
319
319
|
*/
|
|
320
|
-
declare function isComponentDefinition(context: RuleContext, node:
|
|
320
|
+
declare function isComponentDefinition(context: RuleContext, node: ast.TSESTreeFunction, hint: bigint): boolean;
|
|
321
321
|
//#endregion
|
|
322
322
|
//#region src/component/component-id.d.ts
|
|
323
323
|
/**
|
|
@@ -326,7 +326,7 @@ declare function isComponentDefinition(context: RuleContext, node: AST.TSESTreeF
|
|
|
326
326
|
* @param node The function node to analyze
|
|
327
327
|
* @returns The function identifier or `unit` if not found
|
|
328
328
|
*/
|
|
329
|
-
declare function getFunctionComponentId(context: RuleContext, node:
|
|
329
|
+
declare function getFunctionComponentId(context: RuleContext, node: ast.TSESTreeFunction): ast.FunctionID | unit;
|
|
330
330
|
//#endregion
|
|
331
331
|
//#region src/component/component-init-path.d.ts
|
|
332
332
|
/**
|
|
@@ -342,7 +342,7 @@ declare function getComponentFlagFromInitPath(initPath: FunctionComponentSemanti
|
|
|
342
342
|
* @param node The AST node to check
|
|
343
343
|
* @returns `true` if the node is a class component, `false` otherwise
|
|
344
344
|
*/
|
|
345
|
-
declare function isClassComponent(node: TSESTree.Node): node is
|
|
345
|
+
declare function isClassComponent(node: TSESTree.Node): node is ast.TSESTreeClass;
|
|
346
346
|
/**
|
|
347
347
|
* Check if a node is a React PureComponent
|
|
348
348
|
* @param node The AST node to check
|
|
@@ -371,24 +371,24 @@ declare function isComponentDidMountCallback(node: TSESTree.Node): boolean;
|
|
|
371
371
|
declare function isComponentWillUnmountCallback(node: TSESTree.Node): boolean;
|
|
372
372
|
//#endregion
|
|
373
373
|
//#region src/component/component-method-is.d.ts
|
|
374
|
-
declare const isRender: (node: TSESTree.Node) => node is
|
|
375
|
-
declare const isComponentDidCatch: (node: TSESTree.Node) => node is
|
|
376
|
-
declare const isComponentDidMount: (node: TSESTree.Node) => node is
|
|
377
|
-
declare const isComponentDidUpdate: (node: TSESTree.Node) => node is
|
|
378
|
-
declare const isComponentWillMount: (node: TSESTree.Node) => node is
|
|
379
|
-
declare const isComponentWillReceiveProps: (node: TSESTree.Node) => node is
|
|
380
|
-
declare const isComponentWillUnmount: (node: TSESTree.Node) => node is
|
|
381
|
-
declare const isComponentWillUpdate: (node: TSESTree.Node) => node is
|
|
382
|
-
declare const isGetChildContext: (node: TSESTree.Node) => node is
|
|
383
|
-
declare const isGetInitialState: (node: TSESTree.Node) => node is
|
|
384
|
-
declare const isGetSnapshotBeforeUpdate: (node: TSESTree.Node) => node is
|
|
385
|
-
declare const isShouldComponentUpdate: (node: TSESTree.Node) => node is
|
|
386
|
-
declare const isUnsafeComponentWillMount: (node: TSESTree.Node) => node is
|
|
387
|
-
declare const isUnsafeComponentWillReceiveProps: (node: TSESTree.Node) => node is
|
|
388
|
-
declare const isUnsafeComponentWillUpdate: (node: TSESTree.Node) => node is
|
|
389
|
-
declare const isGetDefaultProps: (node: TSESTree.Node) => node is
|
|
390
|
-
declare const isGetDerivedStateFromProps: (node: TSESTree.Node) => node is
|
|
391
|
-
declare const isGetDerivedStateFromError: (node: TSESTree.Node) => node is
|
|
374
|
+
declare const isRender: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
375
|
+
declare const isComponentDidCatch: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
376
|
+
declare const isComponentDidMount: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
377
|
+
declare const isComponentDidUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
378
|
+
declare const isComponentWillMount: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
379
|
+
declare const isComponentWillReceiveProps: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
380
|
+
declare const isComponentWillUnmount: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
381
|
+
declare const isComponentWillUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
382
|
+
declare const isGetChildContext: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
383
|
+
declare const isGetInitialState: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
384
|
+
declare const isGetSnapshotBeforeUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
385
|
+
declare const isShouldComponentUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
386
|
+
declare const isUnsafeComponentWillMount: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
387
|
+
declare const isUnsafeComponentWillReceiveProps: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
388
|
+
declare const isUnsafeComponentWillUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
389
|
+
declare const isGetDefaultProps: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
390
|
+
declare const isGetDerivedStateFromProps: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
391
|
+
declare const isGetDerivedStateFromError: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
|
|
392
392
|
//#endregion
|
|
393
393
|
//#region src/component/component-name.d.ts
|
|
394
394
|
/**
|
|
@@ -408,7 +408,7 @@ declare function isComponentNameLoose(name: string): boolean;
|
|
|
408
408
|
* @param allowNone Whether to allow no name
|
|
409
409
|
* @returns Whether the function has a loose component name
|
|
410
410
|
*/
|
|
411
|
-
declare function isFunctionWithLooseComponentName(context: RuleContext, fn:
|
|
411
|
+
declare function isFunctionWithLooseComponentName(context: RuleContext, fn: ast.TSESTreeFunction, allowNone?: boolean): boolean;
|
|
412
412
|
//#endregion
|
|
413
413
|
//#region src/component/component-render-method.d.ts
|
|
414
414
|
/**
|
|
@@ -423,7 +423,7 @@ declare function isFunctionWithLooseComponentName(context: RuleContext, fn: AST.
|
|
|
423
423
|
* @param node The AST node to check
|
|
424
424
|
* @returns `true` if node is a render function, `false` if not
|
|
425
425
|
*/
|
|
426
|
-
declare function isRenderMethodLike(node: TSESTree.Node): node is
|
|
426
|
+
declare function isRenderMethodLike(node: TSESTree.Node): node is ast.TSESTreeMethodOrProperty;
|
|
427
427
|
//#endregion
|
|
428
428
|
//#region src/component/component-render-prop.d.ts
|
|
429
429
|
/**
|
|
@@ -438,7 +438,7 @@ declare function isRenderMethodLike(node: TSESTree.Node): node is AST.TSESTreeMe
|
|
|
438
438
|
* @param node The AST node to check
|
|
439
439
|
* @returns `true` if node is a render function, `false` if not
|
|
440
440
|
*/
|
|
441
|
-
declare function isRenderFunctionLoose(context: RuleContext, node: TSESTree.Node): node is
|
|
441
|
+
declare function isRenderFunctionLoose(context: RuleContext, node: TSESTree.Node): node is ast.TSESTreeFunction;
|
|
442
442
|
/**
|
|
443
443
|
* Unsafe check whether given JSXAttribute is a render prop
|
|
444
444
|
* ```tsx
|
|
@@ -536,9 +536,9 @@ type FindEnclosingComponentOrHookFilter = (n: TSESTree.Node, name: string | null
|
|
|
536
536
|
* Find the enclosing React component or hook for a given AST node
|
|
537
537
|
* @param node The AST node to start the search from
|
|
538
538
|
* @param test Optional test function to customize component or hook identification
|
|
539
|
-
* @returns The enclosing component or hook node, or `null` if none is
|
|
539
|
+
* @returns The enclosing component or hook node, or `null` if none is ASAST.
|
|
540
540
|
*/
|
|
541
|
-
declare function findEnclosingComponentOrHook(node: TSESTree.Node | unit, test?: FindEnclosingComponentOrHookFilter): TSESTree.ArrowFunctionExpression | TSESTree.
|
|
541
|
+
declare function findEnclosingComponentOrHook(node: TSESTree.Node | unit, test?: FindEnclosingComponentOrHookFilter): TSESTree.ArrowFunctionExpression | TSESTree.FunctionDeclarationWithName | TSESTree.FunctionDeclarationWithOptionalName | TSESTree.FunctionExpression | undefined;
|
|
542
542
|
//#endregion
|
|
543
543
|
//#region src/hierarchy/is-inside-component-or-hook.d.ts
|
|
544
544
|
/**
|
|
@@ -562,8 +562,8 @@ declare function isUseEffectCleanupCallback(node: TSESTree.Node | unit): boolean
|
|
|
562
562
|
//#endregion
|
|
563
563
|
//#region src/hook/hook-semantic-node.d.ts
|
|
564
564
|
interface HookSemanticNode extends SemanticNode {
|
|
565
|
-
id:
|
|
566
|
-
node:
|
|
565
|
+
id: ast.FunctionID | unit;
|
|
566
|
+
node: ast.TSESTreeFunction;
|
|
567
567
|
name: string;
|
|
568
568
|
hookCalls: TSESTree.CallExpression[];
|
|
569
569
|
/**
|
|
@@ -575,7 +575,7 @@ interface HookSemanticNode extends SemanticNode {
|
|
|
575
575
|
//#region src/hook/hook-collector.d.ts
|
|
576
576
|
type FunctionEntry = {
|
|
577
577
|
key: string;
|
|
578
|
-
node:
|
|
578
|
+
node: ast.TSESTreeFunction;
|
|
579
579
|
};
|
|
580
580
|
declare namespace useHookCollector {
|
|
581
581
|
type ReturnType = {
|
|
@@ -603,7 +603,7 @@ declare function isHookId(id: TSESTree.Node): id is TSESTree.Identifier | TSESTr
|
|
|
603
603
|
* @param node The function node to check
|
|
604
604
|
* @returns True if the function is a React Hook, false otherwise
|
|
605
605
|
*/
|
|
606
|
-
declare function isHook(node:
|
|
606
|
+
declare function isHook(node: ast.TSESTreeFunction | unit): boolean;
|
|
607
607
|
/**
|
|
608
608
|
* Check if the given node is a React Hook call by its name.
|
|
609
609
|
* @param node The node to check.
|
|
@@ -715,7 +715,7 @@ type JsxAttributeValue = {
|
|
|
715
715
|
* @param attribute - The JSX attribute node to resolve
|
|
716
716
|
* @returns An object containing the value kind, the node (if applicable), and a `toStatic` helper
|
|
717
717
|
*/
|
|
718
|
-
declare function resolveJsxAttributeValue(context: RuleContext, attribute:
|
|
718
|
+
declare function resolveJsxAttributeValue(context: RuleContext, attribute: ast.TSESTreeJSXAttributeLike): {
|
|
719
719
|
readonly kind: "boolean";
|
|
720
720
|
readonly toStatic: () => true;
|
|
721
721
|
readonly node?: never;
|
|
@@ -725,7 +725,7 @@ declare function resolveJsxAttributeValue(context: RuleContext, attribute: AST.T
|
|
|
725
725
|
readonly toStatic: () => string | number | bigint | boolean | RegExp | null;
|
|
726
726
|
} | {
|
|
727
727
|
readonly kind: "expression";
|
|
728
|
-
readonly node: TSESTree.
|
|
728
|
+
readonly node: TSESTree.JSXEmptyExpression | TSESTree.Expression;
|
|
729
729
|
readonly toStatic: () => unknown;
|
|
730
730
|
} | {
|
|
731
731
|
readonly kind: "element";
|
|
@@ -733,7 +733,7 @@ declare function resolveJsxAttributeValue(context: RuleContext, attribute: AST.T
|
|
|
733
733
|
readonly toStatic: () => undefined;
|
|
734
734
|
} | {
|
|
735
735
|
readonly kind: "spreadChild";
|
|
736
|
-
readonly node: TSESTree.
|
|
736
|
+
readonly node: TSESTree.JSXEmptyExpression | TSESTree.Expression;
|
|
737
737
|
readonly toStatic: () => undefined;
|
|
738
738
|
} | {
|
|
739
739
|
readonly kind: "spreadProps";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findImportSource, findProperty, findVariable, getVariableDefinitionNode } from "@eslint-react/var";
|
|
2
|
-
import * as
|
|
2
|
+
import * as ast from "@eslint-react/ast";
|
|
3
3
|
import { constFalse, constTrue, dual, flip, getOrElseUpdate, identity, unit } from "@eslint-react/eff";
|
|
4
4
|
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
5
5
|
import { IdGenerator, RE_ANNOTATION_JSX, RE_ANNOTATION_JSX_FRAG, RE_ANNOTATION_JSX_IMPORT_SOURCE, RE_ANNOTATION_JSX_RUNTIME, RE_COMPONENT_NAME, RE_COMPONENT_NAME_LOOSE } from "@eslint-react/shared";
|
|
@@ -47,7 +47,7 @@ function isReactAPI(api) {
|
|
|
47
47
|
const func = (context, node) => {
|
|
48
48
|
if (node == null) return false;
|
|
49
49
|
const getText = (n) => context.sourceCode.getText(n);
|
|
50
|
-
const name =
|
|
50
|
+
const name = ast.toStringFormat(node, getText);
|
|
51
51
|
if (name === api) return true;
|
|
52
52
|
if (name.substring(name.indexOf(".") + 1) === api) return true;
|
|
53
53
|
return false;
|
|
@@ -136,7 +136,7 @@ function isHookName(name) {
|
|
|
136
136
|
*/
|
|
137
137
|
function isHook(node) {
|
|
138
138
|
if (node == null) return false;
|
|
139
|
-
const id =
|
|
139
|
+
const id = ast.getFunctionId(node);
|
|
140
140
|
switch (id?.type) {
|
|
141
141
|
case AST_NODE_TYPES.Identifier: return isHookName(id.name);
|
|
142
142
|
case AST_NODE_TYPES.MemberExpression: return "name" in id.property && isHookName(id.property.name);
|
|
@@ -237,9 +237,9 @@ function isUseEffectSetupCallback(node) {
|
|
|
237
237
|
*/
|
|
238
238
|
function isUseEffectCleanupCallback(node) {
|
|
239
239
|
if (node == null) return false;
|
|
240
|
-
const pReturn =
|
|
241
|
-
const pFunction =
|
|
242
|
-
if (pFunction !==
|
|
240
|
+
const pReturn = ast.findParentNode(node, ast.is(AST_NODE_TYPES.ReturnStatement));
|
|
241
|
+
const pFunction = ast.findParentNode(node, ast.isFunction);
|
|
242
|
+
if (pFunction !== ast.findParentNode(pReturn, ast.isFunction)) return false;
|
|
243
243
|
return isUseEffectSetupCallback(pFunction);
|
|
244
244
|
}
|
|
245
245
|
|
|
@@ -267,7 +267,7 @@ function useHookCollector(context) {
|
|
|
267
267
|
const getText = (n) => context.sourceCode.getText(n);
|
|
268
268
|
const getCurrentEntry = () => functionEntries.at(-1);
|
|
269
269
|
const onFunctionEnter = (node) => {
|
|
270
|
-
const id =
|
|
270
|
+
const id = ast.getFunctionId(node);
|
|
271
271
|
const key = idGen$2.next();
|
|
272
272
|
functionEntries.push({
|
|
273
273
|
key,
|
|
@@ -278,7 +278,7 @@ function useHookCollector(context) {
|
|
|
278
278
|
id,
|
|
279
279
|
key,
|
|
280
280
|
kind: "function",
|
|
281
|
-
name:
|
|
281
|
+
name: ast.toStringFormat(id, getText),
|
|
282
282
|
node,
|
|
283
283
|
directives: [],
|
|
284
284
|
flag: 0n,
|
|
@@ -546,7 +546,7 @@ function isJsxText(node) {
|
|
|
546
546
|
*/
|
|
547
547
|
function isJsxLike(code, node, hint = DEFAULT_JSX_DETECTION_HINT) {
|
|
548
548
|
if (node == null) return false;
|
|
549
|
-
if (
|
|
549
|
+
if (ast.isJSX(node)) return true;
|
|
550
550
|
switch (node.type) {
|
|
551
551
|
case AST_NODE_TYPES.Literal:
|
|
552
552
|
switch (typeof node.value) {
|
|
@@ -591,7 +591,7 @@ function isJsxLike(code, node, hint = DEFAULT_JSX_DETECTION_HINT) {
|
|
|
591
591
|
case AST_NODE_TYPES.Identifier: {
|
|
592
592
|
const { name } = node;
|
|
593
593
|
if (name === "undefined") return !(hint & JsxDetectionHint.SkipUndefined);
|
|
594
|
-
if (
|
|
594
|
+
if (ast.isJSXTagNameExpression(node)) return true;
|
|
595
595
|
return isJsxLike(code, getVariableDefinitionNode(findVariable(name, code.getScope(node)), 0), hint);
|
|
596
596
|
}
|
|
597
597
|
}
|
|
@@ -657,7 +657,7 @@ function findParentJsxAttribute(node, test = constTrue) {
|
|
|
657
657
|
const guard = (node) => {
|
|
658
658
|
return node.type === AST_NODE_TYPES.JSXAttribute && test(node);
|
|
659
659
|
};
|
|
660
|
-
return
|
|
660
|
+
return ast.findParentNode(node, guard);
|
|
661
661
|
}
|
|
662
662
|
|
|
663
663
|
//#endregion
|
|
@@ -741,7 +741,7 @@ function isComponentWrapperCallLoose(context, node) {
|
|
|
741
741
|
* @returns `true` if the node is a callback function passed to a component wrapper
|
|
742
742
|
*/
|
|
743
743
|
function isComponentWrapperCallback(context, node) {
|
|
744
|
-
if (!
|
|
744
|
+
if (!ast.isFunction(node)) return false;
|
|
745
745
|
const parent = node.parent;
|
|
746
746
|
if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
747
747
|
return isComponentWrapperCall(context, parent);
|
|
@@ -753,7 +753,7 @@ function isComponentWrapperCallback(context, node) {
|
|
|
753
753
|
* @returns `true` if the node is a callback function passed to a component wrapper loosely
|
|
754
754
|
*/
|
|
755
755
|
function isComponentWrapperCallbackLoose(context, node) {
|
|
756
|
-
if (!
|
|
756
|
+
if (!ast.isFunction(node)) return false;
|
|
757
757
|
const parent = node.parent;
|
|
758
758
|
if (parent.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
759
759
|
return isComponentWrapperCallLoose(context, parent);
|
|
@@ -768,7 +768,7 @@ function isComponentWrapperCallbackLoose(context, node) {
|
|
|
768
768
|
* @returns The function identifier or `unit` if not found
|
|
769
769
|
*/
|
|
770
770
|
function getFunctionComponentId(context, node) {
|
|
771
|
-
const functionId =
|
|
771
|
+
const functionId = ast.getFunctionId(node);
|
|
772
772
|
if (functionId != null) return functionId;
|
|
773
773
|
const { parent } = node;
|
|
774
774
|
if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCallLoose(context, parent) && parent.parent.type === AST_NODE_TYPES.VariableDeclarator) return parent.parent.id;
|
|
@@ -822,7 +822,7 @@ function isFunctionWithLooseComponentName(context, fn, allowNone = false) {
|
|
|
822
822
|
* @returns `true` if node is a render function, `false` if not
|
|
823
823
|
*/
|
|
824
824
|
function isRenderMethodLike(node) {
|
|
825
|
-
return
|
|
825
|
+
return ast.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name.startsWith("render") && node.parent.parent.type === AST_NODE_TYPES.ClassDeclaration;
|
|
826
826
|
}
|
|
827
827
|
|
|
828
828
|
//#endregion
|
|
@@ -854,9 +854,9 @@ function isRenderMethodCallback(node) {
|
|
|
854
854
|
*/
|
|
855
855
|
function shouldExcludeBasedOnHint(node, hint) {
|
|
856
856
|
switch (true) {
|
|
857
|
-
case hint & ComponentDetectionHint.SkipObjectMethod &&
|
|
858
|
-
case hint & ComponentDetectionHint.SkipClassMethod &&
|
|
859
|
-
case hint & ComponentDetectionHint.SkipClassProperty &&
|
|
857
|
+
case hint & ComponentDetectionHint.SkipObjectMethod && ast.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && node.parent.type === AST_NODE_TYPES.Property && node.parent.parent.type === AST_NODE_TYPES.ObjectExpression: return true;
|
|
858
|
+
case hint & ComponentDetectionHint.SkipClassMethod && ast.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && node.parent.type === AST_NODE_TYPES.MethodDefinition: return true;
|
|
859
|
+
case hint & ComponentDetectionHint.SkipClassProperty && ast.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && node.parent.type === AST_NODE_TYPES.Property: return true;
|
|
860
860
|
case hint & ComponentDetectionHint.SkipArrayPattern && node.parent.type === AST_NODE_TYPES.ArrayPattern: return true;
|
|
861
861
|
case hint & ComponentDetectionHint.SkipArrayExpression && node.parent.type === AST_NODE_TYPES.ArrayExpression: return true;
|
|
862
862
|
case hint & ComponentDetectionHint.SkipArrayMapCallback && node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee.type === AST_NODE_TYPES.MemberExpression && node.parent.callee.property.type === AST_NODE_TYPES.Identifier && node.parent.callee.property.name === "map": return true;
|
|
@@ -888,7 +888,7 @@ function isComponentDefinition(context, node, hint) {
|
|
|
888
888
|
if (!isFunctionWithLooseComponentName(context, node, true)) return false;
|
|
889
889
|
if (isChildrenOfCreateElement(context, node) || isRenderMethodCallback(node)) return false;
|
|
890
890
|
if (shouldExcludeBasedOnHint(node, hint)) return false;
|
|
891
|
-
const significantParent =
|
|
891
|
+
const significantParent = ast.findParentNode(node, ast.isOneOf([
|
|
892
892
|
AST_NODE_TYPES.JSXExpressionContainer,
|
|
893
893
|
AST_NODE_TYPES.ArrowFunctionExpression,
|
|
894
894
|
AST_NODE_TYPES.FunctionExpression,
|
|
@@ -922,8 +922,8 @@ const ComponentFlag = {
|
|
|
922
922
|
*/
|
|
923
923
|
function getComponentFlagFromInitPath(initPath) {
|
|
924
924
|
let flag = ComponentFlag.None;
|
|
925
|
-
if (initPath != null &&
|
|
926
|
-
if (initPath != null &&
|
|
925
|
+
if (initPath != null && ast.hasCallInFunctionInitPath("memo", initPath)) flag |= ComponentFlag.Memo;
|
|
926
|
+
if (initPath != null && ast.hasCallInFunctionInitPath("forwardRef", initPath)) flag |= ComponentFlag.ForwardRef;
|
|
927
927
|
return flag;
|
|
928
928
|
}
|
|
929
929
|
|
|
@@ -944,13 +944,13 @@ function useComponentCollector(context, options = {}) {
|
|
|
944
944
|
const getCurrentEntry = () => functionEntries.at(-1);
|
|
945
945
|
const onFunctionEnter = (node) => {
|
|
946
946
|
const key = idGen$1.next();
|
|
947
|
-
const exp =
|
|
947
|
+
const exp = ast.findParentNode(node, (n) => n.type === AST_NODE_TYPES.ExportDefaultDeclaration);
|
|
948
948
|
const isExportDefault = exp != null;
|
|
949
|
-
const isExportDefaultDeclaration = exp != null &&
|
|
949
|
+
const isExportDefaultDeclaration = exp != null && ast.getUnderlyingExpression(exp.declaration) === node;
|
|
950
950
|
const id = getFunctionComponentId(context, node);
|
|
951
|
-
const name = id == null ? unit :
|
|
952
|
-
const initPath =
|
|
953
|
-
const directives =
|
|
951
|
+
const name = id == null ? unit : ast.toStringFormat(id, getText);
|
|
952
|
+
const initPath = ast.getFunctionInitPath(node);
|
|
953
|
+
const directives = ast.getFunctionDirectives(node);
|
|
954
954
|
const entry = {
|
|
955
955
|
id: getFunctionComponentId(context, node),
|
|
956
956
|
key,
|
|
@@ -998,7 +998,7 @@ function useComponentCollector(context, options = {}) {
|
|
|
998
998
|
if (!components.has(entry.key) && !isJsxLike(context.sourceCode, body, hint)) return;
|
|
999
999
|
components.set(entry.key, entry);
|
|
1000
1000
|
},
|
|
1001
|
-
...collectDisplayName ? { [
|
|
1001
|
+
...collectDisplayName ? { [ast.SEL_DISPLAY_NAME_ASSIGNMENT_EXPRESSION](node) {
|
|
1002
1002
|
const { left, right } = node;
|
|
1003
1003
|
if (left.type !== AST_NODE_TYPES.MemberExpression) return;
|
|
1004
1004
|
const componentName = left.object.type === AST_NODE_TYPES.Identifier ? left.object.name : unit;
|
|
@@ -1043,9 +1043,9 @@ function useComponentCollectorLegacy(context) {
|
|
|
1043
1043
|
const getText = (n) => context.sourceCode.getText(n);
|
|
1044
1044
|
const collect = (node) => {
|
|
1045
1045
|
if (!isClassComponent(node)) return;
|
|
1046
|
-
const id =
|
|
1046
|
+
const id = ast.getClassId(node);
|
|
1047
1047
|
const key = idGen.next();
|
|
1048
|
-
const name = id == null ? unit :
|
|
1048
|
+
const name = id == null ? unit : ast.toStringFormat(id, getText);
|
|
1049
1049
|
const flag = isPureComponent(node) ? ComponentFlag.PureComponent : ComponentFlag.None;
|
|
1050
1050
|
components.set(key, {
|
|
1051
1051
|
id,
|
|
@@ -1074,7 +1074,7 @@ function useComponentCollectorLegacy(context) {
|
|
|
1074
1074
|
*/
|
|
1075
1075
|
function isThisSetState(node) {
|
|
1076
1076
|
const { callee } = node;
|
|
1077
|
-
return callee.type === AST_NODE_TYPES$1.MemberExpression &&
|
|
1077
|
+
return callee.type === AST_NODE_TYPES$1.MemberExpression && ast.isThisExpressionLoose(callee.object) && callee.property.type === AST_NODE_TYPES$1.Identifier && callee.property.name === "setState";
|
|
1078
1078
|
}
|
|
1079
1079
|
/**
|
|
1080
1080
|
* Check whether the given node is an assignment to this.state
|
|
@@ -1083,7 +1083,7 @@ function isThisSetState(node) {
|
|
|
1083
1083
|
*/
|
|
1084
1084
|
function isAssignmentToThisState(node) {
|
|
1085
1085
|
const { left } = node;
|
|
1086
|
-
return left.type === AST_NODE_TYPES$1.MemberExpression &&
|
|
1086
|
+
return left.type === AST_NODE_TYPES$1.MemberExpression && ast.isThisExpressionLoose(left.object) && ast.getPropertyName(left.property) === "state";
|
|
1087
1087
|
}
|
|
1088
1088
|
|
|
1089
1089
|
//#endregion
|
|
@@ -1094,7 +1094,7 @@ function isAssignmentToThisState(node) {
|
|
|
1094
1094
|
* @param isStatic Whether the method is static
|
|
1095
1095
|
*/
|
|
1096
1096
|
function createLifecycleChecker(methodName, isStatic = false) {
|
|
1097
|
-
return (node) =>
|
|
1097
|
+
return (node) => ast.isMethodOrProperty(node) && node.static === isStatic && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === methodName;
|
|
1098
1098
|
}
|
|
1099
1099
|
const isRender = createLifecycleChecker("render");
|
|
1100
1100
|
const isComponentDidCatch = createLifecycleChecker("componentDidCatch");
|
|
@@ -1123,7 +1123,7 @@ const isGetDerivedStateFromError = createLifecycleChecker("getDerivedStateFromEr
|
|
|
1123
1123
|
* @returns True if the node is a componentDidMount callback, false otherwise
|
|
1124
1124
|
*/
|
|
1125
1125
|
function isComponentDidMountCallback(node) {
|
|
1126
|
-
return
|
|
1126
|
+
return ast.isFunction(node) && isComponentDidMount(node.parent) && node.parent.value === node;
|
|
1127
1127
|
}
|
|
1128
1128
|
/**
|
|
1129
1129
|
* Check if the given node is a componentWillUnmount callback
|
|
@@ -1131,7 +1131,7 @@ function isComponentDidMountCallback(node) {
|
|
|
1131
1131
|
* @returns True if the node is a componentWillUnmount callback, false otherwise
|
|
1132
1132
|
*/
|
|
1133
1133
|
function isComponentWillUnmountCallback(node) {
|
|
1134
|
-
return
|
|
1134
|
+
return ast.isFunction(node) && isComponentWillUnmount(node.parent) && node.parent.value === node;
|
|
1135
1135
|
}
|
|
1136
1136
|
|
|
1137
1137
|
//#endregion
|
|
@@ -1149,8 +1149,8 @@ function isComponentWillUnmountCallback(node) {
|
|
|
1149
1149
|
* @returns `true` if node is a render function, `false` if not
|
|
1150
1150
|
*/
|
|
1151
1151
|
function isRenderFunctionLoose(context, node) {
|
|
1152
|
-
if (!
|
|
1153
|
-
const id =
|
|
1152
|
+
if (!ast.isFunction(node)) return false;
|
|
1153
|
+
const id = ast.getFunctionId(node);
|
|
1154
1154
|
switch (true) {
|
|
1155
1155
|
case id?.type === AST_NODE_TYPES.Identifier: return id.name.startsWith("render");
|
|
1156
1156
|
case id?.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier: return id.property.name.startsWith("render");
|
|
@@ -1203,7 +1203,7 @@ function isDirectValueOfRenderPropertyLoose(node) {
|
|
|
1203
1203
|
*/
|
|
1204
1204
|
function isDeclaredInRenderPropLoose(node) {
|
|
1205
1205
|
if (isDirectValueOfRenderPropertyLoose(node)) return true;
|
|
1206
|
-
const parent =
|
|
1206
|
+
const parent = ast.findParentNode(node, ast.is(AST_NODE_TYPES.JSXExpressionContainer))?.parent;
|
|
1207
1207
|
if (parent?.type !== AST_NODE_TYPES.JSXAttribute) return false;
|
|
1208
1208
|
return parent.name.type === AST_NODE_TYPES.JSXIdentifier && parent.name.name.startsWith("render");
|
|
1209
1209
|
}
|
|
@@ -1214,20 +1214,20 @@ function isDeclaredInRenderPropLoose(node) {
|
|
|
1214
1214
|
* Find the enclosing React component or hook for a given AST node
|
|
1215
1215
|
* @param node The AST node to start the search from
|
|
1216
1216
|
* @param test Optional test function to customize component or hook identification
|
|
1217
|
-
* @returns The enclosing component or hook node, or `null` if none is
|
|
1217
|
+
* @returns The enclosing component or hook node, or `null` if none is ASAST.
|
|
1218
1218
|
*/
|
|
1219
1219
|
function findEnclosingComponentOrHook(node, test = (n, name) => {
|
|
1220
1220
|
if (name == null) return false;
|
|
1221
1221
|
return isComponentNameLoose(name) || isHookName(name);
|
|
1222
1222
|
}) {
|
|
1223
|
-
const enclosingNode =
|
|
1224
|
-
if (!
|
|
1225
|
-
return test(n, match(
|
|
1223
|
+
const enclosingNode = ast.findParentNode(node, (n) => {
|
|
1224
|
+
if (!ast.isFunction(n)) return false;
|
|
1225
|
+
return test(n, match(ast.getFunctionId(n)).with({ type: AST_NODE_TYPES.Identifier }, (id) => id.name).with({
|
|
1226
1226
|
type: AST_NODE_TYPES.MemberExpression,
|
|
1227
1227
|
property: { type: AST_NODE_TYPES.Identifier }
|
|
1228
1228
|
}, (me) => me.property.name).otherwise(() => null));
|
|
1229
1229
|
});
|
|
1230
|
-
return
|
|
1230
|
+
return ast.isFunction(enclosingNode) ? enclosingNode : unit;
|
|
1231
1231
|
}
|
|
1232
1232
|
|
|
1233
1233
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/core",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.2-beta.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.8.
|
|
38
|
-
"@eslint-react/shared": "2.8.
|
|
39
|
-
"@eslint-react/
|
|
40
|
-
"@eslint-react/
|
|
37
|
+
"@eslint-react/ast": "2.8.2-beta.0",
|
|
38
|
+
"@eslint-react/shared": "2.8.2-beta.0",
|
|
39
|
+
"@eslint-react/var": "2.8.2-beta.0",
|
|
40
|
+
"@eslint-react/eff": "2.8.2-beta.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"tsdown": "^0.20.1",
|