@eslint-react/core 3.0.0-next.4 → 3.0.0-next.41

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +157 -150
  2. package/dist/index.js +200 -209
  3. package/package.json +9 -9
package/dist/index.d.ts CHANGED
@@ -78,19 +78,19 @@ declare const isForwardRefCall: isReactAPICall.ReturnType;
78
78
  declare const isMemoCall: isReactAPICall.ReturnType;
79
79
  declare const isLazyCall: isReactAPICall.ReturnType;
80
80
  //#endregion
81
- //#region src/component/component-detection-hint.d.ts
81
+ //#region src/component/component-detection.d.ts
82
82
  type ComponentDetectionHint = bigint;
83
83
  /**
84
84
  * Hints for component collector
85
85
  */
86
86
  declare const ComponentDetectionHint: {
87
- readonly DoNotIncludeFunctionDefinedOnObjectMethod: bigint;
87
+ readonly DoNotIncludeFunctionDefinedAsArrayFlatMapCallback: bigint;
88
+ readonly DoNotIncludeFunctionDefinedAsArrayMapCallback: bigint;
89
+ readonly DoNotIncludeFunctionDefinedInArrayExpression: bigint;
90
+ readonly DoNotIncludeFunctionDefinedInArrayPattern: bigint;
88
91
  readonly DoNotIncludeFunctionDefinedOnClassMethod: bigint;
89
92
  readonly DoNotIncludeFunctionDefinedOnClassProperty: bigint;
90
- readonly DoNotIncludeFunctionDefinedInArrayPattern: bigint;
91
- readonly DoNotIncludeFunctionDefinedInArrayExpression: bigint;
92
- readonly DoNotIncludeFunctionDefinedAsArrayMapCallback: bigint;
93
- readonly DoNotIncludeFunctionDefinedAsArrayFlatMapCallback: bigint;
93
+ readonly DoNotIncludeFunctionDefinedOnObjectMethod: bigint;
94
94
  readonly None: 0n;
95
95
  readonly DoNotIncludeJsxWithNullValue: bigint;
96
96
  readonly DoNotIncludeJsxWithNumberValue: bigint;
@@ -108,6 +108,64 @@ declare const ComponentDetectionHint: {
108
108
  * Default component detection hint
109
109
  */
110
110
  declare const DEFAULT_COMPONENT_DETECTION_HINT: bigint;
111
+ /**
112
+ * Unsafe check whether given node is a render function
113
+ * ```tsx
114
+ * const renderRow = () => <div />
115
+ * ` ^^^^^^^^^^^^`
116
+ * _ = <Component renderRow={() => <div />} />
117
+ * ` ^^^^^^^^^^^^^ `
118
+ * ```
119
+ * @param context The rule context
120
+ * @param node The AST node to check
121
+ * @returns `true` if node is a render function, `false` if not
122
+ */
123
+ declare function isRenderFunctionLoose(context: RuleContext, node: TSESTree.Node): node is ast.TSESTreeFunction;
124
+ /**
125
+ * Unsafe check whether given JSXAttribute is a render prop
126
+ * ```tsx
127
+ * _ = <Component renderRow={() => <div />} />
128
+ * ` ^^^^^^^^^^^^^^^^^^^^^^^^^ `
129
+ * ```
130
+ * @param context The rule context
131
+ * @param node The AST node to check
132
+ * @returns `true` if node is a render prop, `false` if not
133
+ */
134
+ declare function isRenderPropLoose(context: RuleContext, node: TSESTree.JSXAttribute): boolean;
135
+ /**
136
+ * Unsafe check whether given node is declared directly inside a render property
137
+ * ```tsx
138
+ * const rows = { render: () => <div /> }
139
+ * ` ^^^^^^^^^^^^^ `
140
+ * _ = <Component rows={ [{ render: () => <div /> }] } />
141
+ * ` ^^^^^^^^^^^^^ `
142
+ * ```
143
+ * @internal
144
+ * @param node The AST node to check
145
+ * @returns `true` if component is declared inside a render property, `false` if not
146
+ */
147
+ declare function isDirectValueOfRenderPropertyLoose(node: TSESTree.Node): boolean;
148
+ /**
149
+ * Unsafe check whether given node is declared inside a render prop
150
+ * ```tsx
151
+ * _ = <Component renderRow={"node"} />
152
+ * ` ^^^^^^ `
153
+ * _ = <Component rows={ [{ render: "node" }] } />
154
+ * ` ^^^^^^ `
155
+ * ```
156
+ * @param node The AST node to check
157
+ * @returns `true` if component is declared inside a render prop, `false` if not
158
+ */
159
+ declare function isDeclaredInRenderPropLoose(node: TSESTree.Node): boolean;
160
+ /**
161
+ * Determine if a function node represents a valid React component definition
162
+ *
163
+ * @param context The rule context
164
+ * @param node The function node to analyze
165
+ * @param hint Component detection hints (bit flags) to customize detection logic
166
+ * @returns `true` if the node is considered a component definition
167
+ */
168
+ declare function isComponentDefinition(context: RuleContext, node: ast.TSESTreeFunction, hint: bigint): boolean;
111
169
  //#endregion
112
170
  //#region src/semantic/semantic-node.d.ts
113
171
  /**
@@ -138,7 +196,7 @@ interface SemanticNode {
138
196
  */
139
197
  interface SemanticFunc extends SemanticNode {
140
198
  /** The identifier of the function */
141
- id: ast.FunctionID | unit;
199
+ id: ast.FunctionID;
142
200
  /** The AST node of the function */
143
201
  node: ast.TSESTreeFunction;
144
202
  /** The name of the function */
@@ -155,19 +213,6 @@ interface SemanticFunc extends SemanticNode {
155
213
  typeParameters: TSESTree.TSTypeParameterDeclaration | unit;
156
214
  }
157
215
  //#endregion
158
- //#region src/component/component-flag.d.ts
159
- type ComponentFlag = bigint;
160
- /**
161
- * Component flag constants
162
- */
163
- declare const ComponentFlag: {
164
- /** No flags set */None: bigint; /** Indicates the component is a pure component (e.g., extends PureComponent) */
165
- PureComponent: bigint; /** Indicates the component creates elements using `createElement` instead of JSX */
166
- CreateElement: bigint; /** Indicates the component is memoized (e.g., React.memo) */
167
- Memo: bigint; /** Indicates the component forwards a ref (e.g., React.forwardRef) */
168
- ForwardRef: bigint;
169
- };
170
- //#endregion
171
216
  //#region src/component/component-semantic-node.d.ts
172
217
  /**
173
218
  * Represents a React Function Component
@@ -176,7 +221,7 @@ interface FunctionComponentSemanticNode extends SemanticNode {
176
221
  /**
177
222
  * The identifier or identifier sequence of the component
178
223
  */
179
- id: unit | ast.FunctionID;
224
+ id: ast.FunctionID;
180
225
  /**
181
226
  * The kind of component
182
227
  */
@@ -188,11 +233,11 @@ interface FunctionComponentSemanticNode extends SemanticNode {
188
233
  /**
189
234
  * Flags describing the component's characteristics
190
235
  */
191
- flag: ComponentFlag;
236
+ flag: bigint;
192
237
  /**
193
238
  * Hint for how the component was detected
194
239
  */
195
- hint: ComponentDetectionHint;
240
+ hint: bigint;
196
241
  /**
197
242
  * List of expressions returned by the component
198
243
  */
@@ -241,11 +286,11 @@ interface ClassComponentSemanticNode extends SemanticNode {
241
286
  /**
242
287
  * Flags describing the component's characteristics
243
288
  */
244
- flag: ComponentFlag;
289
+ flag: bigint;
245
290
  /**
246
291
  * Hint for how the component was detected
247
292
  */
248
- hint: ComponentDetectionHint;
293
+ hint: bigint;
249
294
  /**
250
295
  * List of methods and properties in the class
251
296
  */
@@ -301,29 +346,95 @@ declare namespace useComponentCollectorLegacy {
301
346
  * @returns The ctx and visitor of the collector
302
347
  */
303
348
  declare function useComponentCollectorLegacy(context: RuleContext): useComponentCollectorLegacy.ReturnType;
349
+ //#endregion
350
+ //#region src/component/component-detection-legacy.d.ts
351
+ declare const isRender: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
352
+ declare const isComponentDidCatch: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
353
+ declare const isComponentDidMount: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
354
+ declare const isComponentDidUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
355
+ declare const isComponentWillMount: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
356
+ declare const isComponentWillReceiveProps: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
357
+ declare const isComponentWillUnmount: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
358
+ declare const isComponentWillUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
359
+ declare const isGetChildContext: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
360
+ declare const isGetInitialState: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
361
+ declare const isGetSnapshotBeforeUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
362
+ declare const isShouldComponentUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
363
+ declare const isUnsafeComponentWillMount: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
364
+ declare const isUnsafeComponentWillReceiveProps: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
365
+ declare const isUnsafeComponentWillUpdate: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
366
+ declare const isGetDefaultProps: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
367
+ declare const isGetDerivedStateFromProps: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
368
+ declare const isGetDerivedStateFromError: (node: TSESTree.Node) => node is ast.TSESTreeMethodOrProperty;
369
+ /**
370
+ * Check if the given node is a componentDidMount callback
371
+ * @param node The node to check
372
+ * @returns True if the node is a componentDidMount callback, false otherwise
373
+ */
374
+ declare function isComponentDidMountCallback(node: TSESTree.Node): boolean;
375
+ /**
376
+ * Check if the given node is a componentWillUnmount callback
377
+ * @param node The node to check
378
+ * @returns True if the node is a componentWillUnmount callback, false otherwise
379
+ */
380
+ declare function isComponentWillUnmountCallback(node: TSESTree.Node): boolean;
381
+ /**
382
+ * Check whether given node is a render method of a class component
383
+ * @example
384
+ * ```tsx
385
+ * class Component extends React.Component {
386
+ * renderHeader = () => <div />;
387
+ * renderFooter = () => <div />;
388
+ * }
389
+ * ```
390
+ * @param node The AST node to check
391
+ * @returns `true` if node is a render function, `false` if not
392
+ */
393
+ declare function isRenderMethodLike(node: TSESTree.Node): node is ast.TSESTreeMethodOrProperty;
394
+ /**
395
+ * Check if the given node is a function within a render method of a class component
396
+ *
397
+ * @param node The AST node to check
398
+ * @returns `true` if the node is a render function inside a class component
399
+ *
400
+ * @example
401
+ * ```tsx
402
+ * class Component extends React.Component {
403
+ * renderHeader = () => <div />; // Returns true
404
+ * }
405
+ * ```
406
+ */
407
+ declare function isRenderMethodCallback(node: ast.TSESTreeFunction): boolean;
304
408
  /**
305
409
  * Check whether the given node is a this.setState() call
306
410
  * @param node The node to check
307
411
  * @internal
308
412
  */
309
- declare function isThisSetState(node: TSESTree$1.CallExpression): boolean;
413
+ declare function isThisSetState(node: TSESTree.CallExpression): boolean;
310
414
  /**
311
415
  * Check whether the given node is an assignment to this.state
312
416
  * @param node The node to check
313
417
  * @internal
314
418
  */
315
- declare function isAssignmentToThisState(node: TSESTree$1.AssignmentExpression): boolean;
419
+ declare function isAssignmentToThisState(node: TSESTree.AssignmentExpression): boolean;
316
420
  //#endregion
317
- //#region src/component/component-definition.d.ts
421
+ //#region src/component/component-flag.d.ts
318
422
  /**
319
- * Determine if a function node represents a valid React component definition
320
- *
321
- * @param context The rule context
322
- * @param node The function node to analyze
323
- * @param hint Component detection hints (bit flags) to customize detection logic
324
- * @returns `true` if the node is considered a component definition
423
+ * Component flag constants
325
424
  */
326
- declare function isComponentDefinition(context: RuleContext, node: ast.TSESTreeFunction, hint: bigint): boolean;
425
+ declare const ComponentFlag: {
426
+ /** Indicates the component creates elements using `createElement` instead of JSX */CreateElement: bigint; /** Indicates the component forwards a ref (e.g., React.forwardRef) */
427
+ ForwardRef: bigint; /** Indicates the component is memoized (e.g., React.memo) */
428
+ Memo: bigint; /** No flags set */
429
+ None: bigint; /** Indicates the component is a pure component (e.g., extends PureComponent) */
430
+ PureComponent: bigint;
431
+ };
432
+ /**
433
+ * Get component flag from init path
434
+ * @param initPath The init path of the function component
435
+ * @returns The component flag
436
+ */
437
+ declare function getComponentFlagFromInitPath(initPath: FunctionComponentSemanticNode["initPath"]): bigint;
327
438
  //#endregion
328
439
  //#region src/component/component-id.d.ts
329
440
  /**
@@ -332,17 +443,10 @@ declare function isComponentDefinition(context: RuleContext, node: ast.TSESTreeF
332
443
  * @param node The function node to analyze
333
444
  * @returns The function identifier or `unit` if not found
334
445
  */
335
- declare function getFunctionComponentId(context: RuleContext, node: ast.TSESTreeFunction): ast.FunctionID | unit;
336
- //#endregion
337
- //#region src/component/component-init-path.d.ts
338
- /**
339
- * Get component flag from init path
340
- * @param initPath The init path of the function component
341
- * @returns The component flag
342
- */
343
- declare function getComponentFlagFromInitPath(initPath: FunctionComponentSemanticNode["initPath"]): bigint;
446
+ declare function getFunctionComponentId(context: RuleContext, node: ast.TSESTreeFunction): ast.FunctionID;
344
447
  //#endregion
345
- //#region src/component/component-is.d.ts
448
+ //#region src/component/component-kind.d.ts
449
+ type ComponentKind = "class-component" | "pure-component" | "function-component";
346
450
  /**
347
451
  * Check if a node is a React class component
348
452
  * @param node The AST node to check
@@ -356,40 +460,6 @@ declare function isClassComponent(node: TSESTree.Node): node is ast.TSESTreeClas
356
460
  */
357
461
  declare function isPureComponent(node: TSESTree.Node): boolean;
358
462
  //#endregion
359
- //#region src/component/component-method-callback.d.ts
360
- /**
361
- * Check if the given node is a componentDidMount callback
362
- * @param node The node to check
363
- * @returns True if the node is a componentDidMount callback, false otherwise
364
- */
365
- declare function isComponentDidMountCallback(node: TSESTree.Node): boolean;
366
- /**
367
- * Check if the given node is a componentWillUnmount callback
368
- * @param node The node to check
369
- * @returns True if the node is a componentWillUnmount callback, false otherwise
370
- */
371
- declare function isComponentWillUnmountCallback(node: TSESTree.Node): boolean;
372
- //#endregion
373
- //#region src/component/component-method-is.d.ts
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
- //#endregion
393
463
  //#region src/component/component-name.d.ts
394
464
  /**
395
465
  * Check if a string matches the strict component name pattern
@@ -410,72 +480,6 @@ declare function isComponentNameLoose(name: string): boolean;
410
480
  */
411
481
  declare function isFunctionWithLooseComponentName(context: RuleContext, fn: ast.TSESTreeFunction, allowNone?: boolean): boolean;
412
482
  //#endregion
413
- //#region src/component/component-render-method.d.ts
414
- /**
415
- * Check whether given node is a render method of a class component
416
- * @example
417
- * ```tsx
418
- * class Component extends React.Component {
419
- * renderHeader = () => <div />;
420
- * renderFooter = () => <div />;
421
- * }
422
- * ```
423
- * @param node The AST node to check
424
- * @returns `true` if node is a render function, `false` if not
425
- */
426
- declare function isRenderMethodLike(node: TSESTree.Node): node is ast.TSESTreeMethodOrProperty;
427
- //#endregion
428
- //#region src/component/component-render-prop.d.ts
429
- /**
430
- * Unsafe check whether given node is a render function
431
- * ```tsx
432
- * const renderRow = () => <div />
433
- * ` ^^^^^^^^^^^^`
434
- * _ = <Component renderRow={() => <div />} />
435
- * ` ^^^^^^^^^^^^^ `
436
- * ```
437
- * @param context The rule context
438
- * @param node The AST node to check
439
- * @returns `true` if node is a render function, `false` if not
440
- */
441
- declare function isRenderFunctionLoose(context: RuleContext, node: TSESTree.Node): node is ast.TSESTreeFunction;
442
- /**
443
- * Unsafe check whether given JSXAttribute is a render prop
444
- * ```tsx
445
- * _ = <Component renderRow={() => <div />} />
446
- * ` ^^^^^^^^^^^^^^^^^^^^^^^^^ `
447
- * ```
448
- * @param context The rule context
449
- * @param node The AST node to check
450
- * @returns `true` if node is a render prop, `false` if not
451
- */
452
- declare function isRenderPropLoose(context: RuleContext, node: TSESTree.JSXAttribute): boolean;
453
- /**
454
- * Unsafe check whether given node is declared directly inside a render property
455
- * ```tsx
456
- * const rows = { render: () => <div /> }
457
- * ` ^^^^^^^^^^^^^ `
458
- * _ = <Component rows={ [{ render: () => <div /> }] } />
459
- * ` ^^^^^^^^^^^^^ `
460
- * ```
461
- * @internal
462
- * @param node The AST node to check
463
- * @returns `true` if component is declared inside a render property, `false` if not
464
- */
465
- declare function isDirectValueOfRenderPropertyLoose(node: TSESTree.Node): boolean;
466
- /**
467
- * Unsafe check whether given node is declared inside a render prop
468
- * ```tsx
469
- * _ = <Component renderRow={"node"} />
470
- * ` ^^^^^^ `
471
- * _ = <Component rows={ [{ render: "node" }] } />
472
- * ` ^^^^^^ `
473
- * ```
474
- * @param node The AST node to check
475
- * @returns `true` if component is declared inside a render prop, `false` if not
476
- */
477
- declare function isDeclaredInRenderPropLoose(node: TSESTree.Node): boolean;
478
- //#endregion
479
483
  //#region src/component/component-wrapper.d.ts
480
484
  /**
481
485
  * Check if the node is a call expression for a component wrapper
@@ -510,7 +514,7 @@ declare function isComponentWrapperCallbackLoose(context: RuleContext, node: TSE
510
514
  /**
511
515
  * Represents the kind of a React function
512
516
  */
513
- type ComponentKind = "client-function" | "server-function";
517
+ type FunctionKind = "client-function" | "server-function";
514
518
  //#endregion
515
519
  //#region src/function/function-semantic-node.d.ts
516
520
  /**
@@ -573,7 +577,7 @@ declare function isUseEffectCleanupCallback(node: TSESTree.Node | unit): boolean
573
577
  */
574
578
  interface HookSemanticNode extends SemanticNode {
575
579
  /** The identifier of the hook */
576
- id: ast.FunctionID | unit;
580
+ id: ast.FunctionID;
577
581
  /** The AST node of the hook */
578
582
  node: ast.TSESTreeFunction;
579
583
  /** The name of the hook */
@@ -889,7 +893,10 @@ declare function findParentJsxAttribute(node: TSESTree.Node, test?: (node: TSEST
889
893
  */
890
894
  declare function stringifyJsx(node: TSESTree$1.JSXIdentifier | TSESTree$1.JSXNamespacedName | TSESTree$1.JSXMemberExpression | TSESTree$1.JSXOpeningElement | TSESTree$1.JSXClosingElement | TSESTree$1.JSXOpeningFragment | TSESTree$1.JSXClosingFragment | TSESTree$1.JSXText): string;
891
895
  //#endregion
892
- //#region src/ref/is-from-ref.d.ts
896
+ //#region src/ref/ref-id.d.ts
897
+ declare function isRefId(node: TSESTree.Expression | TSESTree.PrivateIdentifier): boolean;
898
+ //#endregion
899
+ //#region src/ref/ref-init.d.ts
893
900
  /**
894
901
  * Check if the variable with the given name is initialized or derived from a ref
895
902
  * @param name The variable name
@@ -911,6 +918,6 @@ declare function getRefInit(name: string, initialScope: Scope): TSESTree$1.Expre
911
918
  * @param name The name to check
912
919
  * @returns True if the name is "ref" or ends with "Ref"
913
920
  */
914
- declare function isRefName(name: string): boolean;
921
+ declare function isRefLikeName(name: string): boolean;
915
922
  //#endregion
916
- export { ClassComponentSemanticNode, ClientFunctionSemanticNode, ComponentDetectionHint, ComponentFlag, ComponentKind, ComponentSemanticNode, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, FindEnclosingComponentOrHookFilter, FunctionComponentSemanticNode, FunctionSemanticNode, HookSemanticNode, JsxAttributeValue, JsxConfig, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, SemanticFunc, SemanticNode, ServerFunctionSemanticNode, findEnclosingComponentOrHook, findParentJsxAttribute, getComponentFlagFromInitPath, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, getRefInit, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHook, isHookCall, isHookCallWithName, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isInitializedFromRef, isInsideComponentOrHook, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRefName, isRender, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall, resolveJsxAttributeValue, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
923
+ export { ClassComponentSemanticNode, ClientFunctionSemanticNode, ComponentDetectionHint, ComponentFlag, ComponentKind, ComponentSemanticNode, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, FindEnclosingComponentOrHookFilter, FunctionComponentSemanticNode, FunctionKind, FunctionSemanticNode, HookSemanticNode, JsxAttributeValue, JsxConfig, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, SemanticFunc, SemanticNode, ServerFunctionSemanticNode, findEnclosingComponentOrHook, findParentJsxAttribute, getComponentFlagFromInitPath, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, getRefInit, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHook, isHookCall, isHookCallWithName, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isInitializedFromRef, isInsideComponentOrHook, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRefId, isRefLikeName, isRender, isRenderFunctionLoose, isRenderMethodCallback, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall, resolveJsxAttributeValue, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { findImportSource, findProperty, findVariable, getVariableDefinitionNode } from "@eslint-react/var";
1
+ import { findImportSource, findProperty, findVariable, getVariableInitializer } from "@eslint-react/var";
2
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";
@@ -260,7 +260,7 @@ function isHookId(id) {
260
260
 
261
261
  //#endregion
262
262
  //#region src/hook/hook-collector.ts
263
- const idGen$2 = new IdGenerator("hook_");
263
+ const idGen$2 = new IdGenerator("hook:");
264
264
  /**
265
265
  * Get a ctx and visitor object for the rule to collect hooks
266
266
  * @param context The ESLint rule context
@@ -369,8 +369,8 @@ function getJsxAttribute(context, node, initialScope) {
369
369
  if (attr.type === AST_NODE_TYPES.JSXAttribute) return getJsxAttributeName(context, attr) === name;
370
370
  switch (attr.argument.type) {
371
371
  case AST_NODE_TYPES.Identifier: {
372
- const variableNode = getVariableDefinitionNode(findVariable(attr.argument.name, scope), 0);
373
- if (variableNode?.type === AST_NODE_TYPES.ObjectExpression) return findProperty(name, variableNode.properties, scope) != null;
372
+ const initNode = getVariableInitializer(findVariable(attr.argument.name, scope), 0);
373
+ if (initNode?.type === AST_NODE_TYPES.ObjectExpression) return findProperty(name, initNode.properties, scope) != null;
374
374
  return false;
375
375
  }
376
376
  case AST_NODE_TYPES.ObjectExpression: return findProperty(name, attr.argument.properties, scope) != null;
@@ -597,7 +597,7 @@ function isJsxLike(code, node, hint = DEFAULT_JSX_DETECTION_HINT) {
597
597
  const { name } = node;
598
598
  if (name === "undefined") return !(hint & JsxDetectionHint.DoNotIncludeJsxWithUndefinedValue);
599
599
  if (ast.isJSXTagNameExpression(node)) return true;
600
- return isJsxLike(code, getVariableDefinitionNode(findVariable(name, code.getScope(node)), 0), hint);
600
+ return isJsxLike(code, getVariableInitializer(findVariable(name, code.getScope(node)), 0), hint);
601
601
  }
602
602
  }
603
603
  return false;
@@ -666,27 +666,7 @@ function findParentJsxAttribute(node, test = constTrue) {
666
666
  }
667
667
 
668
668
  //#endregion
669
- //#region src/component/component-detection-hint.ts
670
- /**
671
- * Hints for component collector
672
- */
673
- const ComponentDetectionHint = {
674
- ...JsxDetectionHint,
675
- DoNotIncludeFunctionDefinedOnObjectMethod: 1n << 64n,
676
- DoNotIncludeFunctionDefinedOnClassMethod: 1n << 65n,
677
- DoNotIncludeFunctionDefinedOnClassProperty: 1n << 66n,
678
- DoNotIncludeFunctionDefinedInArrayPattern: 1n << 67n,
679
- DoNotIncludeFunctionDefinedInArrayExpression: 1n << 68n,
680
- DoNotIncludeFunctionDefinedAsArrayMapCallback: 1n << 69n,
681
- DoNotIncludeFunctionDefinedAsArrayFlatMapCallback: 1n << 70n
682
- };
683
- /**
684
- * Default component detection hint
685
- */
686
- const DEFAULT_COMPONENT_DETECTION_HINT = 0n | ComponentDetectionHint.DoNotIncludeJsxWithBigIntValue | ComponentDetectionHint.DoNotIncludeJsxWithBooleanValue | ComponentDetectionHint.DoNotIncludeJsxWithNumberValue | ComponentDetectionHint.DoNotIncludeJsxWithStringValue | ComponentDetectionHint.DoNotIncludeJsxWithUndefinedValue | ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayFlatMapCallback | ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback | ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayExpression | ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayPattern | ComponentDetectionHint.RequireAllArrayElementsToBeJsx | ComponentDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx | ComponentDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx;
687
-
688
- //#endregion
689
- //#region src/component/component-is.ts
669
+ //#region src/component/component-kind.ts
690
670
  /**
691
671
  * Check if a node is a React class component
692
672
  * @param node The AST node to check
@@ -718,6 +698,102 @@ function isPureComponent(node) {
718
698
  return false;
719
699
  }
720
700
 
701
+ //#endregion
702
+ //#region src/component/component-detection-legacy.ts
703
+ /**
704
+ * Create a lifecycle method checker function
705
+ * @param methodName The lifecycle method name
706
+ * @param isStatic Whether the method is static
707
+ */
708
+ function createLifecycleChecker(methodName, isStatic = false) {
709
+ return (node) => ast.isMethodOrProperty(node) && node.static === isStatic && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === methodName;
710
+ }
711
+ const isRender = createLifecycleChecker("render");
712
+ const isComponentDidCatch = createLifecycleChecker("componentDidCatch");
713
+ const isComponentDidMount = createLifecycleChecker("componentDidMount");
714
+ const isComponentDidUpdate = createLifecycleChecker("componentDidUpdate");
715
+ const isComponentWillMount = createLifecycleChecker("componentWillMount");
716
+ const isComponentWillReceiveProps = createLifecycleChecker("componentWillReceiveProps");
717
+ const isComponentWillUnmount = createLifecycleChecker("componentWillUnmount");
718
+ const isComponentWillUpdate = createLifecycleChecker("componentWillUpdate");
719
+ const isGetChildContext = createLifecycleChecker("getChildContext");
720
+ const isGetInitialState = createLifecycleChecker("getInitialState");
721
+ const isGetSnapshotBeforeUpdate = createLifecycleChecker("getSnapshotBeforeUpdate");
722
+ const isShouldComponentUpdate = createLifecycleChecker("shouldComponentUpdate");
723
+ const isUnsafeComponentWillMount = createLifecycleChecker("UNSAFE_componentWillMount");
724
+ const isUnsafeComponentWillReceiveProps = createLifecycleChecker("UNSAFE_componentWillReceiveProps");
725
+ const isUnsafeComponentWillUpdate = createLifecycleChecker("UNSAFE_componentWillUpdate");
726
+ const isGetDefaultProps = createLifecycleChecker("getDefaultProps", true);
727
+ const isGetDerivedStateFromProps = createLifecycleChecker("getDerivedStateFromProps", true);
728
+ const isGetDerivedStateFromError = createLifecycleChecker("getDerivedStateFromError", true);
729
+ /**
730
+ * Check if the given node is a componentDidMount callback
731
+ * @param node The node to check
732
+ * @returns True if the node is a componentDidMount callback, false otherwise
733
+ */
734
+ function isComponentDidMountCallback(node) {
735
+ return ast.isFunction(node) && isComponentDidMount(node.parent) && node.parent.value === node;
736
+ }
737
+ /**
738
+ * Check if the given node is a componentWillUnmount callback
739
+ * @param node The node to check
740
+ * @returns True if the node is a componentWillUnmount callback, false otherwise
741
+ */
742
+ function isComponentWillUnmountCallback(node) {
743
+ return ast.isFunction(node) && isComponentWillUnmount(node.parent) && node.parent.value === node;
744
+ }
745
+ /**
746
+ * Check whether given node is a render method of a class component
747
+ * @example
748
+ * ```tsx
749
+ * class Component extends React.Component {
750
+ * renderHeader = () => <div />;
751
+ * renderFooter = () => <div />;
752
+ * }
753
+ * ```
754
+ * @param node The AST node to check
755
+ * @returns `true` if node is a render function, `false` if not
756
+ */
757
+ function isRenderMethodLike(node) {
758
+ return ast.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name.startsWith("render") && node.parent.parent.type === AST_NODE_TYPES.ClassDeclaration;
759
+ }
760
+ /**
761
+ * Check if the given node is a function within a render method of a class component
762
+ *
763
+ * @param node The AST node to check
764
+ * @returns `true` if the node is a render function inside a class component
765
+ *
766
+ * @example
767
+ * ```tsx
768
+ * class Component extends React.Component {
769
+ * renderHeader = () => <div />; // Returns true
770
+ * }
771
+ * ```
772
+ */
773
+ function isRenderMethodCallback(node) {
774
+ const parent = node.parent;
775
+ const greatGrandparent = parent.parent?.parent;
776
+ return greatGrandparent != null && isRenderMethodLike(parent) && isClassComponent(greatGrandparent);
777
+ }
778
+ /**
779
+ * Check whether the given node is a this.setState() call
780
+ * @param node The node to check
781
+ * @internal
782
+ */
783
+ function isThisSetState(node) {
784
+ const { callee } = node;
785
+ return callee.type === AST_NODE_TYPES.MemberExpression && ast.isThisExpressionLoose(callee.object) && callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === "setState";
786
+ }
787
+ /**
788
+ * Check whether the given node is an assignment to this.state
789
+ * @param node The node to check
790
+ * @internal
791
+ */
792
+ function isAssignmentToThisState(node) {
793
+ const { left } = node;
794
+ return left.type === AST_NODE_TYPES.MemberExpression && ast.isThisExpressionLoose(left.object) && ast.getPropertyName(left.property) === "state";
795
+ }
796
+
721
797
  //#endregion
722
798
  //#region src/component/component-wrapper.ts
723
799
  /**
@@ -814,42 +890,94 @@ function isFunctionWithLooseComponentName(context, fn, allowNone = false) {
814
890
  }
815
891
 
816
892
  //#endregion
817
- //#region src/component/component-render-method.ts
893
+ //#region src/component/component-detection.ts
818
894
  /**
819
- * Check whether given node is a render method of a class component
820
- * @example
895
+ * Hints for component collector
896
+ */
897
+ const ComponentDetectionHint = {
898
+ ...JsxDetectionHint,
899
+ DoNotIncludeFunctionDefinedAsArrayFlatMapCallback: 1n << 17n,
900
+ DoNotIncludeFunctionDefinedAsArrayMapCallback: 1n << 16n,
901
+ DoNotIncludeFunctionDefinedInArrayExpression: 1n << 15n,
902
+ DoNotIncludeFunctionDefinedInArrayPattern: 1n << 14n,
903
+ DoNotIncludeFunctionDefinedOnClassMethod: 1n << 12n,
904
+ DoNotIncludeFunctionDefinedOnClassProperty: 1n << 13n,
905
+ DoNotIncludeFunctionDefinedOnObjectMethod: 1n << 11n
906
+ };
907
+ /**
908
+ * Default component detection hint
909
+ */
910
+ const DEFAULT_COMPONENT_DETECTION_HINT = 0n | ComponentDetectionHint.DoNotIncludeJsxWithBigIntValue | ComponentDetectionHint.DoNotIncludeJsxWithBooleanValue | ComponentDetectionHint.DoNotIncludeJsxWithNumberValue | ComponentDetectionHint.DoNotIncludeJsxWithStringValue | ComponentDetectionHint.DoNotIncludeJsxWithUndefinedValue | ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayFlatMapCallback | ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback | ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayExpression | ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayPattern | ComponentDetectionHint.RequireAllArrayElementsToBeJsx | ComponentDetectionHint.RequireBothBranchesOfConditionalExpressionToBeJsx | ComponentDetectionHint.RequireBothSidesOfLogicalExpressionToBeJsx;
911
+ /**
912
+ * Unsafe check whether given node is a render function
821
913
  * ```tsx
822
- * class Component extends React.Component {
823
- * renderHeader = () => <div />;
824
- * renderFooter = () => <div />;
825
- * }
914
+ * const renderRow = () => <div />
915
+ * ` ^^^^^^^^^^^^`
916
+ * _ = <Component renderRow={() => <div />} />
917
+ * ` ^^^^^^^^^^^^^ `
826
918
  * ```
919
+ * @param context The rule context
827
920
  * @param node The AST node to check
828
921
  * @returns `true` if node is a render function, `false` if not
829
922
  */
830
- function isRenderMethodLike(node) {
831
- return ast.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name.startsWith("render") && node.parent.parent.type === AST_NODE_TYPES.ClassDeclaration;
923
+ function isRenderFunctionLoose(context, node) {
924
+ if (!ast.isFunction(node)) return false;
925
+ const id = ast.getFunctionId(node);
926
+ switch (true) {
927
+ case id?.type === AST_NODE_TYPES.Identifier: return id.name.startsWith("render");
928
+ case id?.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier: return id.property.name.startsWith("render");
929
+ case node.parent.type === AST_NODE_TYPES.JSXExpressionContainer && node.parent.parent.type === AST_NODE_TYPES.JSXAttribute && node.parent.parent.name.type === AST_NODE_TYPES.JSXIdentifier: return node.parent.parent.name.name.startsWith("render");
930
+ }
931
+ return false;
832
932
  }
833
-
834
- //#endregion
835
- //#region src/component/component-definition.ts
836
933
  /**
837
- * Check if the given node is a function within a render method of a class component.
838
- *
934
+ * Unsafe check whether given JSXAttribute is a render prop
935
+ * ```tsx
936
+ * _ = <Component renderRow={() => <div />} />
937
+ * ` ^^^^^^^^^^^^^^^^^^^^^^^^^ `
938
+ * ```
939
+ * @param context The rule context
839
940
  * @param node The AST node to check
840
- * @returns `true` if the node is a render function inside a class component
841
- *
842
- * @example
941
+ * @returns `true` if node is a render prop, `false` if not
942
+ */
943
+ function isRenderPropLoose(context, node) {
944
+ if (node.name.type !== AST_NODE_TYPES.JSXIdentifier) return false;
945
+ return node.name.name.startsWith("render") && node.value?.type === AST_NODE_TYPES.JSXExpressionContainer && isRenderFunctionLoose(context, node.value.expression);
946
+ }
947
+ /**
948
+ * Unsafe check whether given node is declared directly inside a render property
843
949
  * ```tsx
844
- * class Component extends React.Component {
845
- * renderHeader = () => <div />; // Returns true
846
- * }
950
+ * const rows = { render: () => <div /> }
951
+ * ` ^^^^^^^^^^^^^ `
952
+ * _ = <Component rows={ [{ render: () => <div /> }] } />
953
+ * ` ^^^^^^^^^^^^^ `
954
+ * ```
955
+ * @internal
956
+ * @param node The AST node to check
957
+ * @returns `true` if component is declared inside a render property, `false` if not
958
+ */
959
+ function isDirectValueOfRenderPropertyLoose(node) {
960
+ const matching = (node) => {
961
+ return node.type === AST_NODE_TYPES.Property && node.key.type === AST_NODE_TYPES.Identifier && node.key.name.startsWith("render");
962
+ };
963
+ return matching(node) || node.parent != null && matching(node.parent);
964
+ }
965
+ /**
966
+ * Unsafe check whether given node is declared inside a render prop
967
+ * ```tsx
968
+ * _ = <Component renderRow={"node"} />
969
+ * ` ^^^^^^ `
970
+ * _ = <Component rows={ [{ render: "node" }] } />
971
+ * ` ^^^^^^ `
847
972
  * ```
973
+ * @param node The AST node to check
974
+ * @returns `true` if component is declared inside a render prop, `false` if not
848
975
  */
849
- function isRenderMethodCallback(node) {
850
- const parent = node.parent;
851
- const greatGrandparent = parent.parent?.parent;
852
- return greatGrandparent != null && isRenderMethodLike(parent) && isClassComponent(greatGrandparent);
976
+ function isDeclaredInRenderPropLoose(node) {
977
+ if (isDirectValueOfRenderPropertyLoose(node)) return true;
978
+ const parent = ast.findParentNode(node, ast.is(AST_NODE_TYPES.JSXExpressionContainer))?.parent;
979
+ if (parent?.type !== AST_NODE_TYPES.JSXAttribute) return false;
980
+ return parent.name.type === AST_NODE_TYPES.JSXIdentifier && parent.name.name.startsWith("render");
853
981
  }
854
982
  /**
855
983
  * Check if a function node should be excluded based on provided detection hints
@@ -860,13 +988,13 @@ function isRenderMethodCallback(node) {
860
988
  */
861
989
  function shouldExcludeBasedOnHint(node, hint) {
862
990
  switch (true) {
863
- case hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedOnObjectMethod && 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;
864
- case hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedOnClassMethod && ast.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && node.parent.type === AST_NODE_TYPES.MethodDefinition: return true;
865
- case hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedOnClassProperty && ast.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && node.parent.type === AST_NODE_TYPES.Property: return true;
866
- case hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayPattern && node.parent.type === AST_NODE_TYPES.ArrayPattern: return true;
867
- case hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayExpression && node.parent.type === AST_NODE_TYPES.ArrayExpression: return true;
868
- case hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback && 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;
869
- case hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayFlatMapCallback && 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 === "flatMap": return true;
991
+ case 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 !!(hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedOnObjectMethod);
992
+ case ast.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && node.parent.type === AST_NODE_TYPES.MethodDefinition: return !!(hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedOnClassMethod);
993
+ case ast.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(node) && node.parent.type === AST_NODE_TYPES.Property: return !!(hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedOnClassProperty);
994
+ case node.parent.type === AST_NODE_TYPES.ArrayPattern: return !!(hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayPattern);
995
+ case node.parent.type === AST_NODE_TYPES.ArrayExpression: return !!(hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedInArrayExpression);
996
+ case 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 !!(hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayMapCallback);
997
+ case 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 === "flatMap": return !!(hint & ComponentDetectionHint.DoNotIncludeFunctionDefinedAsArrayFlatMapCallback);
870
998
  }
871
999
  return false;
872
1000
  }
@@ -913,15 +1041,12 @@ function isComponentDefinition(context, node, hint) {
913
1041
  * Component flag constants
914
1042
  */
915
1043
  const ComponentFlag = {
916
- None: 0n,
917
- PureComponent: 1n << 0n,
918
1044
  CreateElement: 1n << 1n,
1045
+ ForwardRef: 1n << 3n,
919
1046
  Memo: 1n << 2n,
920
- ForwardRef: 1n << 3n
1047
+ None: 0n,
1048
+ PureComponent: 1n << 0n
921
1049
  };
922
-
923
- //#endregion
924
- //#region src/component/component-init-path.ts
925
1050
  /**
926
1051
  * Get component flag from init path
927
1052
  * @param initPath The init path of the function component
@@ -936,7 +1061,7 @@ function getComponentFlagFromInitPath(initPath) {
936
1061
 
937
1062
  //#endregion
938
1063
  //#region src/component/component-collector.ts
939
- const idGen$1 = new IdGenerator("function_component_");
1064
+ const idGen$1 = new IdGenerator("function-component:");
940
1065
  /**
941
1066
  * Get a ctx and visitor object for the rule to collect function components
942
1067
  * @param context The ESLint rule context
@@ -1036,7 +1161,7 @@ function useComponentCollector(context, options = {}) {
1036
1161
 
1037
1162
  //#endregion
1038
1163
  //#region src/component/component-collector-legacy.ts
1039
- const idGen = new IdGenerator("class_component_");
1164
+ const idGen = new IdGenerator("class-component:");
1040
1165
  /**
1041
1166
  * Get a ctx and visitor object for the rule to collect class componentss
1042
1167
  * @param context The ESLint rule context
@@ -1074,146 +1199,6 @@ function useComponentCollectorLegacy(context) {
1074
1199
  }
1075
1200
  };
1076
1201
  }
1077
- /**
1078
- * Check whether the given node is a this.setState() call
1079
- * @param node The node to check
1080
- * @internal
1081
- */
1082
- function isThisSetState(node) {
1083
- const { callee } = node;
1084
- return callee.type === AST_NODE_TYPES$1.MemberExpression && ast.isThisExpressionLoose(callee.object) && callee.property.type === AST_NODE_TYPES$1.Identifier && callee.property.name === "setState";
1085
- }
1086
- /**
1087
- * Check whether the given node is an assignment to this.state
1088
- * @param node The node to check
1089
- * @internal
1090
- */
1091
- function isAssignmentToThisState(node) {
1092
- const { left } = node;
1093
- return left.type === AST_NODE_TYPES$1.MemberExpression && ast.isThisExpressionLoose(left.object) && ast.getPropertyName(left.property) === "state";
1094
- }
1095
-
1096
- //#endregion
1097
- //#region src/component/component-method-is.ts
1098
- /**
1099
- * Create a lifecycle method checker function
1100
- * @param methodName The lifecycle method name
1101
- * @param isStatic Whether the method is static
1102
- */
1103
- function createLifecycleChecker(methodName, isStatic = false) {
1104
- return (node) => ast.isMethodOrProperty(node) && node.static === isStatic && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === methodName;
1105
- }
1106
- const isRender = createLifecycleChecker("render");
1107
- const isComponentDidCatch = createLifecycleChecker("componentDidCatch");
1108
- const isComponentDidMount = createLifecycleChecker("componentDidMount");
1109
- const isComponentDidUpdate = createLifecycleChecker("componentDidUpdate");
1110
- const isComponentWillMount = createLifecycleChecker("componentWillMount");
1111
- const isComponentWillReceiveProps = createLifecycleChecker("componentWillReceiveProps");
1112
- const isComponentWillUnmount = createLifecycleChecker("componentWillUnmount");
1113
- const isComponentWillUpdate = createLifecycleChecker("componentWillUpdate");
1114
- const isGetChildContext = createLifecycleChecker("getChildContext");
1115
- const isGetInitialState = createLifecycleChecker("getInitialState");
1116
- const isGetSnapshotBeforeUpdate = createLifecycleChecker("getSnapshotBeforeUpdate");
1117
- const isShouldComponentUpdate = createLifecycleChecker("shouldComponentUpdate");
1118
- const isUnsafeComponentWillMount = createLifecycleChecker("UNSAFE_componentWillMount");
1119
- const isUnsafeComponentWillReceiveProps = createLifecycleChecker("UNSAFE_componentWillReceiveProps");
1120
- const isUnsafeComponentWillUpdate = createLifecycleChecker("UNSAFE_componentWillUpdate");
1121
- const isGetDefaultProps = createLifecycleChecker("getDefaultProps", true);
1122
- const isGetDerivedStateFromProps = createLifecycleChecker("getDerivedStateFromProps", true);
1123
- const isGetDerivedStateFromError = createLifecycleChecker("getDerivedStateFromError", true);
1124
-
1125
- //#endregion
1126
- //#region src/component/component-method-callback.ts
1127
- /**
1128
- * Check if the given node is a componentDidMount callback
1129
- * @param node The node to check
1130
- * @returns True if the node is a componentDidMount callback, false otherwise
1131
- */
1132
- function isComponentDidMountCallback(node) {
1133
- return ast.isFunction(node) && isComponentDidMount(node.parent) && node.parent.value === node;
1134
- }
1135
- /**
1136
- * Check if the given node is a componentWillUnmount callback
1137
- * @param node The node to check
1138
- * @returns True if the node is a componentWillUnmount callback, false otherwise
1139
- */
1140
- function isComponentWillUnmountCallback(node) {
1141
- return ast.isFunction(node) && isComponentWillUnmount(node.parent) && node.parent.value === node;
1142
- }
1143
-
1144
- //#endregion
1145
- //#region src/component/component-render-prop.ts
1146
- /**
1147
- * Unsafe check whether given node is a render function
1148
- * ```tsx
1149
- * const renderRow = () => <div />
1150
- * ` ^^^^^^^^^^^^`
1151
- * _ = <Component renderRow={() => <div />} />
1152
- * ` ^^^^^^^^^^^^^ `
1153
- * ```
1154
- * @param context The rule context
1155
- * @param node The AST node to check
1156
- * @returns `true` if node is a render function, `false` if not
1157
- */
1158
- function isRenderFunctionLoose(context, node) {
1159
- if (!ast.isFunction(node)) return false;
1160
- const id = ast.getFunctionId(node);
1161
- switch (true) {
1162
- case id?.type === AST_NODE_TYPES.Identifier: return id.name.startsWith("render");
1163
- case id?.type === AST_NODE_TYPES.MemberExpression && id.property.type === AST_NODE_TYPES.Identifier: return id.property.name.startsWith("render");
1164
- case node.parent.type === AST_NODE_TYPES.JSXExpressionContainer && node.parent.parent.type === AST_NODE_TYPES.JSXAttribute && node.parent.parent.name.type === AST_NODE_TYPES.JSXIdentifier: return node.parent.parent.name.name.startsWith("render");
1165
- }
1166
- return false;
1167
- }
1168
- /**
1169
- * Unsafe check whether given JSXAttribute is a render prop
1170
- * ```tsx
1171
- * _ = <Component renderRow={() => <div />} />
1172
- * ` ^^^^^^^^^^^^^^^^^^^^^^^^^ `
1173
- * ```
1174
- * @param context The rule context
1175
- * @param node The AST node to check
1176
- * @returns `true` if node is a render prop, `false` if not
1177
- */
1178
- function isRenderPropLoose(context, node) {
1179
- if (node.name.type !== AST_NODE_TYPES.JSXIdentifier) return false;
1180
- return node.name.name.startsWith("render") && node.value?.type === AST_NODE_TYPES.JSXExpressionContainer && isRenderFunctionLoose(context, node.value.expression);
1181
- }
1182
- /**
1183
- * Unsafe check whether given node is declared directly inside a render property
1184
- * ```tsx
1185
- * const rows = { render: () => <div /> }
1186
- * ` ^^^^^^^^^^^^^ `
1187
- * _ = <Component rows={ [{ render: () => <div /> }] } />
1188
- * ` ^^^^^^^^^^^^^ `
1189
- * ```
1190
- * @internal
1191
- * @param node The AST node to check
1192
- * @returns `true` if component is declared inside a render property, `false` if not
1193
- */
1194
- function isDirectValueOfRenderPropertyLoose(node) {
1195
- const matching = (node) => {
1196
- return node.type === AST_NODE_TYPES.Property && node.key.type === AST_NODE_TYPES.Identifier && node.key.name.startsWith("render");
1197
- };
1198
- return matching(node) || node.parent != null && matching(node.parent);
1199
- }
1200
- /**
1201
- * Unsafe check whether given node is declared inside a render prop
1202
- * ```tsx
1203
- * _ = <Component renderRow={"node"} />
1204
- * ` ^^^^^^ `
1205
- * _ = <Component rows={ [{ render: "node" }] } />
1206
- * ` ^^^^^^ `
1207
- * ```
1208
- * @param node The AST node to check
1209
- * @returns `true` if component is declared inside a render prop, `false` if not
1210
- */
1211
- function isDeclaredInRenderPropLoose(node) {
1212
- if (isDirectValueOfRenderPropertyLoose(node)) return true;
1213
- const parent = ast.findParentNode(node, ast.is(AST_NODE_TYPES.JSXExpressionContainer))?.parent;
1214
- if (parent?.type !== AST_NODE_TYPES.JSXAttribute) return false;
1215
- return parent.name.type === AST_NODE_TYPES.JSXIdentifier && parent.name.name.startsWith("render");
1216
- }
1217
1202
 
1218
1203
  //#endregion
1219
1204
  //#region src/hierarchy/find-enclosing-component-or-hook.ts
@@ -1255,12 +1240,18 @@ function isInsideComponentOrHook(node) {
1255
1240
  * @param name The name to check
1256
1241
  * @returns True if the name is "ref" or ends with "Ref"
1257
1242
  */
1258
- function isRefName(name) {
1243
+ function isRefLikeName(name) {
1259
1244
  return name === "ref" || name.endsWith("Ref");
1260
1245
  }
1261
1246
 
1262
1247
  //#endregion
1263
- //#region src/ref/is-from-ref.ts
1248
+ //#region src/ref/ref-id.ts
1249
+ function isRefId(node) {
1250
+ return node.type === AST_NODE_TYPES.Identifier && isRefLikeName(node.name);
1251
+ }
1252
+
1253
+ //#endregion
1254
+ //#region src/ref/ref-init.ts
1264
1255
  /**
1265
1256
  * Check if the variable with the given name is initialized or derived from a ref
1266
1257
  * @param name The variable name
@@ -1282,7 +1273,7 @@ function getRefInit(name, initialScope) {
1282
1273
  const init = node.init;
1283
1274
  if (init == null) continue;
1284
1275
  switch (true) {
1285
- case init.type === AST_NODE_TYPES$1.MemberExpression && init.object.type === AST_NODE_TYPES$1.Identifier && isRefName(init.object.name): return init;
1276
+ case init.type === AST_NODE_TYPES$1.MemberExpression && init.object.type === AST_NODE_TYPES$1.Identifier && isRefLikeName(init.object.name): return init;
1286
1277
  case init.type === AST_NODE_TYPES$1.CallExpression && isUseRefCall(init): return init;
1287
1278
  }
1288
1279
  }
@@ -1290,4 +1281,4 @@ function getRefInit(name, initialScope) {
1290
1281
  }
1291
1282
 
1292
1283
  //#endregion
1293
- export { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, findEnclosingComponentOrHook, findParentJsxAttribute, getComponentFlagFromInitPath, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, getRefInit, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHook, isHookCall, isHookCallWithName, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isInitializedFromRef, isInsideComponentOrHook, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRefName, isRender, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall, resolveJsxAttributeValue, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
1284
+ export { ComponentDetectionHint, ComponentFlag, DEFAULT_COMPONENT_DETECTION_HINT, DEFAULT_JSX_DETECTION_HINT, JsxDetectionHint, JsxEmit, REACT_BUILTIN_HOOK_NAMES, findEnclosingComponentOrHook, findParentJsxAttribute, getComponentFlagFromInitPath, getFunctionComponentId, getJsxAttribute, getJsxAttributeName, getJsxConfigFromAnnotation, getJsxConfigFromContext, getJsxElementType, getRefInit, isAssignmentToThisState, isCaptureOwnerStack, isCaptureOwnerStackCall, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDefinition, isComponentDidCatch, isComponentDidMount, isComponentDidMountCallback, isComponentDidUpdate, isComponentName, isComponentNameLoose, isComponentWillMount, isComponentWillReceiveProps, isComponentWillUnmount, isComponentWillUnmountCallback, isComponentWillUpdate, isComponentWrapperCall, isComponentWrapperCallLoose, isComponentWrapperCallback, isComponentWrapperCallbackLoose, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFunctionWithLooseComponentName, isGetChildContext, isGetDefaultProps, isGetDerivedStateFromError, isGetDerivedStateFromProps, isGetInitialState, isGetSnapshotBeforeUpdate, isHook, isHookCall, isHookCallWithName, isHookId, isHookName, isInitializedFromReact, isInitializedFromReactNative, isInitializedFromRef, isInsideComponentOrHook, isJsxFragmentElement, isJsxHostElement, isJsxLike, isJsxText, isLazy, isLazyCall, isMemo, isMemoCall, isPureComponent, isReactAPI, isReactAPICall, isRefId, isRefLikeName, isRender, isRenderFunctionLoose, isRenderMethodCallback, isRenderMethodLike, isRenderPropLoose, isShouldComponentUpdate, isThisSetState, isUnsafeComponentWillMount, isUnsafeComponentWillReceiveProps, isUnsafeComponentWillUpdate, isUseActionStateCall, isUseCall, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCleanupCallback, isUseEffectLikeCall, isUseEffectSetupCallback, isUseFormStatusCall, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseOptimisticCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseStateLikeCall, isUseSyncExternalStoreCall, isUseTransitionCall, resolveJsxAttributeValue, stringifyJsx, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-react/core",
3
- "version": "3.0.0-next.4",
3
+ "version": "3.0.0-next.41",
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": {
@@ -30,14 +30,14 @@
30
30
  "./package.json"
31
31
  ],
32
32
  "dependencies": {
33
- "@typescript-eslint/scope-manager": "^8.56.0",
34
- "@typescript-eslint/types": "^8.56.0",
35
- "@typescript-eslint/utils": "^8.56.0",
33
+ "@typescript-eslint/scope-manager": "canary",
34
+ "@typescript-eslint/types": "canary",
35
+ "@typescript-eslint/utils": "canary",
36
36
  "ts-pattern": "^5.9.0",
37
- "@eslint-react/ast": "3.0.0-next.4",
38
- "@eslint-react/var": "3.0.0-next.4",
39
- "@eslint-react/shared": "3.0.0-next.4",
40
- "@eslint-react/eff": "3.0.0-next.4"
37
+ "@eslint-react/ast": "3.0.0-next.41",
38
+ "@eslint-react/eff": "3.0.0-next.41",
39
+ "@eslint-react/var": "3.0.0-next.41",
40
+ "@eslint-react/shared": "3.0.0-next.41"
41
41
  },
42
42
  "devDependencies": {
43
43
  "tsdown": "^0.20.3",
@@ -54,6 +54,6 @@
54
54
  "build": "tsdown --dts-resolve",
55
55
  "build:docs": "typedoc",
56
56
  "lint:publish": "publint",
57
- "lint:ts": "tsc --noEmit"
57
+ "lint:ts": "tsl"
58
58
  }
59
59
  }