@eslint-react/core 1.24.0-beta.1 → 1.24.0-beta.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +152 -140
- package/dist/index.d.ts +152 -140
- package/dist/index.js +160 -158
- package/dist/index.mjs +144 -148
- package/package.json +12 -12
package/dist/index.mjs
CHANGED
|
@@ -1,35 +1,13 @@
|
|
|
1
1
|
import * as AST8 from '@eslint-react/ast';
|
|
2
|
-
import { flip,
|
|
3
|
-
import * as
|
|
2
|
+
import { flip, dual, _, returnFalse } from '@eslint-react/eff';
|
|
3
|
+
import * as JSX3 from '@eslint-react/jsx';
|
|
4
|
+
import { unsafeDecodeSettings, DEFAULT_ESLINT_REACT_SETTINGS, getId } from '@eslint-react/shared';
|
|
4
5
|
import { AST_NODE_TYPES } from '@typescript-eslint/types';
|
|
5
6
|
import * as VAR from '@eslint-react/var';
|
|
6
|
-
import
|
|
7
|
+
import birecord from 'birecord';
|
|
7
8
|
|
|
8
9
|
// src/component/component-collector.ts
|
|
9
|
-
function
|
|
10
|
-
const name = JSX4.getElementName(node);
|
|
11
|
-
if (name === name.toLowerCase()) return [name, name];
|
|
12
|
-
const component = additionalComponents.findLast((c) => c.name === name || c.re.test(name));
|
|
13
|
-
if (component != null) return [name, component.as];
|
|
14
|
-
if (polymorphicPropName == null) return [name, name];
|
|
15
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
16
|
-
const polymorphicProp = JSX4.findPropInAttributes(
|
|
17
|
-
polymorphicPropName,
|
|
18
|
-
initialScope,
|
|
19
|
-
node.attributes
|
|
20
|
-
);
|
|
21
|
-
if (polymorphicProp == null) return [name, name];
|
|
22
|
-
const polymorphicName = VAR.toResolved(JSX4.getPropValue(polymorphicProp, initialScope)).value;
|
|
23
|
-
if (typeof polymorphicName === "string") {
|
|
24
|
-
return [name, polymorphicName];
|
|
25
|
-
}
|
|
26
|
-
return [name, name];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// src/utils/get-id.ts
|
|
30
|
-
var id = 0n;
|
|
31
|
-
var getId = () => (id++).toString();
|
|
32
|
-
function isInitializedFromReact(name, initialScope, importSource = "react") {
|
|
10
|
+
function isInitializedFromReact(name, importSource, initialScope) {
|
|
33
11
|
return name.toLowerCase() === "react" || VAR.isInitializedFromSource(
|
|
34
12
|
name,
|
|
35
13
|
importSource,
|
|
@@ -47,12 +25,13 @@ function isFromReact(name) {
|
|
|
47
25
|
}
|
|
48
26
|
return node.name === name;
|
|
49
27
|
}
|
|
28
|
+
const importSource = settings.importSource ?? DEFAULT_ESLINT_REACT_SETTINGS.importSource;
|
|
50
29
|
const initialScope = context.sourceCode.getScope(node);
|
|
51
30
|
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
52
|
-
return node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name,
|
|
31
|
+
return node.object.type === AST_NODE_TYPES.Identifier && node.property.type === AST_NODE_TYPES.Identifier && node.property.name === name && isInitializedFromReact(node.object.name, importSource, initialScope);
|
|
53
32
|
}
|
|
54
33
|
if (node.name === name) {
|
|
55
|
-
return isInitializedFromReact(name,
|
|
34
|
+
return isInitializedFromReact(name, importSource, initialScope);
|
|
56
35
|
}
|
|
57
36
|
return false;
|
|
58
37
|
};
|
|
@@ -72,14 +51,15 @@ function isFromReactMember(memberName, name) {
|
|
|
72
51
|
}
|
|
73
52
|
return false;
|
|
74
53
|
}
|
|
54
|
+
const importSource = settings.importSource ?? DEFAULT_ESLINT_REACT_SETTINGS.importSource;
|
|
75
55
|
const initialScope = context.sourceCode.getScope(node);
|
|
76
56
|
if (node.property.type !== AST_NODE_TYPES.Identifier || node.property.name !== name) {
|
|
77
57
|
return false;
|
|
78
58
|
}
|
|
79
59
|
if (node.object.type === AST_NODE_TYPES.Identifier && node.object.name === memberName) {
|
|
80
|
-
return isInitializedFromReact(node.object.name,
|
|
60
|
+
return isInitializedFromReact(node.object.name, importSource, initialScope);
|
|
81
61
|
}
|
|
82
|
-
if (node.object.type === AST_NODE_TYPES.MemberExpression && node.object.object.type === AST_NODE_TYPES.Identifier && isInitializedFromReact(node.object.object.name,
|
|
62
|
+
if (node.object.type === AST_NODE_TYPES.MemberExpression && node.object.object.type === AST_NODE_TYPES.Identifier && isInitializedFromReact(node.object.object.name, importSource, initialScope) && node.object.property.type === AST_NODE_TYPES.Identifier) {
|
|
83
63
|
return node.object.property.name === memberName;
|
|
84
64
|
}
|
|
85
65
|
return false;
|
|
@@ -140,9 +120,9 @@ var isMemoCall = isReactAPICallWithName("memo");
|
|
|
140
120
|
|
|
141
121
|
// src/element/hierarchy.ts
|
|
142
122
|
function isInsideCreateElementProps(node, context) {
|
|
143
|
-
const call = AST8.
|
|
123
|
+
const call = AST8.findParentNode(node, isCreateElementCall(context));
|
|
144
124
|
if (call == null) return false;
|
|
145
|
-
const prop = AST8.
|
|
125
|
+
const prop = AST8.findParentNode(node, AST8.is(AST_NODE_TYPES.ObjectExpression));
|
|
146
126
|
if (prop == null) return false;
|
|
147
127
|
return prop === call.arguments[1];
|
|
148
128
|
}
|
|
@@ -162,8 +142,8 @@ function isReactHookName(name) {
|
|
|
162
142
|
// src/hook/is.ts
|
|
163
143
|
function isReactHook(node) {
|
|
164
144
|
if (node == null) return _;
|
|
165
|
-
const
|
|
166
|
-
return
|
|
145
|
+
const id = AST8.getFunctionIdentifier(node);
|
|
146
|
+
return id?.name != null && isReactHookName(id.name);
|
|
167
147
|
}
|
|
168
148
|
function isReactHookCall(node) {
|
|
169
149
|
if (node == null) return false;
|
|
@@ -181,13 +161,14 @@ function isReactHookCall(node) {
|
|
|
181
161
|
function isReactHookCallWithName(node, context) {
|
|
182
162
|
if (node == null) return returnFalse;
|
|
183
163
|
const settings = unsafeDecodeSettings(context.settings);
|
|
164
|
+
const importSource = settings.importSource ?? "react";
|
|
165
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
184
166
|
return (name) => {
|
|
185
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
186
167
|
switch (true) {
|
|
187
168
|
case (node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === name):
|
|
188
|
-
return !settings.strictImportCheck || isInitializedFromReact(name,
|
|
169
|
+
return !settings.strictImportCheck || isInitializedFromReact(name, importSource, initialScope);
|
|
189
170
|
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object):
|
|
190
|
-
return !settings.strictImportCheck || isInitializedFromReact(node.callee.object.name,
|
|
171
|
+
return !settings.strictImportCheck || isInitializedFromReact(node.callee.object.name, importSource, initialScope);
|
|
191
172
|
default:
|
|
192
173
|
return false;
|
|
193
174
|
}
|
|
@@ -208,13 +189,14 @@ function isReactHookCallWithNameLoose(node) {
|
|
|
208
189
|
}
|
|
209
190
|
function isReactHookCallWithNameAlias(name, context, alias) {
|
|
210
191
|
const settings = unsafeDecodeSettings(context);
|
|
192
|
+
const importSource = settings.importSource ?? "react";
|
|
211
193
|
return (node) => {
|
|
212
194
|
const initialScope = context.sourceCode.getScope(node);
|
|
213
195
|
switch (true) {
|
|
214
196
|
case (node.callee.type === AST_NODE_TYPES.Identifier && node.callee.name === name):
|
|
215
|
-
return !settings.strictImportCheck || isInitializedFromReact(name,
|
|
197
|
+
return !settings.strictImportCheck || isInitializedFromReact(name, importSource, initialScope);
|
|
216
198
|
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === name && "name" in node.callee.object):
|
|
217
|
-
return !settings.strictImportCheck || isInitializedFromReact(node.callee.object.name,
|
|
199
|
+
return !settings.strictImportCheck || isInitializedFromReact(node.callee.object.name, importSource, initialScope);
|
|
218
200
|
default:
|
|
219
201
|
return alias.some(isReactHookCallWithNameLoose(node));
|
|
220
202
|
}
|
|
@@ -252,20 +234,20 @@ var isUseTransitionCall = flip(isReactHookCallWithName)("useTransition");
|
|
|
252
234
|
|
|
253
235
|
// src/hook/hierarchy.ts
|
|
254
236
|
function isInsideReactHook(node) {
|
|
255
|
-
return isReactHook(AST8.
|
|
237
|
+
return isReactHook(AST8.findParentNode(node, AST8.isFunction));
|
|
256
238
|
}
|
|
257
239
|
function useHookCollector() {
|
|
258
240
|
const hooks = /* @__PURE__ */ new Map();
|
|
259
241
|
const fEntries = [];
|
|
260
242
|
const onFunctionEnter = (node) => {
|
|
261
|
-
const
|
|
262
|
-
const name =
|
|
243
|
+
const id = AST8.getFunctionIdentifier(node);
|
|
244
|
+
const name = id?.name;
|
|
263
245
|
if (name != null && isReactHookName(name)) {
|
|
264
246
|
const key = getId();
|
|
265
247
|
fEntries.push({ key, node });
|
|
266
248
|
hooks.set(key, {
|
|
267
|
-
|
|
268
|
-
|
|
249
|
+
id,
|
|
250
|
+
key,
|
|
269
251
|
kind: "function",
|
|
270
252
|
name,
|
|
271
253
|
node,
|
|
@@ -304,19 +286,13 @@ function useHookCollector() {
|
|
|
304
286
|
if (hook == null) {
|
|
305
287
|
return;
|
|
306
288
|
}
|
|
307
|
-
|
|
308
|
-
...hook,
|
|
309
|
-
hookCalls: [
|
|
310
|
-
...hook.hookCalls,
|
|
311
|
-
node
|
|
312
|
-
]
|
|
313
|
-
});
|
|
289
|
+
hook.hookCalls.push(node);
|
|
314
290
|
}
|
|
315
291
|
};
|
|
316
292
|
return { ctx, listeners };
|
|
317
293
|
}
|
|
318
294
|
var ERComponentHint = {
|
|
319
|
-
...
|
|
295
|
+
...JSX3.JSXValueHint,
|
|
320
296
|
// 1n << 0n - 1n << 63n are reserved for JSXValueHint
|
|
321
297
|
// Skip function component created by React.memo
|
|
322
298
|
SkipMemo: 1n << 64n,
|
|
@@ -332,6 +308,17 @@ var ERComponentHint = {
|
|
|
332
308
|
SkipClassProperty: 1n << 69n
|
|
333
309
|
};
|
|
334
310
|
var DEFAULT_COMPONENT_HINT = 0n | ERComponentHint.SkipBooleanLiteral | ERComponentHint.SkipMapCallback | ERComponentHint.SkipNumberLiteral | ERComponentHint.SkipStringLiteral | ERComponentHint.SkipUndefined | ERComponentHint.SkipEmptyArray | ERComponentHint.StrictArray | ERComponentHint.StrictConditional | ERComponentHint.StrictLogical;
|
|
311
|
+
var COMPONENT_DISPLAY_NAME_ASSIGNMENT_SELECTOR = [
|
|
312
|
+
"AssignmentExpression",
|
|
313
|
+
"[type]",
|
|
314
|
+
"[operator='=']",
|
|
315
|
+
"[left.type='MemberExpression']",
|
|
316
|
+
"[left.property.name='displayName']"
|
|
317
|
+
].join("");
|
|
318
|
+
function isComponentDisplayNameAssignment(node) {
|
|
319
|
+
if (node == null) return false;
|
|
320
|
+
return node.type === AST_NODE_TYPES.AssignmentExpression && node.operator === "=" && node.left.type === AST_NODE_TYPES.MemberExpression && node.left.property.type === AST_NODE_TYPES.Identifier && node.left.property.name === "displayName";
|
|
321
|
+
}
|
|
335
322
|
|
|
336
323
|
// src/component/component-flag.ts
|
|
337
324
|
var ERClassComponentFlag = {
|
|
@@ -371,14 +358,6 @@ function getFunctionComponentIdentifier(node, context) {
|
|
|
371
358
|
}
|
|
372
359
|
return _;
|
|
373
360
|
}
|
|
374
|
-
var RE_COMPONENT_NAME = /^_?[A-Z]/u;
|
|
375
|
-
function getComponentNameFromIdentifier(node) {
|
|
376
|
-
if (node == null) return _;
|
|
377
|
-
return Array.isArray(node) ? node.map((n) => n.name).join(".") : node.name;
|
|
378
|
-
}
|
|
379
|
-
function isComponentName(name) {
|
|
380
|
-
return RE_COMPONENT_NAME.test(name);
|
|
381
|
-
}
|
|
382
361
|
function isClassComponent(node) {
|
|
383
362
|
if ("superClass" in node && node.superClass != null) {
|
|
384
363
|
const re = /^(?:Pure)?Component$/u;
|
|
@@ -404,9 +383,30 @@ function isPureComponent(node) {
|
|
|
404
383
|
return false;
|
|
405
384
|
}
|
|
406
385
|
|
|
407
|
-
// src/component/component-
|
|
386
|
+
// src/component/component-lifecycle.ts
|
|
387
|
+
function isComponentDidMount(node) {
|
|
388
|
+
return AST8.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "componentDidMount";
|
|
389
|
+
}
|
|
390
|
+
function isComponentWillUnmount(node) {
|
|
391
|
+
return AST8.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "componentWillUnmount";
|
|
392
|
+
}
|
|
393
|
+
function isComponentDidCatch(node) {
|
|
394
|
+
return AST8.isMethodOrProperty(node) && !node.static && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "componentDidCatch";
|
|
395
|
+
}
|
|
396
|
+
function isGetDerivedStateFromError(node) {
|
|
397
|
+
return AST8.isMethodOrProperty(node) && node.static && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "getDerivedStateFromError";
|
|
398
|
+
}
|
|
399
|
+
function isGetDerivedStateFromProps(node) {
|
|
400
|
+
return AST8.isMethodOrProperty(node) && node.static && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "getDerivedStateFromProps";
|
|
401
|
+
}
|
|
402
|
+
function isFunctionOfComponentDidMount(node) {
|
|
403
|
+
return AST8.isFunction(node) && isComponentDidMount(node.parent) && node.parent.value === node;
|
|
404
|
+
}
|
|
405
|
+
function isFunctionOfComponentWillUnmount(node) {
|
|
406
|
+
return AST8.isFunction(node) && isComponentWillUnmount(node.parent) && node.parent.value === node;
|
|
407
|
+
}
|
|
408
408
|
function isRenderMethodLike(node) {
|
|
409
|
-
return (node
|
|
409
|
+
return AST8.isMethodOrProperty(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "render" && node.parent.parent.type === AST_NODE_TYPES.ClassDeclaration;
|
|
410
410
|
}
|
|
411
411
|
function isFunctionOfRenderMethod(node) {
|
|
412
412
|
if (!isRenderMethodLike(node.parent)) {
|
|
@@ -417,12 +417,18 @@ function isFunctionOfRenderMethod(node) {
|
|
|
417
417
|
function isInsideRenderMethod(node) {
|
|
418
418
|
return AST8.findParentNode(node, (node2) => isRenderMethodLike(node2) && isClassComponent(node2.parent.parent)) != null;
|
|
419
419
|
}
|
|
420
|
-
|
|
421
|
-
|
|
420
|
+
var RE_COMPONENT_NAME = /^_?[A-Z]/u;
|
|
421
|
+
function getComponentNameFromIdentifier(node) {
|
|
422
|
+
if (node == null) return _;
|
|
423
|
+
return Array.isArray(node) ? node.map((n) => n.name).join(".") : node.name;
|
|
424
|
+
}
|
|
425
|
+
function isComponentName(name) {
|
|
426
|
+
return RE_COMPONENT_NAME.test(name);
|
|
427
|
+
}
|
|
422
428
|
function hasNoneOrValidComponentName(node, context) {
|
|
423
|
-
const
|
|
424
|
-
if (
|
|
425
|
-
const name = Array.isArray(
|
|
429
|
+
const id = getFunctionComponentIdentifier(node, context);
|
|
430
|
+
if (id == null) return true;
|
|
431
|
+
const name = Array.isArray(id) ? id.at(-1)?.name : id.name;
|
|
426
432
|
return name != null && isComponentName(name);
|
|
427
433
|
}
|
|
428
434
|
|
|
@@ -457,15 +463,16 @@ function hasValidHierarchy(node, context, hint) {
|
|
|
457
463
|
}
|
|
458
464
|
function getComponentFlag(initPath) {
|
|
459
465
|
let flag = ERFunctionComponentFlag.None;
|
|
460
|
-
if (initPath != null && AST8.hasCallInFunctionInitPath("memo"
|
|
466
|
+
if (initPath != null && AST8.hasCallInFunctionInitPath("memo", initPath)) {
|
|
461
467
|
flag |= ERFunctionComponentFlag.Memo;
|
|
462
468
|
}
|
|
463
|
-
if (initPath != null && AST8.hasCallInFunctionInitPath("forwardRef"
|
|
469
|
+
if (initPath != null && AST8.hasCallInFunctionInitPath("forwardRef", initPath)) {
|
|
464
470
|
flag |= ERFunctionComponentFlag.ForwardRef;
|
|
465
471
|
}
|
|
466
472
|
return flag;
|
|
467
473
|
}
|
|
468
|
-
function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
474
|
+
function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT, options = {}) {
|
|
475
|
+
const { collectDisplayName = false, collectHookCalls = false } = options;
|
|
469
476
|
const jsxCtx = { getScope: (node) => context.sourceCode.getScope(node) };
|
|
470
477
|
const components = /* @__PURE__ */ new Map();
|
|
471
478
|
const functionEntries = [];
|
|
@@ -481,7 +488,7 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
481
488
|
return functionEntries.pop();
|
|
482
489
|
}
|
|
483
490
|
const shouldDrop = AST8.getNestedReturnStatements(entry.node.body).slice().reverse().some((r) => {
|
|
484
|
-
return context.sourceCode.getScope(r).block === entry.node && r.argument != null && !
|
|
491
|
+
return context.sourceCode.getScope(r).block === entry.node && r.argument != null && !JSX3.isJSXValue(r.argument, jsxCtx, hint);
|
|
485
492
|
});
|
|
486
493
|
if (shouldDrop) {
|
|
487
494
|
components.delete(entry.key);
|
|
@@ -507,17 +514,17 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
507
514
|
return;
|
|
508
515
|
}
|
|
509
516
|
const { body } = entry.node;
|
|
510
|
-
const isComponent = hasNoneOrValidComponentName(entry.node, context) &&
|
|
517
|
+
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX3.isJSXValue(body, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
511
518
|
if (!isComponent) {
|
|
512
519
|
return;
|
|
513
520
|
}
|
|
514
521
|
const initPath = AST8.getFunctionInitPath(entry.node);
|
|
515
|
-
const
|
|
516
|
-
const name = getComponentNameFromIdentifier(
|
|
522
|
+
const id = getFunctionComponentIdentifier(entry.node, context);
|
|
523
|
+
const name = getComponentNameFromIdentifier(id);
|
|
517
524
|
const key = getId();
|
|
518
525
|
components.set(key, {
|
|
519
|
-
|
|
520
|
-
|
|
526
|
+
id,
|
|
527
|
+
key,
|
|
521
528
|
kind: "function",
|
|
522
529
|
name,
|
|
523
530
|
node: entry.node,
|
|
@@ -528,46 +535,47 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
528
535
|
initPath
|
|
529
536
|
});
|
|
530
537
|
},
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
displayName
|
|
541
|
-
});
|
|
542
|
-
},
|
|
543
|
-
"CallExpression[type]:exit"(node) {
|
|
544
|
-
if (!isReactHookCall(node)) {
|
|
545
|
-
return;
|
|
538
|
+
...collectDisplayName ? {
|
|
539
|
+
[COMPONENT_DISPLAY_NAME_ASSIGNMENT_SELECTOR](node) {
|
|
540
|
+
const { left, right } = node;
|
|
541
|
+
if (left.type !== AST_NODE_TYPES.MemberExpression) return;
|
|
542
|
+
const componentName = left.object.type === AST_NODE_TYPES.Identifier ? left.object.name : _;
|
|
543
|
+
const component = [...components.values()].findLast(({ name }) => name != null && name === componentName);
|
|
544
|
+
if (component == null) {
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
component.displayName = right;
|
|
546
548
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
549
|
+
} : {},
|
|
550
|
+
...collectHookCalls ? {
|
|
551
|
+
"CallExpression[type]:exit"(node) {
|
|
552
|
+
if (!isReactHookCall(node)) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
const entry = getCurrentEntry();
|
|
556
|
+
if (entry == null) {
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
entry.hookCalls.push(node);
|
|
550
560
|
}
|
|
551
|
-
|
|
552
|
-
functionEntries.push({ ...entry, hookCalls: [...entry.hookCalls, node] });
|
|
553
|
-
},
|
|
561
|
+
} : {},
|
|
554
562
|
"ReturnStatement[type]"(node) {
|
|
555
563
|
const entry = getCurrentEntry();
|
|
556
564
|
if (entry == null) {
|
|
557
565
|
return;
|
|
558
566
|
}
|
|
559
|
-
const isComponent = hasNoneOrValidComponentName(entry.node, context) &&
|
|
567
|
+
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX3.isJSXValue(node.argument, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
560
568
|
if (!isComponent) {
|
|
561
569
|
return;
|
|
562
570
|
}
|
|
563
571
|
functionEntries.pop();
|
|
564
572
|
functionEntries.push({ ...entry, isComponent });
|
|
565
573
|
const initPath = AST8.getFunctionInitPath(entry.node);
|
|
566
|
-
const
|
|
567
|
-
const name = getComponentNameFromIdentifier(
|
|
574
|
+
const id = getFunctionComponentIdentifier(entry.node, context);
|
|
575
|
+
const name = getComponentNameFromIdentifier(id);
|
|
568
576
|
components.set(entry.key, {
|
|
569
|
-
|
|
570
|
-
|
|
577
|
+
id,
|
|
578
|
+
key: entry.key,
|
|
571
579
|
kind: "function",
|
|
572
580
|
name,
|
|
573
581
|
node: entry.node,
|
|
@@ -593,16 +601,16 @@ function useComponentCollectorLegacy() {
|
|
|
593
601
|
if (!isClassComponent(node)) {
|
|
594
602
|
return;
|
|
595
603
|
}
|
|
596
|
-
const
|
|
604
|
+
const id = AST8.getClassIdentifier(node);
|
|
597
605
|
const key = getId();
|
|
598
606
|
const flag = isPureComponent(node) ? ERClassComponentFlag.PureComponent : ERClassComponentFlag.None;
|
|
599
607
|
components.set(
|
|
600
608
|
key,
|
|
601
609
|
{
|
|
602
|
-
|
|
603
|
-
|
|
610
|
+
id,
|
|
611
|
+
key,
|
|
604
612
|
kind: "class",
|
|
605
|
-
name:
|
|
613
|
+
name: id?.name,
|
|
606
614
|
node,
|
|
607
615
|
// TODO: Get displayName of class component
|
|
608
616
|
displayName: _,
|
|
@@ -619,60 +627,22 @@ function useComponentCollectorLegacy() {
|
|
|
619
627
|
};
|
|
620
628
|
return { ctx, listeners };
|
|
621
629
|
}
|
|
622
|
-
function isSetupFunction(node) {
|
|
623
|
-
if (node == null) return _;
|
|
624
|
-
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && node.parent.callee.type === AST_NODE_TYPES.Identifier && node.parent.arguments.at(0) === node && isUseEffectCallLoose(node.parent);
|
|
625
|
-
}
|
|
626
|
-
function isCleanupFunction(node) {
|
|
627
|
-
const nearReturn = AST8.findParentNodeGuard(node, AST8.is(AST_NODE_TYPES.ReturnStatement));
|
|
628
|
-
const nearFunction = AST8.findParentNodeGuard(node, AST8.isFunction);
|
|
629
|
-
const nearFunctionOfReturn = AST8.findParentNodeGuard(nearReturn, AST8.isFunction);
|
|
630
|
-
return nearFunction === nearFunctionOfReturn && isSetupFunction(nearFunction);
|
|
631
|
-
}
|
|
632
|
-
function isComponentDidMount(node) {
|
|
633
|
-
return AST8.isOneOf([AST_NODE_TYPES.MethodDefinition, AST_NODE_TYPES.PropertyDefinition])(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "componentDidMount";
|
|
634
|
-
}
|
|
635
|
-
function isComponentWillUnmount(node) {
|
|
636
|
-
return AST8.isOneOf([AST_NODE_TYPES.MethodDefinition, AST_NODE_TYPES.PropertyDefinition])(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "componentWillUnmount";
|
|
637
|
-
}
|
|
638
|
-
function isComponentDidMountFunction(node) {
|
|
639
|
-
return AST8.isFunction(node) && isComponentDidMount(node.parent) && node.parent.value === node;
|
|
640
|
-
}
|
|
641
|
-
function isComponentWillUnmountFunction(node) {
|
|
642
|
-
return AST8.isFunction(node) && isComponentWillUnmount(node.parent) && node.parent.value === node;
|
|
643
|
-
}
|
|
644
630
|
var ERPhaseRelevance = birecord({
|
|
645
631
|
mount: "unmount",
|
|
646
632
|
setup: "cleanup"
|
|
647
633
|
});
|
|
648
634
|
var isInversePhase = dual(2, (a, b) => ERPhaseRelevance.get(a) === b);
|
|
649
|
-
function isDirectValueOfRenderPropertyLoose(node) {
|
|
650
|
-
const matching = (node2) => {
|
|
651
|
-
return node2.type === AST_NODE_TYPES.Property && node2.key.type === AST_NODE_TYPES.Identifier && node2.key.name.startsWith("render");
|
|
652
|
-
};
|
|
653
|
-
return matching(node) || node.parent != null && matching(node.parent);
|
|
654
|
-
}
|
|
655
|
-
function isDeclaredInRenderPropLoose(node) {
|
|
656
|
-
if (isDirectValueOfRenderPropertyLoose(node)) {
|
|
657
|
-
return true;
|
|
658
|
-
}
|
|
659
|
-
const parent = AST8.findParentNodeGuard(node, AST8.is(AST_NODE_TYPES.JSXExpressionContainer))?.parent;
|
|
660
|
-
if (parent?.type !== AST_NODE_TYPES.JSXAttribute) {
|
|
661
|
-
return false;
|
|
662
|
-
}
|
|
663
|
-
return parent.name.type === AST_NODE_TYPES.JSXIdentifier && parent.name.name.startsWith("render");
|
|
664
|
-
}
|
|
665
635
|
function isRenderFunctionLoose(node, context) {
|
|
666
636
|
const { body, parent } = node;
|
|
667
637
|
if (AST8.getFunctionIdentifier(node)?.name.startsWith("render")) {
|
|
668
638
|
return parent.type === AST_NODE_TYPES.JSXExpressionContainer && parent.parent.type === AST_NODE_TYPES.JSXAttribute && parent.parent.name.type === AST_NODE_TYPES.JSXIdentifier && parent.parent.name.name.startsWith("render");
|
|
669
639
|
}
|
|
670
|
-
return
|
|
640
|
+
return JSX3.isJSXValue(
|
|
671
641
|
body,
|
|
672
642
|
{
|
|
673
643
|
getScope: (node2) => context.sourceCode.getScope(node2)
|
|
674
644
|
},
|
|
675
|
-
|
|
645
|
+
JSX3.JSXValueHint.SkipNullLiteral | JSX3.JSXValueHint.SkipUndefined | JSX3.JSXValueHint.StrictLogical | JSX3.JSXValueHint.StrictConditional
|
|
676
646
|
);
|
|
677
647
|
}
|
|
678
648
|
function isRenderPropLoose(node, context) {
|
|
@@ -681,9 +651,35 @@ function isRenderPropLoose(node, context) {
|
|
|
681
651
|
}
|
|
682
652
|
return node.name.name.startsWith("render") && node.value?.type === AST_NODE_TYPES.JSXExpressionContainer && AST8.isFunction(node.value.expression) && isRenderFunctionLoose(node.value.expression, context);
|
|
683
653
|
}
|
|
654
|
+
function isDirectValueOfRenderPropertyLoose(node) {
|
|
655
|
+
const matching = (node2) => {
|
|
656
|
+
return node2.type === AST_NODE_TYPES.Property && node2.key.type === AST_NODE_TYPES.Identifier && node2.key.name.startsWith("render");
|
|
657
|
+
};
|
|
658
|
+
return matching(node) || node.parent != null && matching(node.parent);
|
|
659
|
+
}
|
|
660
|
+
function isDeclaredInRenderPropLoose(node) {
|
|
661
|
+
if (isDirectValueOfRenderPropertyLoose(node)) {
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
const parent = AST8.findParentNode(node, AST8.is(AST_NODE_TYPES.JSXExpressionContainer))?.parent;
|
|
665
|
+
if (parent?.type !== AST_NODE_TYPES.JSXAttribute) {
|
|
666
|
+
return false;
|
|
667
|
+
}
|
|
668
|
+
return parent.name.type === AST_NODE_TYPES.JSXIdentifier && parent.name.name.startsWith("render");
|
|
669
|
+
}
|
|
684
670
|
function isThisSetState(node) {
|
|
685
671
|
const { callee } = node;
|
|
686
672
|
return callee.type === AST_NODE_TYPES.MemberExpression && AST8.isThisExpression(callee.object) && callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === "setState";
|
|
687
673
|
}
|
|
674
|
+
function isFunctionOfUseEffectSetup(node) {
|
|
675
|
+
if (node == null) return _;
|
|
676
|
+
return node.parent?.type === AST_NODE_TYPES.CallExpression && node.parent.callee !== node && node.parent.callee.type === AST_NODE_TYPES.Identifier && node.parent.arguments.at(0) === node && isUseEffectCallLoose(node.parent);
|
|
677
|
+
}
|
|
678
|
+
function isFunctionOfUseEffectCleanup(node) {
|
|
679
|
+
const nearReturn = AST8.findParentNode(node, AST8.is(AST_NODE_TYPES.ReturnStatement));
|
|
680
|
+
const nearFunction = AST8.findParentNode(node, AST8.isFunction);
|
|
681
|
+
const nearFunctionOfReturn = AST8.findParentNode(nearReturn, AST8.isFunction);
|
|
682
|
+
return nearFunction === nearFunctionOfReturn && isFunctionOfUseEffectSetup(nearFunction);
|
|
683
|
+
}
|
|
688
684
|
|
|
689
|
-
export { DEFAULT_COMPONENT_HINT, ERClassComponentFlag, ERComponentHint, ERFunctionComponentFlag, ERPhaseRelevance, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier,
|
|
685
|
+
export { COMPONENT_DISPLAY_NAME_ASSIGNMENT_SELECTOR, DEFAULT_COMPONENT_HINT, ERClassComponentFlag, ERComponentHint, ERFunctionComponentFlag, ERPhaseRelevance, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier, getFunctionComponentIdentifier, hasNoneOrValidComponentName, isCallFromReact, isCallFromReactMember, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCloneElement, isCloneElementCall, isComponentDidCatch, isComponentDidMount, isComponentDisplayNameAssignment, isComponentName, isComponentWillUnmount, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFromReact, isFromReactMember, isFunctionOfComponentDidMount, isFunctionOfComponentWillUnmount, isFunctionOfRenderMethod, isFunctionOfUseEffectCleanup, isFunctionOfUseEffectSetup, isGetDerivedStateFromError, isGetDerivedStateFromProps, isInitializedFromReact, isInsideCreateElementProps, isInsideReactHook, isInsideRenderMethod, isInversePhase, isMemo, isMemoCall, isPureComponent, isReactAPICallWithName, isReactAPIWithName, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookName, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isThisSetState, isUseCallbackCall, isUseContextCall, isUseDebugValueCall, isUseDeferredValueCall, isUseEffectCall, isUseEffectCallLoose, isUseIdCall, isUseImperativeHandleCall, isUseInsertionEffectCall, isUseLayoutEffectCall, isUseMemoCall, isUseReducerCall, isUseRefCall, isUseStateCall, isUseSyncExternalStoreCall, isUseTransitionCall, useComponentCollector, useComponentCollectorLegacy, useHookCollector };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/core",
|
|
3
|
-
"version": "1.24.0-beta.
|
|
3
|
+
"version": "1.24.0-beta.18",
|
|
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": {
|
|
@@ -33,17 +33,17 @@
|
|
|
33
33
|
"./package.json"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@typescript-eslint/scope-manager": "^8.
|
|
37
|
-
"@typescript-eslint/type-utils": "^8.
|
|
38
|
-
"@typescript-eslint/types": "^8.
|
|
39
|
-
"@typescript-eslint/utils": "^8.
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"@eslint-react/
|
|
43
|
-
"@eslint-react/
|
|
44
|
-
"@eslint-react/
|
|
45
|
-
"@eslint-react/
|
|
46
|
-
"@eslint-react/
|
|
36
|
+
"@typescript-eslint/scope-manager": "^8.20.0",
|
|
37
|
+
"@typescript-eslint/type-utils": "^8.20.0",
|
|
38
|
+
"@typescript-eslint/types": "^8.20.0",
|
|
39
|
+
"@typescript-eslint/utils": "^8.20.0",
|
|
40
|
+
"birecord": "^0.1.1",
|
|
41
|
+
"ts-pattern": "^5.6.1",
|
|
42
|
+
"@eslint-react/ast": "1.24.0-beta.18",
|
|
43
|
+
"@eslint-react/eff": "1.24.0-beta.18",
|
|
44
|
+
"@eslint-react/jsx": "1.24.0-beta.18",
|
|
45
|
+
"@eslint-react/var": "1.24.0-beta.18",
|
|
46
|
+
"@eslint-react/shared": "1.24.0-beta.18"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"tsup": "^8.3.5",
|