@eslint-react/core 1.23.3-next.7 → 1.24.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +47 -45
- package/dist/index.d.ts +47 -45
- package/dist/index.js +186 -208
- package/dist/index.mjs +140 -162
- package/package.json +10 -10
package/dist/index.mjs
CHANGED
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
import * as AST8 from '@eslint-react/ast';
|
|
2
|
-
import {
|
|
2
|
+
import { flip, birecord, dual, _, returnFalse } from '@eslint-react/eff';
|
|
3
3
|
import * as JSX4 from '@eslint-react/jsx';
|
|
4
4
|
import { AST_NODE_TYPES } from '@typescript-eslint/types';
|
|
5
|
-
import { match } from 'ts-pattern';
|
|
6
|
-
import { getSettingsFromContext, unsafeDecodeSettings } from '@eslint-react/shared';
|
|
7
5
|
import * as VAR from '@eslint-react/var';
|
|
8
|
-
import {
|
|
6
|
+
import { unsafeDecodeSettings } from '@eslint-react/shared';
|
|
9
7
|
|
|
10
8
|
// src/component/component-collector.ts
|
|
11
|
-
function
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
O.fromNullable(polymorphicPropName),
|
|
23
|
-
O.flatMap(JSX4.findPropInAttributes(node.attributes, context.sourceCode.getScope(node))),
|
|
24
|
-
O.flatMap((attr) => JSX4.getPropValue(attr, context.sourceCode.getScope(attr))),
|
|
25
|
-
O.filter(isString),
|
|
26
|
-
O.getOrElse(() => rawElementName)
|
|
9
|
+
function getElementNameAndRepresentName(node, context, polymorphicPropName, additionalComponents = []) {
|
|
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 !== _) 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
|
|
27
20
|
);
|
|
21
|
+
if (polymorphicProp === _) 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];
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
// src/utils/get-id.ts
|
|
@@ -87,7 +86,7 @@ function isFromReactMember(memberName, name) {
|
|
|
87
86
|
};
|
|
88
87
|
}
|
|
89
88
|
function isCallFromReact(name) {
|
|
90
|
-
return
|
|
89
|
+
return dual(2, (node, context) => {
|
|
91
90
|
if (node.type !== AST_NODE_TYPES.CallExpression) {
|
|
92
91
|
return false;
|
|
93
92
|
}
|
|
@@ -98,7 +97,7 @@ function isCallFromReact(name) {
|
|
|
98
97
|
});
|
|
99
98
|
}
|
|
100
99
|
function isCallFromReactMember(pragmaMemberName, name) {
|
|
101
|
-
return
|
|
100
|
+
return dual(2, (node, context) => {
|
|
102
101
|
if (node.type !== AST_NODE_TYPES.CallExpression) {
|
|
103
102
|
return false;
|
|
104
103
|
}
|
|
@@ -111,10 +110,10 @@ function isCallFromReactMember(pragmaMemberName, name) {
|
|
|
111
110
|
|
|
112
111
|
// src/utils/is-react-api.ts
|
|
113
112
|
function isReactAPIWithName(name, member) {
|
|
114
|
-
return member
|
|
113
|
+
return member != null ? isFromReactMember(name, member) : isFromReact(name);
|
|
115
114
|
}
|
|
116
115
|
function isReactAPICallWithName(name, member) {
|
|
117
|
-
return member
|
|
116
|
+
return member != null ? isCallFromReactMember(name, member) : isCallFromReact(name);
|
|
118
117
|
}
|
|
119
118
|
var isChildrenCount = isReactAPIWithName("Children", "count");
|
|
120
119
|
var isChildrenForEach = isReactAPIWithName("Children", "forEach");
|
|
@@ -141,23 +140,17 @@ var isMemoCall = isReactAPICallWithName("memo");
|
|
|
141
140
|
|
|
142
141
|
// src/element/hierarchy.ts
|
|
143
142
|
function isInsideCreateElementProps(node, context) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
O.exists(({ arg1, prop }) => prop === arg1)
|
|
150
|
-
);
|
|
143
|
+
const call = AST8.findParentNodeGuard(node, isCreateElementCall(context));
|
|
144
|
+
if (!call) return false;
|
|
145
|
+
const prop = AST8.findParentNodeGuard(node, AST8.is(AST_NODE_TYPES.ObjectExpression));
|
|
146
|
+
if (!prop) return false;
|
|
147
|
+
return prop === call.arguments[1];
|
|
151
148
|
}
|
|
152
149
|
function isChildrenOfCreateElement(node, context) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
O.exists(
|
|
158
|
-
(n) => n.arguments.slice(2).some((arg) => arg === node)
|
|
159
|
-
)
|
|
160
|
-
);
|
|
150
|
+
const parent = node.parent;
|
|
151
|
+
if (!parent || parent.type !== AST_NODE_TYPES.CallExpression) return false;
|
|
152
|
+
if (!isCreateElementCall(parent, context)) return false;
|
|
153
|
+
return parent.arguments.slice(2).some((arg) => arg === node);
|
|
161
154
|
}
|
|
162
155
|
|
|
163
156
|
// src/hook/hook-name.ts
|
|
@@ -168,13 +161,12 @@ function isReactHookName(name) {
|
|
|
168
161
|
|
|
169
162
|
// src/hook/is.ts
|
|
170
163
|
function isReactHook(node) {
|
|
171
|
-
return
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
O.exists(isReactHookName)
|
|
175
|
-
);
|
|
164
|
+
if (node === _) return _;
|
|
165
|
+
const id2 = AST8.getFunctionIdentifier(node);
|
|
166
|
+
return id2?.name !== _ && isReactHookName(id2.name);
|
|
176
167
|
}
|
|
177
168
|
function isReactHookCall(node) {
|
|
169
|
+
if (node === _) return false;
|
|
178
170
|
if (node.type !== AST_NODE_TYPES.CallExpression) {
|
|
179
171
|
return false;
|
|
180
172
|
}
|
|
@@ -187,6 +179,7 @@ function isReactHookCall(node) {
|
|
|
187
179
|
return false;
|
|
188
180
|
}
|
|
189
181
|
function isReactHookCallWithName(node, context) {
|
|
182
|
+
if (node === _) return returnFalse;
|
|
190
183
|
const settings = unsafeDecodeSettings(context.settings);
|
|
191
184
|
return (name) => {
|
|
192
185
|
const initialScope = context.sourceCode.getScope(node);
|
|
@@ -201,6 +194,7 @@ function isReactHookCallWithName(node, context) {
|
|
|
201
194
|
};
|
|
202
195
|
}
|
|
203
196
|
function isReactHookCallWithNameLoose(node) {
|
|
197
|
+
if (node === _) return returnFalse;
|
|
204
198
|
return (name) => {
|
|
205
199
|
switch (node.callee.type) {
|
|
206
200
|
case AST_NODE_TYPES.Identifier:
|
|
@@ -227,6 +221,7 @@ function isReactHookCallWithNameAlias(name, context, alias) {
|
|
|
227
221
|
};
|
|
228
222
|
}
|
|
229
223
|
function isUseEffectCallLoose(node) {
|
|
224
|
+
if (node === _) return false;
|
|
230
225
|
if (node.type !== AST_NODE_TYPES.CallExpression) {
|
|
231
226
|
return false;
|
|
232
227
|
}
|
|
@@ -239,35 +234,35 @@ function isUseEffectCallLoose(node) {
|
|
|
239
234
|
return false;
|
|
240
235
|
}
|
|
241
236
|
}
|
|
242
|
-
var isUseCallbackCall =
|
|
243
|
-
var isUseContextCall =
|
|
244
|
-
var isUseDebugValueCall =
|
|
245
|
-
var isUseDeferredValueCall =
|
|
246
|
-
var isUseEffectCall =
|
|
247
|
-
var isUseIdCall =
|
|
248
|
-
var isUseImperativeHandleCall =
|
|
249
|
-
var isUseInsertionEffectCall =
|
|
250
|
-
var isUseLayoutEffectCall =
|
|
251
|
-
var isUseMemoCall =
|
|
252
|
-
var isUseReducerCall =
|
|
253
|
-
var isUseRefCall =
|
|
254
|
-
var isUseStateCall =
|
|
255
|
-
var isUseSyncExternalStoreCall =
|
|
256
|
-
var isUseTransitionCall =
|
|
237
|
+
var isUseCallbackCall = flip(isReactHookCallWithName)("useCallback");
|
|
238
|
+
var isUseContextCall = flip(isReactHookCallWithName)("useContext");
|
|
239
|
+
var isUseDebugValueCall = flip(isReactHookCallWithName)("useDebugValue");
|
|
240
|
+
var isUseDeferredValueCall = flip(isReactHookCallWithName)("useDeferredValue");
|
|
241
|
+
var isUseEffectCall = flip(isReactHookCallWithName)("useEffect");
|
|
242
|
+
var isUseIdCall = flip(isReactHookCallWithName)("useId");
|
|
243
|
+
var isUseImperativeHandleCall = flip(isReactHookCallWithName)("useImperativeHandle");
|
|
244
|
+
var isUseInsertionEffectCall = flip(isReactHookCallWithName)("useInsertionEffect");
|
|
245
|
+
var isUseLayoutEffectCall = flip(isReactHookCallWithName)("useLayoutEffect");
|
|
246
|
+
var isUseMemoCall = flip(isReactHookCallWithName)("useMemo");
|
|
247
|
+
var isUseReducerCall = flip(isReactHookCallWithName)("useReducer");
|
|
248
|
+
var isUseRefCall = flip(isReactHookCallWithName)("useRef");
|
|
249
|
+
var isUseStateCall = flip(isReactHookCallWithName)("useState");
|
|
250
|
+
var isUseSyncExternalStoreCall = flip(isReactHookCallWithName)("useSyncExternalStore");
|
|
251
|
+
var isUseTransitionCall = flip(isReactHookCallWithName)("useTransition");
|
|
257
252
|
|
|
258
253
|
// src/hook/hierarchy.ts
|
|
259
254
|
function isInsideReactHook(node) {
|
|
260
|
-
return
|
|
255
|
+
return isReactHook(AST8.findParentNodeGuard(node, AST8.isFunction));
|
|
261
256
|
}
|
|
262
257
|
function useHookCollector() {
|
|
263
258
|
const hooks = /* @__PURE__ */ new Map();
|
|
264
|
-
const
|
|
259
|
+
const fEntries = [];
|
|
265
260
|
const onFunctionEnter = (node) => {
|
|
266
261
|
const id2 = AST8.getFunctionIdentifier(node);
|
|
267
|
-
const name =
|
|
268
|
-
if (
|
|
262
|
+
const name = id2?.name;
|
|
263
|
+
if (name !== _ && isReactHookName(name)) {
|
|
269
264
|
const key = getId();
|
|
270
|
-
|
|
265
|
+
fEntries.push({ key, node });
|
|
271
266
|
hooks.set(key, {
|
|
272
267
|
_: key,
|
|
273
268
|
id: id2,
|
|
@@ -280,13 +275,14 @@ function useHookCollector() {
|
|
|
280
275
|
});
|
|
281
276
|
return;
|
|
282
277
|
}
|
|
283
|
-
|
|
278
|
+
fEntries.push({ key: _, node });
|
|
284
279
|
};
|
|
285
280
|
const onFunctionExit = () => {
|
|
286
|
-
|
|
281
|
+
fEntries.pop();
|
|
287
282
|
};
|
|
288
283
|
const ctx = {
|
|
289
|
-
|
|
284
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
285
|
+
getAllHooks(node) {
|
|
290
286
|
return hooks;
|
|
291
287
|
},
|
|
292
288
|
getCurrentHooks() {
|
|
@@ -300,24 +296,21 @@ function useHookCollector() {
|
|
|
300
296
|
if (!isReactHookCall(node)) {
|
|
301
297
|
return;
|
|
302
298
|
}
|
|
303
|
-
const
|
|
304
|
-
if (
|
|
299
|
+
const fEntry = fEntries.at(-1);
|
|
300
|
+
if (fEntry?.key === _) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const hook = hooks.get(fEntry.key);
|
|
304
|
+
if (hook === _) {
|
|
305
305
|
return;
|
|
306
306
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
hookCalls: [
|
|
315
|
-
...hook.hookCalls,
|
|
316
|
-
node
|
|
317
|
-
]
|
|
318
|
-
});
|
|
319
|
-
})
|
|
320
|
-
);
|
|
307
|
+
hooks.set(hook._, {
|
|
308
|
+
...hook,
|
|
309
|
+
hookCalls: [
|
|
310
|
+
...hook.hookCalls,
|
|
311
|
+
node
|
|
312
|
+
]
|
|
313
|
+
});
|
|
321
314
|
}
|
|
322
315
|
};
|
|
323
316
|
return { ctx, listeners };
|
|
@@ -366,17 +359,17 @@ function isComponentWrapperCall(node, context) {
|
|
|
366
359
|
}
|
|
367
360
|
function getFunctionComponentIdentifier(node, context) {
|
|
368
361
|
const functionId = AST8.getFunctionIdentifier(node);
|
|
369
|
-
if (
|
|
362
|
+
if (functionId) {
|
|
370
363
|
return functionId;
|
|
371
364
|
}
|
|
372
365
|
const { parent } = node;
|
|
373
366
|
if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCall(parent, context) && parent.parent.type === AST_NODE_TYPES.VariableDeclarator && parent.parent.id.type === AST_NODE_TYPES.Identifier) {
|
|
374
|
-
return
|
|
367
|
+
return parent.parent.id;
|
|
375
368
|
}
|
|
376
369
|
if (parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCall(parent, context) && parent.parent.type === AST_NODE_TYPES.CallExpression && isComponentWrapperCall(parent.parent, context) && parent.parent.parent.type === AST_NODE_TYPES.VariableDeclarator && parent.parent.parent.id.type === AST_NODE_TYPES.Identifier) {
|
|
377
|
-
return
|
|
370
|
+
return parent.parent.parent.id;
|
|
378
371
|
}
|
|
379
|
-
return
|
|
372
|
+
return _;
|
|
380
373
|
}
|
|
381
374
|
|
|
382
375
|
// src/component/component-name.ts
|
|
@@ -388,7 +381,7 @@ function isComponentName(name) {
|
|
|
388
381
|
return RE_COMPONENT_NAME.test(name);
|
|
389
382
|
}
|
|
390
383
|
function isClassComponent(node) {
|
|
391
|
-
if ("superClass" in node && node.superClass
|
|
384
|
+
if ("superClass" in node && node.superClass) {
|
|
392
385
|
const re = /^(?:Pure)?Component$/u;
|
|
393
386
|
switch (true) {
|
|
394
387
|
case node.superClass.type === AST_NODE_TYPES.Identifier:
|
|
@@ -400,7 +393,7 @@ function isClassComponent(node) {
|
|
|
400
393
|
return false;
|
|
401
394
|
}
|
|
402
395
|
function isPureComponent(node) {
|
|
403
|
-
if ("superClass" in node && node.superClass
|
|
396
|
+
if ("superClass" in node && node.superClass) {
|
|
404
397
|
const re = /^PureComponent$/u;
|
|
405
398
|
switch (true) {
|
|
406
399
|
case node.superClass.type === AST_NODE_TYPES.Identifier:
|
|
@@ -423,14 +416,13 @@ function isFunctionOfRenderMethod(node) {
|
|
|
423
416
|
return isClassComponent(node.parent.parent.parent);
|
|
424
417
|
}
|
|
425
418
|
function isInsideRenderMethod(node) {
|
|
426
|
-
return
|
|
419
|
+
return !!AST8.findParentNode(node, (node2) => isRenderMethodLike(node2) && isClassComponent(node2.parent.parent));
|
|
427
420
|
}
|
|
421
|
+
|
|
422
|
+
// src/component/misc.ts
|
|
428
423
|
function hasNoneOrValidComponentName(node, context) {
|
|
429
|
-
const
|
|
430
|
-
if (
|
|
431
|
-
return true;
|
|
432
|
-
}
|
|
433
|
-
const id2 = mbIdentifier.value;
|
|
424
|
+
const id2 = getFunctionComponentIdentifier(node, context);
|
|
425
|
+
if (!id2) return true;
|
|
434
426
|
const name = Array.isArray(id2) ? id2.at(-1)?.name : id2.name;
|
|
435
427
|
return name != null && isComponentName(name);
|
|
436
428
|
}
|
|
@@ -452,26 +444,24 @@ function hasValidHierarchy(node, context, hint) {
|
|
|
452
444
|
if (hint & ERComponentHint.SkipClassProperty && AST8.isFunctionOfClassProperty(node.parent)) {
|
|
453
445
|
return false;
|
|
454
446
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
])
|
|
465
|
-
),
|
|
466
|
-
AST8.is(AST_NODE_TYPES.JSXExpressionContainer)
|
|
447
|
+
const boundaryNode = AST8.findParentNode(
|
|
448
|
+
node,
|
|
449
|
+
AST8.isOneOf([
|
|
450
|
+
AST_NODE_TYPES.JSXExpressionContainer,
|
|
451
|
+
AST_NODE_TYPES.ArrowFunctionExpression,
|
|
452
|
+
AST_NODE_TYPES.FunctionExpression,
|
|
453
|
+
AST_NODE_TYPES.Property,
|
|
454
|
+
AST_NODE_TYPES.ClassBody
|
|
455
|
+
])
|
|
467
456
|
);
|
|
457
|
+
return !boundaryNode || boundaryNode.type !== AST_NODE_TYPES.JSXExpressionContainer;
|
|
468
458
|
}
|
|
469
459
|
function getComponentFlag(initPath) {
|
|
470
460
|
let flag = ERFunctionComponentFlag.None;
|
|
471
|
-
if (AST8.hasCallInFunctionInitPath("memo")(initPath)) {
|
|
461
|
+
if (initPath && AST8.hasCallInFunctionInitPath("memo")(initPath)) {
|
|
472
462
|
flag |= ERFunctionComponentFlag.Memo;
|
|
473
463
|
}
|
|
474
|
-
if (AST8.hasCallInFunctionInitPath("forwardRef")(initPath)) {
|
|
464
|
+
if (initPath && AST8.hasCallInFunctionInitPath("forwardRef")(initPath)) {
|
|
475
465
|
flag |= ERFunctionComponentFlag.ForwardRef;
|
|
476
466
|
}
|
|
477
467
|
return flag;
|
|
@@ -480,18 +470,19 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
480
470
|
const jsxCtx = { getScope: (node) => context.sourceCode.getScope(node) };
|
|
481
471
|
const components = /* @__PURE__ */ new Map();
|
|
482
472
|
const functionEntries = [];
|
|
483
|
-
const
|
|
473
|
+
const getCurrentEntry = () => functionEntries.at(-1);
|
|
484
474
|
const onFunctionEnter = (node) => {
|
|
485
475
|
const key = getId();
|
|
486
476
|
functionEntries.push({ key, node, hookCalls: [], isComponent: false });
|
|
487
477
|
};
|
|
488
478
|
const onFunctionExit = () => {
|
|
489
479
|
const entry = functionEntries.at(-1);
|
|
490
|
-
if (!entry
|
|
480
|
+
if (!entry) return;
|
|
481
|
+
if (!entry.isComponent) {
|
|
491
482
|
return functionEntries.pop();
|
|
492
483
|
}
|
|
493
484
|
const shouldDrop = AST8.getNestedReturnStatements(entry.node.body).slice().reverse().some((r) => {
|
|
494
|
-
return context.sourceCode.getScope(r).block === entry.node && r.argument
|
|
485
|
+
return context.sourceCode.getScope(r).block === entry.node && !!r.argument && !JSX4.isJSXValue(r.argument, jsxCtx, hint);
|
|
495
486
|
});
|
|
496
487
|
if (shouldDrop) {
|
|
497
488
|
components.delete(entry.key);
|
|
@@ -499,23 +490,23 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
499
490
|
return functionEntries.pop();
|
|
500
491
|
};
|
|
501
492
|
const ctx = {
|
|
502
|
-
|
|
493
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
494
|
+
getAllComponents(node) {
|
|
503
495
|
return components;
|
|
504
496
|
},
|
|
505
|
-
|
|
506
|
-
getCurrentFunctionStack() {
|
|
497
|
+
getCurrentEntries() {
|
|
507
498
|
return [...functionEntries];
|
|
508
|
-
}
|
|
499
|
+
},
|
|
500
|
+
getCurrentEntry
|
|
509
501
|
};
|
|
510
502
|
const listeners = {
|
|
511
503
|
":function[type]": onFunctionEnter,
|
|
512
504
|
":function[type]:exit": onFunctionExit,
|
|
513
505
|
"ArrowFunctionExpression[type][body.type!='BlockStatement']"() {
|
|
514
|
-
const
|
|
515
|
-
if (
|
|
506
|
+
const entry = getCurrentEntry();
|
|
507
|
+
if (!entry) {
|
|
516
508
|
return;
|
|
517
509
|
}
|
|
518
|
-
const entry = mbEntry.value;
|
|
519
510
|
const { body } = entry.node;
|
|
520
511
|
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX4.isJSXValue(body, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
521
512
|
if (!isComponent) {
|
|
@@ -523,7 +514,7 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
523
514
|
}
|
|
524
515
|
const initPath = AST8.getFunctionInitPath(entry.node);
|
|
525
516
|
const id2 = getFunctionComponentIdentifier(entry.node, context);
|
|
526
|
-
const name =
|
|
517
|
+
const name = id2 && getComponentNameFromIdentifier(id2);
|
|
527
518
|
const key = getId();
|
|
528
519
|
components.set(key, {
|
|
529
520
|
_: key,
|
|
@@ -531,7 +522,7 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
531
522
|
kind: "function",
|
|
532
523
|
name,
|
|
533
524
|
node: entry.node,
|
|
534
|
-
displayName:
|
|
525
|
+
displayName: _,
|
|
535
526
|
flag: getComponentFlag(initPath),
|
|
536
527
|
hint,
|
|
537
528
|
hookCalls: entry.hookCalls,
|
|
@@ -540,38 +531,32 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
540
531
|
},
|
|
541
532
|
"AssignmentExpression[type][operator='='][left.type='MemberExpression'][left.property.name='displayName']"(node) {
|
|
542
533
|
const { left, right } = node;
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
}
|
|
547
|
-
const componentName = mbComponentName.value;
|
|
548
|
-
const component = Array.from(components.values()).findLast(({ name }) => O.exists(name, (n) => n === componentName));
|
|
549
|
-
if (component == null) {
|
|
534
|
+
const componentName = left.object.type === AST_NODE_TYPES.Identifier ? left.object.name : _;
|
|
535
|
+
const component = [...components.values()].findLast(({ name }) => name != null && name === componentName);
|
|
536
|
+
if (!component) {
|
|
550
537
|
return;
|
|
551
538
|
}
|
|
552
539
|
components.set(component._, {
|
|
553
540
|
...component,
|
|
554
|
-
displayName:
|
|
541
|
+
displayName: right
|
|
555
542
|
});
|
|
556
543
|
},
|
|
557
544
|
"CallExpression[type]:exit"(node) {
|
|
558
545
|
if (!isReactHookCall(node)) {
|
|
559
546
|
return;
|
|
560
547
|
}
|
|
561
|
-
const
|
|
562
|
-
if (
|
|
548
|
+
const entry = getCurrentEntry();
|
|
549
|
+
if (!entry) {
|
|
563
550
|
return;
|
|
564
551
|
}
|
|
565
|
-
const entry = mbEntry.value;
|
|
566
552
|
functionEntries.pop();
|
|
567
553
|
functionEntries.push({ ...entry, hookCalls: [...entry.hookCalls, node] });
|
|
568
554
|
},
|
|
569
555
|
"ReturnStatement[type]"(node) {
|
|
570
|
-
const
|
|
571
|
-
if (
|
|
556
|
+
const entry = getCurrentEntry();
|
|
557
|
+
if (!entry) {
|
|
572
558
|
return;
|
|
573
559
|
}
|
|
574
|
-
const entry = mbEntry.value;
|
|
575
560
|
const isComponent = hasNoneOrValidComponentName(entry.node, context) && JSX4.isJSXValue(node.argument, jsxCtx, hint) && hasValidHierarchy(entry.node, context, hint);
|
|
576
561
|
if (!isComponent) {
|
|
577
562
|
return;
|
|
@@ -580,14 +565,14 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
580
565
|
functionEntries.push({ ...entry, isComponent });
|
|
581
566
|
const initPath = AST8.getFunctionInitPath(entry.node);
|
|
582
567
|
const id2 = getFunctionComponentIdentifier(entry.node, context);
|
|
583
|
-
const name =
|
|
568
|
+
const name = id2 && getComponentNameFromIdentifier(id2);
|
|
584
569
|
components.set(entry.key, {
|
|
585
570
|
_: entry.key,
|
|
586
571
|
id: id2,
|
|
587
572
|
kind: "function",
|
|
588
573
|
name,
|
|
589
574
|
node: entry.node,
|
|
590
|
-
displayName:
|
|
575
|
+
displayName: _,
|
|
591
576
|
flag: getComponentFlag(initPath),
|
|
592
577
|
hint,
|
|
593
578
|
hookCalls: entry.hookCalls,
|
|
@@ -600,7 +585,8 @@ function useComponentCollector(context, hint = DEFAULT_COMPONENT_HINT) {
|
|
|
600
585
|
function useComponentCollectorLegacy() {
|
|
601
586
|
const components = /* @__PURE__ */ new Map();
|
|
602
587
|
const ctx = {
|
|
603
|
-
|
|
588
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
589
|
+
getAllComponents(node) {
|
|
604
590
|
return components;
|
|
605
591
|
}
|
|
606
592
|
};
|
|
@@ -617,10 +603,10 @@ function useComponentCollectorLegacy() {
|
|
|
617
603
|
_: key,
|
|
618
604
|
id: id2,
|
|
619
605
|
kind: "class",
|
|
620
|
-
name:
|
|
606
|
+
name: id2?.name,
|
|
621
607
|
node,
|
|
622
608
|
// TODO: Get displayName of class component
|
|
623
|
-
displayName:
|
|
609
|
+
displayName: _,
|
|
624
610
|
flag,
|
|
625
611
|
hint: 0n,
|
|
626
612
|
// TODO: Get methods of class component
|
|
@@ -635,18 +621,14 @@ function useComponentCollectorLegacy() {
|
|
|
635
621
|
return { ctx, listeners };
|
|
636
622
|
}
|
|
637
623
|
function isSetupFunction(node) {
|
|
624
|
+
if (node === _) return _;
|
|
638
625
|
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);
|
|
639
626
|
}
|
|
640
627
|
function isCleanupFunction(node) {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
O.bind("nearFunctionOfReturn", ({ nearReturn }) => AST8.findParentNodeGuard(nearReturn, AST8.isFunction)),
|
|
646
|
-
O.exists(
|
|
647
|
-
({ nearFunction, nearFunctionOfReturn }) => nearFunction === nearFunctionOfReturn && isSetupFunction(nearFunction)
|
|
648
|
-
)
|
|
649
|
-
);
|
|
628
|
+
const nearReturn = AST8.findParentNodeGuard(node, AST8.is(AST_NODE_TYPES.ReturnStatement));
|
|
629
|
+
const nearFunction = AST8.findParentNodeGuard(node, AST8.isFunction);
|
|
630
|
+
const nearFunctionOfReturn = AST8.findParentNodeGuard(nearReturn, AST8.isFunction);
|
|
631
|
+
return nearFunction === nearFunctionOfReturn && isSetupFunction(nearFunction);
|
|
650
632
|
}
|
|
651
633
|
function isComponentDidMount(node) {
|
|
652
634
|
return AST8.isOneOf([AST_NODE_TYPES.MethodDefinition, AST_NODE_TYPES.PropertyDefinition])(node) && node.key.type === AST_NODE_TYPES.Identifier && node.key.name === "componentDidMount";
|
|
@@ -664,30 +646,26 @@ var ERPhaseRelevance = birecord({
|
|
|
664
646
|
mount: "unmount",
|
|
665
647
|
setup: "cleanup"
|
|
666
648
|
});
|
|
667
|
-
var isInversePhase =
|
|
649
|
+
var isInversePhase = dual(2, (a, b) => ERPhaseRelevance.get(a) === b);
|
|
668
650
|
function isDirectValueOfRenderPropertyLoose(node) {
|
|
669
651
|
const matching = (node2) => {
|
|
670
652
|
return node2.type === AST_NODE_TYPES.Property && node2.key.type === AST_NODE_TYPES.Identifier && node2.key.name.startsWith("render");
|
|
671
653
|
};
|
|
672
|
-
return matching(node) || node.parent
|
|
654
|
+
return matching(node) || !!node.parent && matching(node.parent);
|
|
673
655
|
}
|
|
674
656
|
function isDeclaredInRenderPropLoose(node) {
|
|
675
657
|
if (isDirectValueOfRenderPropertyLoose(node)) {
|
|
676
658
|
return true;
|
|
677
659
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
O.exists(
|
|
684
|
-
(n) => n.type === AST_NODE_TYPES.JSXIdentifier && n.name.startsWith("render")
|
|
685
|
-
)
|
|
686
|
-
);
|
|
660
|
+
const parent = AST8.findParentNodeGuard(node, AST8.is(AST_NODE_TYPES.JSXExpressionContainer))?.parent;
|
|
661
|
+
if (parent?.type !== AST_NODE_TYPES.JSXAttribute) {
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
return parent.name.type === AST_NODE_TYPES.JSXIdentifier && parent.name.name.startsWith("render");
|
|
687
665
|
}
|
|
688
666
|
function isRenderFunctionLoose(node, context) {
|
|
689
667
|
const { body, parent } = node;
|
|
690
|
-
if (
|
|
668
|
+
if (AST8.getFunctionIdentifier(node)?.name.startsWith("render")) {
|
|
691
669
|
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");
|
|
692
670
|
}
|
|
693
671
|
return JSX4.isJSXValue(
|
|
@@ -709,4 +687,4 @@ function isThisSetState(node) {
|
|
|
709
687
|
return callee.type === AST_NODE_TYPES.MemberExpression && AST8.isThisExpression(callee.object) && callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === "setState";
|
|
710
688
|
}
|
|
711
689
|
|
|
712
|
-
export { DEFAULT_COMPONENT_HINT, ERClassComponentFlag, ERComponentHint, ERFunctionComponentFlag, ERPhaseRelevance, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier,
|
|
690
|
+
export { DEFAULT_COMPONENT_HINT, ERClassComponentFlag, ERComponentHint, ERFunctionComponentFlag, ERPhaseRelevance, RE_COMPONENT_NAME, RE_HOOK_NAME, getComponentNameFromIdentifier, getElementNameAndRepresentName, getFunctionComponentIdentifier, getId, hasNoneOrValidComponentName, isCallFromReact, isCallFromReactMember, isChildrenCount, isChildrenCountCall, isChildrenForEach, isChildrenForEachCall, isChildrenMap, isChildrenMapCall, isChildrenOfCreateElement, isChildrenOnly, isChildrenOnlyCall, isChildrenToArray, isChildrenToArrayCall, isClassComponent, isCleanupFunction, isCloneElement, isCloneElementCall, isComponentDidMount, isComponentDidMountFunction, isComponentName, isComponentWillUnmount, isComponentWillUnmountFunction, isCreateContext, isCreateContextCall, isCreateElement, isCreateElementCall, isCreateRef, isCreateRefCall, isDeclaredInRenderPropLoose, isDirectValueOfRenderPropertyLoose, isForwardRef, isForwardRefCall, isFromReact, isFromReactMember, isFunctionOfRenderMethod, isInitializedFromReact, isInsideCreateElementProps, isInsideReactHook, isInsideRenderMethod, isInversePhase, isMemo, isMemoCall, isPureComponent, isReactAPICallWithName, isReactAPIWithName, isReactHook, isReactHookCall, isReactHookCallWithName, isReactHookCallWithNameAlias, isReactHookCallWithNameLoose, isReactHookName, isRenderFunctionLoose, isRenderMethodLike, isRenderPropLoose, isSetupFunction, 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,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0-beta.0",
|
|
4
4
|
"description": "ESLint React's ESLint utility module for static analysis of React core APIs and Patterns.",
|
|
5
|
-
"homepage": "https://github.com/
|
|
5
|
+
"homepage": "https://github.com/Rel1cx/eslint-react",
|
|
6
6
|
"bugs": {
|
|
7
|
-
"url": "https://github.com/
|
|
7
|
+
"url": "https://github.com/Rel1cx/eslint-react/issues"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/
|
|
11
|
+
"url": "git+https://github.com/Rel1cx/eslint-react.git",
|
|
12
12
|
"directory": "packages/core"
|
|
13
13
|
},
|
|
14
14
|
"license": "MIT",
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
"@typescript-eslint/types": "^8.19.1",
|
|
39
39
|
"@typescript-eslint/utils": "^8.19.1",
|
|
40
40
|
"ts-pattern": "^5.6.0",
|
|
41
|
-
"@eslint-react/
|
|
42
|
-
"@eslint-react/
|
|
43
|
-
"@eslint-react/jsx": "1.
|
|
44
|
-
"@eslint-react/
|
|
45
|
-
"@eslint-react/
|
|
46
|
-
"@eslint-react/var": "1.
|
|
41
|
+
"@eslint-react/ast": "1.24.0-beta.0",
|
|
42
|
+
"@eslint-react/eff": "1.24.0-beta.0",
|
|
43
|
+
"@eslint-react/jsx": "1.24.0-beta.0",
|
|
44
|
+
"@eslint-react/shared": "1.24.0-beta.0",
|
|
45
|
+
"@eslint-react/types": "1.24.0-beta.0",
|
|
46
|
+
"@eslint-react/var": "1.24.0-beta.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"tsup": "^8.3.5",
|