eslint-plugin-react-x 3.0.0-beta.69 → 3.0.0-beta.70
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 +35 -41
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_ESLINT_REACT_SETTINGS, IMPURE_CTORS, IMPURE_FUNCS, WEBSITE_URL, defineRuleListener, getSettingsFromContext, report, toRegExp } from "@eslint-react/shared";
|
|
2
2
|
import * as ast from "@eslint-react/ast";
|
|
3
3
|
import * as core from "@eslint-react/core";
|
|
4
|
+
import { JsxEmit, JsxInspector } from "@eslint-react/core";
|
|
4
5
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
5
6
|
import { P, isMatching, match } from "ts-pattern";
|
|
6
7
|
import ts from "typescript";
|
|
@@ -147,7 +148,7 @@ const rules$7 = {
|
|
|
147
148
|
//#endregion
|
|
148
149
|
//#region package.json
|
|
149
150
|
var name$6 = "eslint-plugin-react-x";
|
|
150
|
-
var version = "3.0.0-beta.
|
|
151
|
+
var version = "3.0.0-beta.70";
|
|
151
152
|
|
|
152
153
|
//#endregion
|
|
153
154
|
//#region src/utils/create-rule.ts
|
|
@@ -1540,11 +1541,8 @@ var jsx_key_before_spread_default = createRule({
|
|
|
1540
1541
|
defaultOptions: []
|
|
1541
1542
|
});
|
|
1542
1543
|
function create$59(context) {
|
|
1543
|
-
const { jsx } =
|
|
1544
|
-
|
|
1545
|
-
...core.getJsxConfigFromAnnotation(context)
|
|
1546
|
-
};
|
|
1547
|
-
if (jsx !== core.JsxEmit.ReactJSX && jsx !== core.JsxEmit.ReactJSXDev) return {};
|
|
1544
|
+
const { jsx } = JsxInspector.from(context).jsxConfig;
|
|
1545
|
+
if (jsx !== JsxEmit.ReactJSX && jsx !== JsxEmit.ReactJSXDev) return {};
|
|
1548
1546
|
return defineRuleListener({ JSXOpeningElement(node) {
|
|
1549
1547
|
let firstSpreadPropIndex = null;
|
|
1550
1548
|
for (const [index, prop] of node.attributes.entries()) {
|
|
@@ -1649,9 +1647,10 @@ var jsx_shorthand_boolean_default = createRule({
|
|
|
1649
1647
|
});
|
|
1650
1648
|
function create$56(context) {
|
|
1651
1649
|
const policy = context.options[0] ?? defaultOptions$4[0];
|
|
1650
|
+
const jsx = JsxInspector.from(context);
|
|
1652
1651
|
return defineRuleListener({ JSXAttribute(node) {
|
|
1653
1652
|
const { value } = node;
|
|
1654
|
-
const propName =
|
|
1653
|
+
const propName = jsx.getAttributeName(node);
|
|
1655
1654
|
switch (true) {
|
|
1656
1655
|
case policy === 1 && value?.type === AST_NODE_TYPES.JSXExpressionContainer && value.expression.type === AST_NODE_TYPES.Literal && value.expression.value === true:
|
|
1657
1656
|
context.report({
|
|
@@ -1695,13 +1694,10 @@ var jsx_shorthand_fragment_default = createRule({
|
|
|
1695
1694
|
});
|
|
1696
1695
|
function create$55(context) {
|
|
1697
1696
|
const policy = context.options[0] ?? defaultOptions$3[0];
|
|
1698
|
-
const
|
|
1699
|
-
|
|
1700
|
-
...core.getJsxConfigFromAnnotation(context)
|
|
1701
|
-
};
|
|
1702
|
-
const { jsxFragmentFactory } = jsxConfig;
|
|
1697
|
+
const jsx = JsxInspector.from(context);
|
|
1698
|
+
const { jsxFragmentFactory } = jsx.jsxConfig;
|
|
1703
1699
|
return match(policy).with(1, () => defineRuleListener({ JSXElement(node) {
|
|
1704
|
-
if (!
|
|
1700
|
+
if (!jsx.isFragmentElement(node)) return;
|
|
1705
1701
|
if (node.openingElement.attributes.length > 0) return;
|
|
1706
1702
|
context.report({
|
|
1707
1703
|
data: { message: "Use fragment shorthand syntax instead of 'Fragment' component." },
|
|
@@ -1741,11 +1737,8 @@ var jsx_uses_react_default = createRule({
|
|
|
1741
1737
|
defaultOptions: []
|
|
1742
1738
|
});
|
|
1743
1739
|
function create$54(context) {
|
|
1744
|
-
const { jsx, jsxFactory, jsxFragmentFactory } =
|
|
1745
|
-
|
|
1746
|
-
...core.getJsxConfigFromAnnotation(context)
|
|
1747
|
-
};
|
|
1748
|
-
if (jsx === core.JsxEmit.ReactJSX || jsx === core.JsxEmit.ReactJSXDev) return {};
|
|
1740
|
+
const { jsx, jsxFactory, jsxFragmentFactory } = JsxInspector.from(context).jsxConfig;
|
|
1741
|
+
if (jsx === JsxEmit.ReactJSX || jsx === JsxEmit.ReactJSXDev) return {};
|
|
1749
1742
|
function handleJsxElement(node) {
|
|
1750
1743
|
context.sourceCode.markVariableAsUsed(jsxFactory, node);
|
|
1751
1744
|
debugReport(context, node, jsxFactory);
|
|
@@ -2110,8 +2103,9 @@ var no_children_prop_default = createRule({
|
|
|
2110
2103
|
defaultOptions: []
|
|
2111
2104
|
});
|
|
2112
2105
|
function create$46(context) {
|
|
2106
|
+
const jsx = JsxInspector.from(context);
|
|
2113
2107
|
return defineRuleListener({ JSXElement(node) {
|
|
2114
|
-
const childrenProp =
|
|
2108
|
+
const childrenProp = jsx.findAttribute(node, "children");
|
|
2115
2109
|
if (childrenProp != null) context.report({
|
|
2116
2110
|
messageId: "default",
|
|
2117
2111
|
node: childrenProp
|
|
@@ -2316,8 +2310,9 @@ function create$39(context) {
|
|
|
2316
2310
|
if (!context.sourceCode.text.includes("Provider")) return {};
|
|
2317
2311
|
const { version } = getSettingsFromContext(context);
|
|
2318
2312
|
if (compare(version, "19.0.0", "<")) return {};
|
|
2313
|
+
const jsx = JsxInspector.from(context);
|
|
2319
2314
|
return defineRuleListener({ JSXElement(node) {
|
|
2320
|
-
const parts =
|
|
2315
|
+
const parts = jsx.getElementType(node).split(".");
|
|
2321
2316
|
const selfName = parts.pop();
|
|
2322
2317
|
const contextFullName = parts.join(".");
|
|
2323
2318
|
const contextSelfName = parts.pop();
|
|
@@ -2797,9 +2792,10 @@ var no_missing_key_default = createRule({
|
|
|
2797
2792
|
defaultOptions: []
|
|
2798
2793
|
});
|
|
2799
2794
|
function create$30(ctx) {
|
|
2795
|
+
const jsx = JsxInspector.from(ctx);
|
|
2800
2796
|
let inChildrenToArray = false;
|
|
2801
2797
|
function check(node) {
|
|
2802
|
-
if (node.type === AST_NODE_TYPES.JSXElement) return
|
|
2798
|
+
if (node.type === AST_NODE_TYPES.JSXElement) return !jsx.hasAttribute(node, "key") ? {
|
|
2803
2799
|
messageId: "default",
|
|
2804
2800
|
node
|
|
2805
2801
|
} : null;
|
|
@@ -2834,7 +2830,7 @@ function create$30(ctx) {
|
|
|
2834
2830
|
const elements = node.elements.filter(ast.is(AST_NODE_TYPES.JSXElement));
|
|
2835
2831
|
if (elements.length === 0) return;
|
|
2836
2832
|
const scope = ctx.sourceCode.getScope(node);
|
|
2837
|
-
for (const el of elements) if (
|
|
2833
|
+
for (const el of elements) if (!jsx.hasAttribute(el, "key", scope)) ctx.report({
|
|
2838
2834
|
messageId: "default",
|
|
2839
2835
|
node: el
|
|
2840
2836
|
});
|
|
@@ -3002,7 +2998,7 @@ function create$28(context) {
|
|
|
3002
2998
|
* @returns `true` if the node is inside JSX attribute value
|
|
3003
2999
|
*/
|
|
3004
3000
|
function isInsideJSXAttributeValue(node) {
|
|
3005
|
-
return node.parent.type === AST_NODE_TYPES.JSXAttribute ||
|
|
3001
|
+
return node.parent.type === AST_NODE_TYPES.JSXAttribute || JsxInspector.findParentAttribute(node, (n) => n.value?.type === AST_NODE_TYPES.JSXExpressionContainer) != null;
|
|
3006
3002
|
}
|
|
3007
3003
|
/**
|
|
3008
3004
|
* Check whether a given node is declared inside a class component's render block
|
|
@@ -3495,9 +3491,10 @@ function create$16(context) {
|
|
|
3495
3491
|
const isReact18OrBelow = compare(version, "19.0.0", "<");
|
|
3496
3492
|
const { ctx, visitor } = core.useComponentCollector(context);
|
|
3497
3493
|
const constructions = /* @__PURE__ */ new WeakMap();
|
|
3494
|
+
const jsx = JsxInspector.from(context);
|
|
3498
3495
|
return defineRuleListener(visitor, {
|
|
3499
3496
|
JSXOpeningElement(node) {
|
|
3500
|
-
const selfName =
|
|
3497
|
+
const selfName = jsx.getElementType(node.parent).split(".").at(-1);
|
|
3501
3498
|
if (selfName == null) return;
|
|
3502
3499
|
if (!isContextName(selfName, isReact18OrBelow)) return;
|
|
3503
3500
|
const functionEntry = ctx.getCurrentEntry();
|
|
@@ -4047,15 +4044,12 @@ var no_useless_fragment_default = createRule({
|
|
|
4047
4044
|
});
|
|
4048
4045
|
function create$10(context, [option]) {
|
|
4049
4046
|
const { allowEmptyFragment = false, allowExpressions = true } = option;
|
|
4050
|
-
const
|
|
4051
|
-
...core.getJsxConfigFromContext(context),
|
|
4052
|
-
...core.getJsxConfigFromAnnotation(context)
|
|
4053
|
-
};
|
|
4047
|
+
const jsx = JsxInspector.from(context);
|
|
4054
4048
|
/**
|
|
4055
4049
|
* Check if a fragment node is useless and should be reported
|
|
4056
4050
|
*/
|
|
4057
4051
|
function checkNode(context, node) {
|
|
4058
|
-
if (
|
|
4052
|
+
if (jsx.isHostElement(node.parent)) context.report({
|
|
4059
4053
|
data: { reason: "placed inside a host component" },
|
|
4060
4054
|
fix: getFix(context, node),
|
|
4061
4055
|
messageId: "default",
|
|
@@ -4073,7 +4067,7 @@ function create$10(context, [option]) {
|
|
|
4073
4067
|
}
|
|
4074
4068
|
const isChildElement = ast.isOneOf([AST_NODE_TYPES.JSXElement, AST_NODE_TYPES.JSXFragment])(node.parent);
|
|
4075
4069
|
switch (true) {
|
|
4076
|
-
case allowExpressions && !isChildElement && node.children.length === 1 &&
|
|
4070
|
+
case allowExpressions && !isChildElement && node.children.length === 1 && JsxInspector.isJsxText(node.children.at(0) ?? null): return;
|
|
4077
4071
|
case !allowExpressions && isChildElement:
|
|
4078
4072
|
context.report({
|
|
4079
4073
|
data: { reason: "contains less than two children" },
|
|
@@ -4113,15 +4107,15 @@ function create$10(context, [option]) {
|
|
|
4113
4107
|
* Check if it's safe to automatically fix the fragment
|
|
4114
4108
|
*/
|
|
4115
4109
|
function canFix(context, node) {
|
|
4116
|
-
if (node.parent.type === AST_NODE_TYPES.JSXElement || node.parent.type === AST_NODE_TYPES.JSXFragment) return
|
|
4110
|
+
if (node.parent.type === AST_NODE_TYPES.JSXElement || node.parent.type === AST_NODE_TYPES.JSXFragment) return jsx.isHostElement(node.parent);
|
|
4117
4111
|
if (node.children.length === 0) return false;
|
|
4118
|
-
return !node.children.some((child) =>
|
|
4112
|
+
return !node.children.some((child) => JsxInspector.isJsxText(child) && !isWhiteSpace(child) || ast.is(AST_NODE_TYPES.JSXExpressionContainer)(child));
|
|
4119
4113
|
}
|
|
4120
4114
|
return defineRuleListener({
|
|
4121
4115
|
JSXElement(node) {
|
|
4122
|
-
if (!
|
|
4123
|
-
if (
|
|
4124
|
-
if (
|
|
4116
|
+
if (!jsx.isFragmentElement(node)) return;
|
|
4117
|
+
if (jsx.hasAttribute(node, "key")) return;
|
|
4118
|
+
if (jsx.hasAttribute(node, "ref")) return;
|
|
4125
4119
|
checkNode(context, node);
|
|
4126
4120
|
},
|
|
4127
4121
|
JSXFragment(node) {
|
|
@@ -4139,7 +4133,7 @@ function isWhiteSpace(node) {
|
|
|
4139
4133
|
* Check if a node is padding spaces (whitespace with line breaks)
|
|
4140
4134
|
*/
|
|
4141
4135
|
function isPaddingSpaces(node) {
|
|
4142
|
-
return
|
|
4136
|
+
return JsxInspector.isJsxText(node) && isWhiteSpace(node) && node.raw.includes("\n");
|
|
4143
4137
|
}
|
|
4144
4138
|
/**
|
|
4145
4139
|
* Trim whitespace like React would in JSX
|
|
@@ -7213,12 +7207,12 @@ function create(context) {
|
|
|
7213
7207
|
if (controlledProp == null) continue;
|
|
7214
7208
|
if (!attributes.has(controlledProp)) continue;
|
|
7215
7209
|
context.report({
|
|
7216
|
-
node: attrNode,
|
|
7217
|
-
messageId: "noControlledAndUncontrolledTogether",
|
|
7218
7210
|
data: {
|
|
7219
7211
|
controlled: controlledProp,
|
|
7220
7212
|
uncontrolled: propName
|
|
7221
|
-
}
|
|
7213
|
+
},
|
|
7214
|
+
messageId: "noControlledAndUncontrolledTogether",
|
|
7215
|
+
node: attrNode
|
|
7222
7216
|
});
|
|
7223
7217
|
}
|
|
7224
7218
|
} });
|
|
@@ -7466,10 +7460,10 @@ const settings = { ...settings$1 };
|
|
|
7466
7460
|
const finalPlugin = {
|
|
7467
7461
|
...plugin,
|
|
7468
7462
|
configs: {
|
|
7469
|
-
["disable-experimental"]: disable_experimental_exports,
|
|
7470
|
-
["disable-type-checked"]: disable_type_checked_exports,
|
|
7471
7463
|
["disable-conflict-eslint-plugin-react"]: disable_conflict_eslint_plugin_react_exports,
|
|
7472
7464
|
["disable-conflict-eslint-plugin-react-hooks"]: disable_conflict_eslint_plugin_react_hooks_exports,
|
|
7465
|
+
["disable-experimental"]: disable_experimental_exports,
|
|
7466
|
+
["disable-type-checked"]: disable_type_checked_exports,
|
|
7473
7467
|
["recommended"]: recommended_exports,
|
|
7474
7468
|
["recommended-type-checked"]: recommended_type_checked_exports,
|
|
7475
7469
|
["recommended-typescript"]: recommended_typescript_exports,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-x",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.70",
|
|
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",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
"string-ts": "^2.3.1",
|
|
46
46
|
"ts-api-utils": "^2.4.0",
|
|
47
47
|
"ts-pattern": "^5.9.0",
|
|
48
|
-
"@eslint-react/ast": "3.0.0-beta.
|
|
49
|
-
"@eslint-react/core": "3.0.0-beta.
|
|
50
|
-
"@eslint-react/
|
|
51
|
-
"@eslint-react/
|
|
52
|
-
"@eslint-react/var": "3.0.0-beta.
|
|
48
|
+
"@eslint-react/ast": "3.0.0-beta.70",
|
|
49
|
+
"@eslint-react/core": "3.0.0-beta.70",
|
|
50
|
+
"@eslint-react/shared": "3.0.0-beta.70",
|
|
51
|
+
"@eslint-react/eff": "3.0.0-beta.70",
|
|
52
|
+
"@eslint-react/var": "3.0.0-beta.70"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/react": "^19.2.14",
|