eslint-plugin-react-x 1.22.2-beta.5 → 1.22.2-beta.8
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.js +73 -127
- package/dist/index.mjs +74 -128
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var eff = require('@eslint-react/eff');
|
|
4
|
-
var
|
|
4
|
+
var JSX7 = require('@eslint-react/jsx');
|
|
5
5
|
var shared = require('@eslint-react/shared');
|
|
6
6
|
var AST11 = require('@eslint-react/ast');
|
|
7
7
|
var core = require('@eslint-react/core');
|
|
@@ -35,14 +35,14 @@ function _interopNamespace(e) {
|
|
|
35
35
|
return Object.freeze(n);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
var
|
|
38
|
+
var JSX7__namespace = /*#__PURE__*/_interopNamespace(JSX7);
|
|
39
39
|
var AST11__namespace = /*#__PURE__*/_interopNamespace(AST11);
|
|
40
40
|
var VAR__namespace = /*#__PURE__*/_interopNamespace(VAR);
|
|
41
41
|
var ts__default = /*#__PURE__*/_interopDefault(ts);
|
|
42
42
|
|
|
43
43
|
// package.json
|
|
44
44
|
var name = "eslint-plugin-react-x";
|
|
45
|
-
var version = "1.22.2-beta.
|
|
45
|
+
var version = "1.22.2-beta.8";
|
|
46
46
|
var createRule = shared.createRuleForPlugin("x");
|
|
47
47
|
|
|
48
48
|
// src/rules/avoid-shorthand-boolean.ts
|
|
@@ -70,7 +70,7 @@ var avoid_shorthand_boolean_default = createRule({
|
|
|
70
70
|
messageId: "avoidShorthandBoolean",
|
|
71
71
|
node,
|
|
72
72
|
data: {
|
|
73
|
-
propName:
|
|
73
|
+
propName: JSX7__namespace.getPropName(node)
|
|
74
74
|
},
|
|
75
75
|
fix: (fixer) => fixer.insertTextAfter(node.name, `={true}`)
|
|
76
76
|
});
|
|
@@ -151,7 +151,7 @@ var RULE_FEATURES4 = [
|
|
|
151
151
|
"CHK"
|
|
152
152
|
];
|
|
153
153
|
function getName(node) {
|
|
154
|
-
if (node
|
|
154
|
+
if (AST11__namespace.isTypeExpression(node)) {
|
|
155
155
|
return getName(node.expression);
|
|
156
156
|
}
|
|
157
157
|
if (node.type === types.AST_NODE_TYPES.Identifier || node.type === types.AST_NODE_TYPES.PrivateIdentifier) {
|
|
@@ -537,7 +537,7 @@ var no_children_prop_default = createRule({
|
|
|
537
537
|
return {
|
|
538
538
|
JSXElement(node) {
|
|
539
539
|
const initialScope = context.sourceCode.getScope(node);
|
|
540
|
-
const prop =
|
|
540
|
+
const prop = JSX7__namespace.getProp(node.openingElement.attributes, "children", initialScope);
|
|
541
541
|
const reportDescriptor = eff.O.map(prop, (prop2) => ({ messageId: "noChildrenProp", node: prop2 }));
|
|
542
542
|
eff.O.map(reportDescriptor, context.report);
|
|
543
543
|
}
|
|
@@ -912,7 +912,7 @@ var no_context_provider_default = createRule({
|
|
|
912
912
|
if (compareVersions.compare(version2, "19.0.0", "<")) return {};
|
|
913
913
|
return {
|
|
914
914
|
JSXElement(node) {
|
|
915
|
-
const elementName =
|
|
915
|
+
const elementName = JSX7__namespace.getElementName(node.openingElement);
|
|
916
916
|
if (!elementName.endsWith(".Provider")) return;
|
|
917
917
|
context.report({
|
|
918
918
|
messageId: "noContextProvider",
|
|
@@ -1009,7 +1009,7 @@ var RULE_FEATURES22 = [
|
|
|
1009
1009
|
"CHK"
|
|
1010
1010
|
];
|
|
1011
1011
|
function getName2(node) {
|
|
1012
|
-
if (node
|
|
1012
|
+
if (AST11__namespace.isTypeExpression(node)) {
|
|
1013
1013
|
return getName2(node.expression);
|
|
1014
1014
|
}
|
|
1015
1015
|
if (node.type === types.AST_NODE_TYPES.Identifier || node.type === types.AST_NODE_TYPES.PrivateIdentifier) {
|
|
@@ -1123,116 +1123,61 @@ var no_duplicate_key_default = createRule({
|
|
|
1123
1123
|
},
|
|
1124
1124
|
name: RULE_NAME24,
|
|
1125
1125
|
create(context) {
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1126
|
+
if (!context.sourceCode.getText().includes("key=")) return {};
|
|
1127
|
+
const keyedEntries = /* @__PURE__ */ new Map();
|
|
1128
|
+
function isKeyValueEqual(a, b) {
|
|
1129
|
+
const aValue = a.value;
|
|
1130
|
+
const bValue = b.value;
|
|
1131
|
+
if (aValue === null || bValue === null) return false;
|
|
1132
|
+
return AST11__namespace.isNodeEqual(aValue, bValue);
|
|
1129
1133
|
}
|
|
1130
|
-
function checkIteratorElement(node) {
|
|
1131
|
-
if (node.type !== types.AST_NODE_TYPES.JSXElement) return eff.O.none();
|
|
1132
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
1133
|
-
return eff.F.pipe(
|
|
1134
|
-
JSX8__namespace.findPropInAttributes(node.openingElement.attributes, initialScope)("key"),
|
|
1135
|
-
eff.O.flatMap((k) => "value" in k ? eff.O.fromNullable(k.value) : eff.O.none()),
|
|
1136
|
-
eff.O.flatMap((v) => {
|
|
1137
|
-
return isKeyEqual(v, v) ? eff.O.some({
|
|
1138
|
-
messageId: "noDuplicateKey",
|
|
1139
|
-
node: v,
|
|
1140
|
-
data: {
|
|
1141
|
-
value: context.sourceCode.getText(v)
|
|
1142
|
-
}
|
|
1143
|
-
}) : eff.O.none();
|
|
1144
|
-
})
|
|
1145
|
-
);
|
|
1146
|
-
}
|
|
1147
|
-
function checkExpression(node) {
|
|
1148
|
-
switch (node.type) {
|
|
1149
|
-
case types.AST_NODE_TYPES.ConditionalExpression:
|
|
1150
|
-
if (!("consequent" in node)) return eff.O.none();
|
|
1151
|
-
return eff.F.pipe(
|
|
1152
|
-
checkIteratorElement(node.consequent),
|
|
1153
|
-
eff.O.orElse(() => checkIteratorElement(node.alternate))
|
|
1154
|
-
);
|
|
1155
|
-
case types.AST_NODE_TYPES.JSXElement:
|
|
1156
|
-
case types.AST_NODE_TYPES.JSXFragment:
|
|
1157
|
-
return checkIteratorElement(node);
|
|
1158
|
-
case types.AST_NODE_TYPES.LogicalExpression:
|
|
1159
|
-
if (!("left" in node)) return eff.O.none();
|
|
1160
|
-
return eff.F.pipe(
|
|
1161
|
-
checkIteratorElement(node.left),
|
|
1162
|
-
eff.O.orElse(() => checkIteratorElement(node.right))
|
|
1163
|
-
);
|
|
1164
|
-
default:
|
|
1165
|
-
return eff.O.none();
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
function checkBlockStatement(node) {
|
|
1169
|
-
return AST11__namespace.getNestedReturnStatements(node).reduce((acc, statement) => {
|
|
1170
|
-
if (!statement.argument) return acc;
|
|
1171
|
-
const maybeDescriptor = checkIteratorElement(statement.argument);
|
|
1172
|
-
if (eff.O.isNone(maybeDescriptor)) return acc;
|
|
1173
|
-
const descriptor = maybeDescriptor.value;
|
|
1174
|
-
return [...acc, descriptor];
|
|
1175
|
-
}, []);
|
|
1176
|
-
}
|
|
1177
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
1178
1134
|
return {
|
|
1179
|
-
"
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1135
|
+
"JSXAttribute[name.name='key']"(node) {
|
|
1136
|
+
const jsxElement = node.parent.parent;
|
|
1137
|
+
switch (jsxElement.parent.type) {
|
|
1138
|
+
case types.AST_NODE_TYPES.ArrayExpression:
|
|
1139
|
+
case types.AST_NODE_TYPES.JSXElement:
|
|
1140
|
+
case types.AST_NODE_TYPES.JSXFragment: {
|
|
1141
|
+
const root = jsxElement.parent;
|
|
1142
|
+
const prevKeys = keyedEntries.get(root)?.keys ?? [];
|
|
1143
|
+
keyedEntries.set(root, {
|
|
1144
|
+
hasDuplicate: prevKeys.some((prevKey) => isKeyValueEqual(prevKey, node)),
|
|
1145
|
+
keys: [...prevKeys, node],
|
|
1146
|
+
root: jsxElement.parent
|
|
1187
1147
|
});
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
data: {
|
|
1205
|
-
value: context.sourceCode.getText(value)
|
|
1148
|
+
break;
|
|
1149
|
+
}
|
|
1150
|
+
default: {
|
|
1151
|
+
const entry = eff.F.pipe(
|
|
1152
|
+
eff.O.Do,
|
|
1153
|
+
eff.O.bind("call", () => AST11__namespace.traverseUpGuard(jsxElement, AST11__namespace.isMapCallLoose)),
|
|
1154
|
+
eff.O.bind("iter", ({ call }) => AST11__namespace.traverseUpStop(jsxElement, call, AST11__namespace.isFunction)),
|
|
1155
|
+
eff.O.bind("arg0", ({ call }) => eff.O.fromNullable(call.arguments[0]))
|
|
1156
|
+
);
|
|
1157
|
+
for (const { arg0, call, iter } of eff.O.toArray(entry)) {
|
|
1158
|
+
if (AST11__namespace.unwrapTypeExpression(arg0) !== iter) continue;
|
|
1159
|
+
keyedEntries.set(call, {
|
|
1160
|
+
hasDuplicate: node.value?.type === types.AST_NODE_TYPES.Literal,
|
|
1161
|
+
keys: [node],
|
|
1162
|
+
root: call
|
|
1163
|
+
});
|
|
1206
1164
|
}
|
|
1207
|
-
}
|
|
1165
|
+
}
|
|
1208
1166
|
}
|
|
1209
1167
|
},
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
}, node);
|
|
1222
|
-
if (!isMapCall && !isArrayFromCall) return;
|
|
1223
|
-
if (eff.MutRef.get(isWithinChildrenToArrayRef)) return;
|
|
1224
|
-
const fn = node.arguments[isMapCall ? 0 : 1];
|
|
1225
|
-
if (!AST11__namespace.isOneOf([types.AST_NODE_TYPES.ArrowFunctionExpression, types.AST_NODE_TYPES.FunctionExpression])(fn)) return;
|
|
1226
|
-
if (fn.body.type === types.AST_NODE_TYPES.BlockStatement) {
|
|
1227
|
-
for (const descriptor of checkBlockStatement(fn.body)) {
|
|
1228
|
-
context.report(descriptor);
|
|
1168
|
+
"Program:exit"() {
|
|
1169
|
+
for (const { hasDuplicate, keys } of keyedEntries.values()) {
|
|
1170
|
+
if (!hasDuplicate) continue;
|
|
1171
|
+
for (const key of keys) {
|
|
1172
|
+
context.report({
|
|
1173
|
+
messageId: "noDuplicateKey",
|
|
1174
|
+
node: key,
|
|
1175
|
+
data: {
|
|
1176
|
+
value: context.sourceCode.getText(key)
|
|
1177
|
+
}
|
|
1178
|
+
});
|
|
1229
1179
|
}
|
|
1230
|
-
return;
|
|
1231
1180
|
}
|
|
1232
|
-
eff.O.map(checkExpression(fn.body), context.report);
|
|
1233
|
-
},
|
|
1234
|
-
"CallExpression:exit"(node) {
|
|
1235
|
-
if (core.isChildrenToArrayCall(node, context)) eff.MutRef.set(isWithinChildrenToArrayRef, false);
|
|
1236
1181
|
}
|
|
1237
1182
|
};
|
|
1238
1183
|
},
|
|
@@ -1355,7 +1300,7 @@ var no_implicit_key_default = createRule({
|
|
|
1355
1300
|
create(context) {
|
|
1356
1301
|
function getReportDescriptor(node) {
|
|
1357
1302
|
const initialScope = context.sourceCode.getScope(node);
|
|
1358
|
-
const keyPropFound =
|
|
1303
|
+
const keyPropFound = JSX7__namespace.findPropInAttributes(node.attributes, initialScope)("key");
|
|
1359
1304
|
const keyPropOnElement = node.attributes.some(
|
|
1360
1305
|
(n) => AST11__namespace.is(types.AST_NODE_TYPES.JSXAttribute)(n) && n.name.name === "key"
|
|
1361
1306
|
);
|
|
@@ -1595,12 +1540,12 @@ var no_missing_key_default = createRule({
|
|
|
1595
1540
|
},
|
|
1596
1541
|
name: RULE_NAME29,
|
|
1597
1542
|
create(context) {
|
|
1598
|
-
const
|
|
1543
|
+
const state = { isWithinChildrenToArray: false };
|
|
1599
1544
|
function checkIteratorElement(node) {
|
|
1600
1545
|
switch (node.type) {
|
|
1601
1546
|
case types.AST_NODE_TYPES.JSXElement: {
|
|
1602
1547
|
const initialScope = context.sourceCode.getScope(node);
|
|
1603
|
-
if (!
|
|
1548
|
+
if (!JSX7__namespace.hasProp(node.openingElement.attributes, "key", initialScope)) {
|
|
1604
1549
|
return eff.O.some({
|
|
1605
1550
|
messageId: "noMissingKey",
|
|
1606
1551
|
node
|
|
@@ -1644,12 +1589,12 @@ var no_missing_key_default = createRule({
|
|
|
1644
1589
|
}
|
|
1645
1590
|
return {
|
|
1646
1591
|
ArrayExpression(node) {
|
|
1647
|
-
if (
|
|
1592
|
+
if (state.isWithinChildrenToArray) return;
|
|
1648
1593
|
const elements = node.elements.filter(AST11__namespace.is(types.AST_NODE_TYPES.JSXElement));
|
|
1649
1594
|
if (elements.length === 0) return;
|
|
1650
1595
|
const initialScope = context.sourceCode.getScope(node);
|
|
1651
1596
|
for (const element of elements) {
|
|
1652
|
-
if (!
|
|
1597
|
+
if (!JSX7__namespace.hasProp(element.openingElement.attributes, "key", initialScope)) {
|
|
1653
1598
|
context.report({
|
|
1654
1599
|
messageId: "noMissingKey",
|
|
1655
1600
|
node: element
|
|
@@ -1658,7 +1603,8 @@ var no_missing_key_default = createRule({
|
|
|
1658
1603
|
}
|
|
1659
1604
|
},
|
|
1660
1605
|
CallExpression(node) {
|
|
1661
|
-
|
|
1606
|
+
state.isWithinChildrenToArray ||= core.isChildrenToArrayCall(node, context);
|
|
1607
|
+
if (state.isWithinChildrenToArray) return;
|
|
1662
1608
|
const isMapCall = AST11__namespace.isMapCallLoose(node);
|
|
1663
1609
|
const isArrayFromCall = tsPattern.isMatching({
|
|
1664
1610
|
type: types.AST_NODE_TYPES.CallExpression,
|
|
@@ -1670,7 +1616,6 @@ var no_missing_key_default = createRule({
|
|
|
1670
1616
|
}
|
|
1671
1617
|
}, node);
|
|
1672
1618
|
if (!isMapCall && !isArrayFromCall) return;
|
|
1673
|
-
if (eff.MutRef.get(isWithinChildrenToArrayRef)) return;
|
|
1674
1619
|
const fn = node.arguments[isMapCall ? 0 : 1];
|
|
1675
1620
|
if (!AST11__namespace.isOneOf([types.AST_NODE_TYPES.ArrowFunctionExpression, types.AST_NODE_TYPES.FunctionExpression])(fn)) return;
|
|
1676
1621
|
if (fn.body.type === types.AST_NODE_TYPES.BlockStatement) {
|
|
@@ -1682,10 +1627,11 @@ var no_missing_key_default = createRule({
|
|
|
1682
1627
|
eff.O.map(checkExpression(fn.body), context.report);
|
|
1683
1628
|
},
|
|
1684
1629
|
"CallExpression:exit"(node) {
|
|
1685
|
-
if (core.isChildrenToArrayCall(node, context))
|
|
1630
|
+
if (!core.isChildrenToArrayCall(node, context)) return;
|
|
1631
|
+
state.isWithinChildrenToArray = false;
|
|
1686
1632
|
},
|
|
1687
1633
|
JSXFragment(node) {
|
|
1688
|
-
if (
|
|
1634
|
+
if (state.isWithinChildrenToArray) return;
|
|
1689
1635
|
if (node.parent.type === types.AST_NODE_TYPES.ArrayExpression) {
|
|
1690
1636
|
context.report({
|
|
1691
1637
|
messageId: "noMissingKeyWithFragment",
|
|
@@ -1736,7 +1682,7 @@ var no_nested_components_default = createRule({
|
|
|
1736
1682
|
if (eff.O.isNone(componentName)) continue;
|
|
1737
1683
|
const name2 = componentName.value;
|
|
1738
1684
|
const isInsideProperty = component.parent.type === types.AST_NODE_TYPES.Property;
|
|
1739
|
-
const isInsideJSXPropValue = component.parent.type === types.AST_NODE_TYPES.JSXAttribute || eff.O.isSome(
|
|
1685
|
+
const isInsideJSXPropValue = component.parent.type === types.AST_NODE_TYPES.JSXAttribute || eff.O.isSome(JSX7__namespace.traverseUpProp(node, (n) => n.value?.type === types.AST_NODE_TYPES.JSXExpressionContainer));
|
|
1740
1686
|
if (isInsideJSXPropValue) {
|
|
1741
1687
|
if (!core.isDeclaredInRenderPropLoose(component)) {
|
|
1742
1688
|
context.report({
|
|
@@ -2360,7 +2306,7 @@ var LIFECYCLE_METHODS = /* @__PURE__ */ new Set([
|
|
|
2360
2306
|
"UNSAFE_componentWillUpdate"
|
|
2361
2307
|
]);
|
|
2362
2308
|
function getName3(node) {
|
|
2363
|
-
if (node
|
|
2309
|
+
if (AST11__namespace.isTypeExpression(node)) {
|
|
2364
2310
|
return getName3(node.expression);
|
|
2365
2311
|
}
|
|
2366
2312
|
if (node.type === types.AST_NODE_TYPES.Identifier || node.type === types.AST_NODE_TYPES.PrivateIdentifier) {
|
|
@@ -2474,7 +2420,7 @@ var RULE_FEATURES43 = [
|
|
|
2474
2420
|
"CHK"
|
|
2475
2421
|
];
|
|
2476
2422
|
function getName4(node) {
|
|
2477
|
-
if (node
|
|
2423
|
+
if (AST11__namespace.isTypeExpression(node)) {
|
|
2478
2424
|
return getName4(node.expression);
|
|
2479
2425
|
}
|
|
2480
2426
|
if (node.type === types.AST_NODE_TYPES.Identifier || node.type === types.AST_NODE_TYPES.PrivateIdentifier) {
|
|
@@ -2617,18 +2563,18 @@ var no_unused_state_default = createRule({
|
|
|
2617
2563
|
var RULE_NAME44 = "no-useless-fragment";
|
|
2618
2564
|
function check(node, context, allowExpressions) {
|
|
2619
2565
|
const initialScope = context.sourceCode.getScope(node);
|
|
2620
|
-
if (
|
|
2621
|
-
if (
|
|
2566
|
+
if (JSX7__namespace.isKeyedElement(node, initialScope)) return;
|
|
2567
|
+
if (JSX7__namespace.isBuiltInElement(node.parent)) context.report({ messageId: "noUselessFragmentInBuiltIn", node });
|
|
2622
2568
|
if (node.children.length === 0) return context.report({ messageId: "noUselessFragment", node });
|
|
2623
2569
|
const isChildren = AST11__namespace.isOneOf([types.AST_NODE_TYPES.JSXElement, types.AST_NODE_TYPES.JSXFragment])(node.parent);
|
|
2624
2570
|
const [firstChildren] = node.children;
|
|
2625
|
-
if (allowExpressions && node.children.length === 1 &&
|
|
2571
|
+
if (allowExpressions && node.children.length === 1 && JSX7__namespace.isLiteral(firstChildren) && !isChildren) return;
|
|
2626
2572
|
if (!allowExpressions && isChildren) {
|
|
2627
2573
|
return context.report({ messageId: "noUselessFragment", node });
|
|
2628
2574
|
} else if (!allowExpressions && !isChildren && node.children.length === 1) {
|
|
2629
2575
|
return context.report({ messageId: "noUselessFragment", node });
|
|
2630
2576
|
}
|
|
2631
|
-
const nonPaddingChildren = node.children.filter((child) => !
|
|
2577
|
+
const nonPaddingChildren = node.children.filter((child) => !JSX7__namespace.isPaddingSpaces(child));
|
|
2632
2578
|
if (nonPaddingChildren.length > 1) return;
|
|
2633
2579
|
if (nonPaddingChildren.length === 0) return context.report({ messageId: "noUselessFragment", node });
|
|
2634
2580
|
const [first] = nonPaddingChildren;
|
|
@@ -2870,7 +2816,7 @@ var prefer_shorthand_boolean_default = createRule({
|
|
|
2870
2816
|
create(context) {
|
|
2871
2817
|
function getReportDescriptor(node) {
|
|
2872
2818
|
const { value } = node;
|
|
2873
|
-
const propName =
|
|
2819
|
+
const propName = JSX7__namespace.getPropName(node);
|
|
2874
2820
|
const hasValueTrue = value?.type === types.AST_NODE_TYPES.JSXExpressionContainer && value.expression.type === types.AST_NODE_TYPES.Literal && value.expression.value === true;
|
|
2875
2821
|
if (!hasValueTrue) return eff.O.none();
|
|
2876
2822
|
return eff.O.some({
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { F, O, isString,
|
|
2
|
-
import * as
|
|
1
|
+
import { F, O, isString, isNullable } from '@eslint-react/eff';
|
|
2
|
+
import * as JSX7 from '@eslint-react/jsx';
|
|
3
3
|
import { createRuleForPlugin, normalizeSettings, decodeSettings, unsafeReadSettings } from '@eslint-react/shared';
|
|
4
4
|
import * as AST11 from '@eslint-react/ast';
|
|
5
|
-
import { isForwardRefCall, isThisSetState, isClassComponent, isChildrenCount, isChildrenForEach, isChildrenMap, isChildrenOnly, isChildrenToArray, useComponentCollectorLegacy, isCloneElementCall, isCreateRefCall, isComponentName,
|
|
5
|
+
import { isForwardRefCall, isThisSetState, isClassComponent, isChildrenCount, isChildrenForEach, isChildrenMap, isChildrenOnly, isChildrenToArray, useComponentCollectorLegacy, isCloneElementCall, isCreateRefCall, isComponentName, useComponentCollector, ERFunctionComponentFlag, isChildrenToArrayCall, ERComponentHint, isDirectValueOfRenderPropertyLoose, isDeclaredInRenderPropLoose, isInsideCreateElementProps, isInsideRenderMethod, ERClassComponentFlag, isFragmentElement, isCreateElementCall, isInitializedFromReact } from '@eslint-react/core';
|
|
6
6
|
import { AST_NODE_TYPES } from '@typescript-eslint/types';
|
|
7
7
|
import { isMatching, P, match } from 'ts-pattern';
|
|
8
8
|
import { compare } from 'compare-versions';
|
|
@@ -15,7 +15,7 @@ import { getTypeImmutability, isUnknown, isImmutable, isReadonlyShallow, isReado
|
|
|
15
15
|
|
|
16
16
|
// package.json
|
|
17
17
|
var name = "eslint-plugin-react-x";
|
|
18
|
-
var version = "1.22.2-beta.
|
|
18
|
+
var version = "1.22.2-beta.8";
|
|
19
19
|
var createRule = createRuleForPlugin("x");
|
|
20
20
|
|
|
21
21
|
// src/rules/avoid-shorthand-boolean.ts
|
|
@@ -43,7 +43,7 @@ var avoid_shorthand_boolean_default = createRule({
|
|
|
43
43
|
messageId: "avoidShorthandBoolean",
|
|
44
44
|
node,
|
|
45
45
|
data: {
|
|
46
|
-
propName:
|
|
46
|
+
propName: JSX7.getPropName(node)
|
|
47
47
|
},
|
|
48
48
|
fix: (fixer) => fixer.insertTextAfter(node.name, `={true}`)
|
|
49
49
|
});
|
|
@@ -124,7 +124,7 @@ var RULE_FEATURES4 = [
|
|
|
124
124
|
"CHK"
|
|
125
125
|
];
|
|
126
126
|
function getName(node) {
|
|
127
|
-
if (node
|
|
127
|
+
if (AST11.isTypeExpression(node)) {
|
|
128
128
|
return getName(node.expression);
|
|
129
129
|
}
|
|
130
130
|
if (node.type === AST_NODE_TYPES.Identifier || node.type === AST_NODE_TYPES.PrivateIdentifier) {
|
|
@@ -510,7 +510,7 @@ var no_children_prop_default = createRule({
|
|
|
510
510
|
return {
|
|
511
511
|
JSXElement(node) {
|
|
512
512
|
const initialScope = context.sourceCode.getScope(node);
|
|
513
|
-
const prop =
|
|
513
|
+
const prop = JSX7.getProp(node.openingElement.attributes, "children", initialScope);
|
|
514
514
|
const reportDescriptor = O.map(prop, (prop2) => ({ messageId: "noChildrenProp", node: prop2 }));
|
|
515
515
|
O.map(reportDescriptor, context.report);
|
|
516
516
|
}
|
|
@@ -885,7 +885,7 @@ var no_context_provider_default = createRule({
|
|
|
885
885
|
if (compare(version2, "19.0.0", "<")) return {};
|
|
886
886
|
return {
|
|
887
887
|
JSXElement(node) {
|
|
888
|
-
const elementName =
|
|
888
|
+
const elementName = JSX7.getElementName(node.openingElement);
|
|
889
889
|
if (!elementName.endsWith(".Provider")) return;
|
|
890
890
|
context.report({
|
|
891
891
|
messageId: "noContextProvider",
|
|
@@ -982,7 +982,7 @@ var RULE_FEATURES22 = [
|
|
|
982
982
|
"CHK"
|
|
983
983
|
];
|
|
984
984
|
function getName2(node) {
|
|
985
|
-
if (node
|
|
985
|
+
if (AST11.isTypeExpression(node)) {
|
|
986
986
|
return getName2(node.expression);
|
|
987
987
|
}
|
|
988
988
|
if (node.type === AST_NODE_TYPES.Identifier || node.type === AST_NODE_TYPES.PrivateIdentifier) {
|
|
@@ -1096,116 +1096,61 @@ var no_duplicate_key_default = createRule({
|
|
|
1096
1096
|
},
|
|
1097
1097
|
name: RULE_NAME24,
|
|
1098
1098
|
create(context) {
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1099
|
+
if (!context.sourceCode.getText().includes("key=")) return {};
|
|
1100
|
+
const keyedEntries = /* @__PURE__ */ new Map();
|
|
1101
|
+
function isKeyValueEqual(a, b) {
|
|
1102
|
+
const aValue = a.value;
|
|
1103
|
+
const bValue = b.value;
|
|
1104
|
+
if (aValue === null || bValue === null) return false;
|
|
1105
|
+
return AST11.isNodeEqual(aValue, bValue);
|
|
1102
1106
|
}
|
|
1103
|
-
function checkIteratorElement(node) {
|
|
1104
|
-
if (node.type !== AST_NODE_TYPES.JSXElement) return O.none();
|
|
1105
|
-
const initialScope = context.sourceCode.getScope(node);
|
|
1106
|
-
return F.pipe(
|
|
1107
|
-
JSX8.findPropInAttributes(node.openingElement.attributes, initialScope)("key"),
|
|
1108
|
-
O.flatMap((k) => "value" in k ? O.fromNullable(k.value) : O.none()),
|
|
1109
|
-
O.flatMap((v) => {
|
|
1110
|
-
return isKeyEqual(v, v) ? O.some({
|
|
1111
|
-
messageId: "noDuplicateKey",
|
|
1112
|
-
node: v,
|
|
1113
|
-
data: {
|
|
1114
|
-
value: context.sourceCode.getText(v)
|
|
1115
|
-
}
|
|
1116
|
-
}) : O.none();
|
|
1117
|
-
})
|
|
1118
|
-
);
|
|
1119
|
-
}
|
|
1120
|
-
function checkExpression(node) {
|
|
1121
|
-
switch (node.type) {
|
|
1122
|
-
case AST_NODE_TYPES.ConditionalExpression:
|
|
1123
|
-
if (!("consequent" in node)) return O.none();
|
|
1124
|
-
return F.pipe(
|
|
1125
|
-
checkIteratorElement(node.consequent),
|
|
1126
|
-
O.orElse(() => checkIteratorElement(node.alternate))
|
|
1127
|
-
);
|
|
1128
|
-
case AST_NODE_TYPES.JSXElement:
|
|
1129
|
-
case AST_NODE_TYPES.JSXFragment:
|
|
1130
|
-
return checkIteratorElement(node);
|
|
1131
|
-
case AST_NODE_TYPES.LogicalExpression:
|
|
1132
|
-
if (!("left" in node)) return O.none();
|
|
1133
|
-
return F.pipe(
|
|
1134
|
-
checkIteratorElement(node.left),
|
|
1135
|
-
O.orElse(() => checkIteratorElement(node.right))
|
|
1136
|
-
);
|
|
1137
|
-
default:
|
|
1138
|
-
return O.none();
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
function checkBlockStatement(node) {
|
|
1142
|
-
return AST11.getNestedReturnStatements(node).reduce((acc, statement) => {
|
|
1143
|
-
if (!statement.argument) return acc;
|
|
1144
|
-
const maybeDescriptor = checkIteratorElement(statement.argument);
|
|
1145
|
-
if (O.isNone(maybeDescriptor)) return acc;
|
|
1146
|
-
const descriptor = maybeDescriptor.value;
|
|
1147
|
-
return [...acc, descriptor];
|
|
1148
|
-
}, []);
|
|
1149
|
-
}
|
|
1150
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
1151
1107
|
return {
|
|
1152
|
-
"
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1108
|
+
"JSXAttribute[name.name='key']"(node) {
|
|
1109
|
+
const jsxElement = node.parent.parent;
|
|
1110
|
+
switch (jsxElement.parent.type) {
|
|
1111
|
+
case AST_NODE_TYPES.ArrayExpression:
|
|
1112
|
+
case AST_NODE_TYPES.JSXElement:
|
|
1113
|
+
case AST_NODE_TYPES.JSXFragment: {
|
|
1114
|
+
const root = jsxElement.parent;
|
|
1115
|
+
const prevKeys = keyedEntries.get(root)?.keys ?? [];
|
|
1116
|
+
keyedEntries.set(root, {
|
|
1117
|
+
hasDuplicate: prevKeys.some((prevKey) => isKeyValueEqual(prevKey, node)),
|
|
1118
|
+
keys: [...prevKeys, node],
|
|
1119
|
+
root: jsxElement.parent
|
|
1160
1120
|
});
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
data: {
|
|
1178
|
-
value: context.sourceCode.getText(value)
|
|
1121
|
+
break;
|
|
1122
|
+
}
|
|
1123
|
+
default: {
|
|
1124
|
+
const entry = F.pipe(
|
|
1125
|
+
O.Do,
|
|
1126
|
+
O.bind("call", () => AST11.traverseUpGuard(jsxElement, AST11.isMapCallLoose)),
|
|
1127
|
+
O.bind("iter", ({ call }) => AST11.traverseUpStop(jsxElement, call, AST11.isFunction)),
|
|
1128
|
+
O.bind("arg0", ({ call }) => O.fromNullable(call.arguments[0]))
|
|
1129
|
+
);
|
|
1130
|
+
for (const { arg0, call, iter } of O.toArray(entry)) {
|
|
1131
|
+
if (AST11.unwrapTypeExpression(arg0) !== iter) continue;
|
|
1132
|
+
keyedEntries.set(call, {
|
|
1133
|
+
hasDuplicate: node.value?.type === AST_NODE_TYPES.Literal,
|
|
1134
|
+
keys: [node],
|
|
1135
|
+
root: call
|
|
1136
|
+
});
|
|
1179
1137
|
}
|
|
1180
|
-
}
|
|
1138
|
+
}
|
|
1181
1139
|
}
|
|
1182
1140
|
},
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
}, node);
|
|
1195
|
-
if (!isMapCall && !isArrayFromCall) return;
|
|
1196
|
-
if (MutRef.get(isWithinChildrenToArrayRef)) return;
|
|
1197
|
-
const fn = node.arguments[isMapCall ? 0 : 1];
|
|
1198
|
-
if (!AST11.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(fn)) return;
|
|
1199
|
-
if (fn.body.type === AST_NODE_TYPES.BlockStatement) {
|
|
1200
|
-
for (const descriptor of checkBlockStatement(fn.body)) {
|
|
1201
|
-
context.report(descriptor);
|
|
1141
|
+
"Program:exit"() {
|
|
1142
|
+
for (const { hasDuplicate, keys } of keyedEntries.values()) {
|
|
1143
|
+
if (!hasDuplicate) continue;
|
|
1144
|
+
for (const key of keys) {
|
|
1145
|
+
context.report({
|
|
1146
|
+
messageId: "noDuplicateKey",
|
|
1147
|
+
node: key,
|
|
1148
|
+
data: {
|
|
1149
|
+
value: context.sourceCode.getText(key)
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1202
1152
|
}
|
|
1203
|
-
return;
|
|
1204
1153
|
}
|
|
1205
|
-
O.map(checkExpression(fn.body), context.report);
|
|
1206
|
-
},
|
|
1207
|
-
"CallExpression:exit"(node) {
|
|
1208
|
-
if (isChildrenToArrayCall(node, context)) MutRef.set(isWithinChildrenToArrayRef, false);
|
|
1209
1154
|
}
|
|
1210
1155
|
};
|
|
1211
1156
|
},
|
|
@@ -1328,7 +1273,7 @@ var no_implicit_key_default = createRule({
|
|
|
1328
1273
|
create(context) {
|
|
1329
1274
|
function getReportDescriptor(node) {
|
|
1330
1275
|
const initialScope = context.sourceCode.getScope(node);
|
|
1331
|
-
const keyPropFound =
|
|
1276
|
+
const keyPropFound = JSX7.findPropInAttributes(node.attributes, initialScope)("key");
|
|
1332
1277
|
const keyPropOnElement = node.attributes.some(
|
|
1333
1278
|
(n) => AST11.is(AST_NODE_TYPES.JSXAttribute)(n) && n.name.name === "key"
|
|
1334
1279
|
);
|
|
@@ -1568,12 +1513,12 @@ var no_missing_key_default = createRule({
|
|
|
1568
1513
|
},
|
|
1569
1514
|
name: RULE_NAME29,
|
|
1570
1515
|
create(context) {
|
|
1571
|
-
const
|
|
1516
|
+
const state = { isWithinChildrenToArray: false };
|
|
1572
1517
|
function checkIteratorElement(node) {
|
|
1573
1518
|
switch (node.type) {
|
|
1574
1519
|
case AST_NODE_TYPES.JSXElement: {
|
|
1575
1520
|
const initialScope = context.sourceCode.getScope(node);
|
|
1576
|
-
if (!
|
|
1521
|
+
if (!JSX7.hasProp(node.openingElement.attributes, "key", initialScope)) {
|
|
1577
1522
|
return O.some({
|
|
1578
1523
|
messageId: "noMissingKey",
|
|
1579
1524
|
node
|
|
@@ -1617,12 +1562,12 @@ var no_missing_key_default = createRule({
|
|
|
1617
1562
|
}
|
|
1618
1563
|
return {
|
|
1619
1564
|
ArrayExpression(node) {
|
|
1620
|
-
if (
|
|
1565
|
+
if (state.isWithinChildrenToArray) return;
|
|
1621
1566
|
const elements = node.elements.filter(AST11.is(AST_NODE_TYPES.JSXElement));
|
|
1622
1567
|
if (elements.length === 0) return;
|
|
1623
1568
|
const initialScope = context.sourceCode.getScope(node);
|
|
1624
1569
|
for (const element of elements) {
|
|
1625
|
-
if (!
|
|
1570
|
+
if (!JSX7.hasProp(element.openingElement.attributes, "key", initialScope)) {
|
|
1626
1571
|
context.report({
|
|
1627
1572
|
messageId: "noMissingKey",
|
|
1628
1573
|
node: element
|
|
@@ -1631,7 +1576,8 @@ var no_missing_key_default = createRule({
|
|
|
1631
1576
|
}
|
|
1632
1577
|
},
|
|
1633
1578
|
CallExpression(node) {
|
|
1634
|
-
|
|
1579
|
+
state.isWithinChildrenToArray ||= isChildrenToArrayCall(node, context);
|
|
1580
|
+
if (state.isWithinChildrenToArray) return;
|
|
1635
1581
|
const isMapCall = AST11.isMapCallLoose(node);
|
|
1636
1582
|
const isArrayFromCall = isMatching({
|
|
1637
1583
|
type: AST_NODE_TYPES.CallExpression,
|
|
@@ -1643,7 +1589,6 @@ var no_missing_key_default = createRule({
|
|
|
1643
1589
|
}
|
|
1644
1590
|
}, node);
|
|
1645
1591
|
if (!isMapCall && !isArrayFromCall) return;
|
|
1646
|
-
if (MutRef.get(isWithinChildrenToArrayRef)) return;
|
|
1647
1592
|
const fn = node.arguments[isMapCall ? 0 : 1];
|
|
1648
1593
|
if (!AST11.isOneOf([AST_NODE_TYPES.ArrowFunctionExpression, AST_NODE_TYPES.FunctionExpression])(fn)) return;
|
|
1649
1594
|
if (fn.body.type === AST_NODE_TYPES.BlockStatement) {
|
|
@@ -1655,10 +1600,11 @@ var no_missing_key_default = createRule({
|
|
|
1655
1600
|
O.map(checkExpression(fn.body), context.report);
|
|
1656
1601
|
},
|
|
1657
1602
|
"CallExpression:exit"(node) {
|
|
1658
|
-
if (isChildrenToArrayCall(node, context))
|
|
1603
|
+
if (!isChildrenToArrayCall(node, context)) return;
|
|
1604
|
+
state.isWithinChildrenToArray = false;
|
|
1659
1605
|
},
|
|
1660
1606
|
JSXFragment(node) {
|
|
1661
|
-
if (
|
|
1607
|
+
if (state.isWithinChildrenToArray) return;
|
|
1662
1608
|
if (node.parent.type === AST_NODE_TYPES.ArrayExpression) {
|
|
1663
1609
|
context.report({
|
|
1664
1610
|
messageId: "noMissingKeyWithFragment",
|
|
@@ -1709,7 +1655,7 @@ var no_nested_components_default = createRule({
|
|
|
1709
1655
|
if (O.isNone(componentName)) continue;
|
|
1710
1656
|
const name2 = componentName.value;
|
|
1711
1657
|
const isInsideProperty = component.parent.type === AST_NODE_TYPES.Property;
|
|
1712
|
-
const isInsideJSXPropValue = component.parent.type === AST_NODE_TYPES.JSXAttribute || O.isSome(
|
|
1658
|
+
const isInsideJSXPropValue = component.parent.type === AST_NODE_TYPES.JSXAttribute || O.isSome(JSX7.traverseUpProp(node, (n) => n.value?.type === AST_NODE_TYPES.JSXExpressionContainer));
|
|
1713
1659
|
if (isInsideJSXPropValue) {
|
|
1714
1660
|
if (!isDeclaredInRenderPropLoose(component)) {
|
|
1715
1661
|
context.report({
|
|
@@ -2333,7 +2279,7 @@ var LIFECYCLE_METHODS = /* @__PURE__ */ new Set([
|
|
|
2333
2279
|
"UNSAFE_componentWillUpdate"
|
|
2334
2280
|
]);
|
|
2335
2281
|
function getName3(node) {
|
|
2336
|
-
if (node
|
|
2282
|
+
if (AST11.isTypeExpression(node)) {
|
|
2337
2283
|
return getName3(node.expression);
|
|
2338
2284
|
}
|
|
2339
2285
|
if (node.type === AST_NODE_TYPES.Identifier || node.type === AST_NODE_TYPES.PrivateIdentifier) {
|
|
@@ -2447,7 +2393,7 @@ var RULE_FEATURES43 = [
|
|
|
2447
2393
|
"CHK"
|
|
2448
2394
|
];
|
|
2449
2395
|
function getName4(node) {
|
|
2450
|
-
if (node
|
|
2396
|
+
if (AST11.isTypeExpression(node)) {
|
|
2451
2397
|
return getName4(node.expression);
|
|
2452
2398
|
}
|
|
2453
2399
|
if (node.type === AST_NODE_TYPES.Identifier || node.type === AST_NODE_TYPES.PrivateIdentifier) {
|
|
@@ -2590,18 +2536,18 @@ var no_unused_state_default = createRule({
|
|
|
2590
2536
|
var RULE_NAME44 = "no-useless-fragment";
|
|
2591
2537
|
function check(node, context, allowExpressions) {
|
|
2592
2538
|
const initialScope = context.sourceCode.getScope(node);
|
|
2593
|
-
if (
|
|
2594
|
-
if (
|
|
2539
|
+
if (JSX7.isKeyedElement(node, initialScope)) return;
|
|
2540
|
+
if (JSX7.isBuiltInElement(node.parent)) context.report({ messageId: "noUselessFragmentInBuiltIn", node });
|
|
2595
2541
|
if (node.children.length === 0) return context.report({ messageId: "noUselessFragment", node });
|
|
2596
2542
|
const isChildren = AST11.isOneOf([AST_NODE_TYPES.JSXElement, AST_NODE_TYPES.JSXFragment])(node.parent);
|
|
2597
2543
|
const [firstChildren] = node.children;
|
|
2598
|
-
if (allowExpressions && node.children.length === 1 &&
|
|
2544
|
+
if (allowExpressions && node.children.length === 1 && JSX7.isLiteral(firstChildren) && !isChildren) return;
|
|
2599
2545
|
if (!allowExpressions && isChildren) {
|
|
2600
2546
|
return context.report({ messageId: "noUselessFragment", node });
|
|
2601
2547
|
} else if (!allowExpressions && !isChildren && node.children.length === 1) {
|
|
2602
2548
|
return context.report({ messageId: "noUselessFragment", node });
|
|
2603
2549
|
}
|
|
2604
|
-
const nonPaddingChildren = node.children.filter((child) => !
|
|
2550
|
+
const nonPaddingChildren = node.children.filter((child) => !JSX7.isPaddingSpaces(child));
|
|
2605
2551
|
if (nonPaddingChildren.length > 1) return;
|
|
2606
2552
|
if (nonPaddingChildren.length === 0) return context.report({ messageId: "noUselessFragment", node });
|
|
2607
2553
|
const [first] = nonPaddingChildren;
|
|
@@ -2843,7 +2789,7 @@ var prefer_shorthand_boolean_default = createRule({
|
|
|
2843
2789
|
create(context) {
|
|
2844
2790
|
function getReportDescriptor(node) {
|
|
2845
2791
|
const { value } = node;
|
|
2846
|
-
const propName =
|
|
2792
|
+
const propName = JSX7.getPropName(node);
|
|
2847
2793
|
const hasValueTrue = value?.type === AST_NODE_TYPES.JSXExpressionContainer && value.expression.type === AST_NODE_TYPES.Literal && value.expression.value === true;
|
|
2848
2794
|
if (!hasValueTrue) return O.none();
|
|
2849
2795
|
return O.some({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-x",
|
|
3
|
-
"version": "1.22.2-beta.
|
|
3
|
+
"version": "1.22.2-beta.8",
|
|
4
4
|
"description": "A set of composable ESLint rules for libraries and frameworks that use React as a UI runtime.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
"string-ts": "^2.2.0",
|
|
50
50
|
"ts-api-utils": "^2.0.0",
|
|
51
51
|
"ts-pattern": "^5.6.0",
|
|
52
|
-
"@eslint-react/
|
|
53
|
-
"@eslint-react/
|
|
54
|
-
"@eslint-react/
|
|
55
|
-
"@eslint-react/
|
|
56
|
-
"@eslint-react/
|
|
57
|
-
"@eslint-react/var": "1.22.2-beta.
|
|
58
|
-
"@eslint-react/
|
|
52
|
+
"@eslint-react/ast": "1.22.2-beta.8",
|
|
53
|
+
"@eslint-react/core": "1.22.2-beta.8",
|
|
54
|
+
"@eslint-react/jsx": "1.22.2-beta.8",
|
|
55
|
+
"@eslint-react/shared": "1.22.2-beta.8",
|
|
56
|
+
"@eslint-react/eff": "1.22.2-beta.8",
|
|
57
|
+
"@eslint-react/var": "1.22.2-beta.8",
|
|
58
|
+
"@eslint-react/types": "1.22.2-beta.8"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@types/react": "^19.0.2",
|