eslint-plugin-react-x 2.0.5-next.3 → 2.0.5-next.5
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 +76 -59
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -115,7 +115,7 @@ const settings = { ...settings$1 };
|
|
|
115
115
|
//#endregion
|
|
116
116
|
//#region package.json
|
|
117
117
|
var name = "eslint-plugin-react-x";
|
|
118
|
-
var version = "2.0.5-next.
|
|
118
|
+
var version = "2.0.5-next.5";
|
|
119
119
|
|
|
120
120
|
//#endregion
|
|
121
121
|
//#region src/utils/create-rule.ts
|
|
@@ -208,10 +208,10 @@ var jsx_key_before_spread_default = createRule({
|
|
|
208
208
|
meta: {
|
|
209
209
|
type: "problem",
|
|
210
210
|
docs: {
|
|
211
|
-
description: "Enforces that the 'key'
|
|
211
|
+
description: "Enforces that the 'key' prop is placed before the spread prop in JSX elements.",
|
|
212
212
|
[Symbol.for("rule_features")]: RULE_FEATURES$59
|
|
213
213
|
},
|
|
214
|
-
messages: { jsxKeyBeforeSpread: "The 'key'
|
|
214
|
+
messages: { jsxKeyBeforeSpread: "The 'key' prop must be placed before any spread props." },
|
|
215
215
|
schema: []
|
|
216
216
|
},
|
|
217
217
|
name: RULE_NAME$61,
|
|
@@ -220,16 +220,16 @@ var jsx_key_before_spread_default = createRule({
|
|
|
220
220
|
});
|
|
221
221
|
function create$61(context) {
|
|
222
222
|
return { JSXOpeningElement(node) {
|
|
223
|
-
let
|
|
224
|
-
for (const [index,
|
|
225
|
-
if (
|
|
226
|
-
|
|
223
|
+
let firstSpreadPropIndex = null;
|
|
224
|
+
for (const [index, prop] of node.attributes.entries()) {
|
|
225
|
+
if (prop.type === AST_NODE_TYPES.JSXSpreadAttribute) {
|
|
226
|
+
firstSpreadPropIndex ??= index;
|
|
227
227
|
continue;
|
|
228
228
|
}
|
|
229
|
-
if (
|
|
230
|
-
if (
|
|
229
|
+
if (firstSpreadPropIndex == null) continue;
|
|
230
|
+
if (prop.name.name === "key" && index > firstSpreadPropIndex) context.report({
|
|
231
231
|
messageId: "jsxKeyBeforeSpread",
|
|
232
|
-
node:
|
|
232
|
+
node: prop
|
|
233
233
|
});
|
|
234
234
|
}
|
|
235
235
|
} };
|
|
@@ -262,7 +262,6 @@ function create$60(context) {
|
|
|
262
262
|
const visitorFunction = (node) => {
|
|
263
263
|
if (!AST.isOneOf([AST_NODE_TYPES.JSXElement, AST_NODE_TYPES.JSXFragment])(node.parent)) return;
|
|
264
264
|
if (!hasCommentLike(node)) return;
|
|
265
|
-
if (!node.parent.type.includes("JSX")) return;
|
|
266
265
|
context.report({
|
|
267
266
|
messageId: "jsxNoCommentTextnodes",
|
|
268
267
|
node
|
|
@@ -1287,7 +1286,7 @@ var no_duplicate_key_default = createRule({
|
|
|
1287
1286
|
defaultOptions: []
|
|
1288
1287
|
});
|
|
1289
1288
|
function create$35(context) {
|
|
1290
|
-
if (!context.sourceCode.
|
|
1289
|
+
if (!context.sourceCode.text.includes("key=")) return {};
|
|
1291
1290
|
const keyedEntries = /* @__PURE__ */ new Map();
|
|
1292
1291
|
function isKeyValueEqual(a, b) {
|
|
1293
1292
|
const aValue = a.value;
|
|
@@ -1452,11 +1451,11 @@ function create$33(context) {
|
|
|
1452
1451
|
}
|
|
1453
1452
|
/**
|
|
1454
1453
|
* Determines whether the given CallExpression can be safely auto-fixed by replacing
|
|
1455
|
-
* the usage of `forwardRef` with passing `ref` as a prop
|
|
1454
|
+
* the usage of `forwardRef` with passing `ref` as a prop
|
|
1456
1455
|
*
|
|
1457
|
-
* @param context - The rule context object
|
|
1458
|
-
* @param node - The CallExpression node to check
|
|
1459
|
-
* @returns True if the call can be auto-fixed, false otherwise
|
|
1456
|
+
* @param context - The rule context object
|
|
1457
|
+
* @param node - The CallExpression node to check
|
|
1458
|
+
* @returns True if the call can be auto-fixed, false otherwise
|
|
1460
1459
|
*/
|
|
1461
1460
|
function canFix$1(context, node) {
|
|
1462
1461
|
const { importSource } = getSettingsFromContext(context);
|
|
@@ -1467,6 +1466,12 @@ function canFix$1(context, node) {
|
|
|
1467
1466
|
default: return false;
|
|
1468
1467
|
}
|
|
1469
1468
|
}
|
|
1469
|
+
/**
|
|
1470
|
+
* Generates the fix for the `forwardRef` call
|
|
1471
|
+
* @param context - The rule context
|
|
1472
|
+
* @param node - The `forwardRef` call expression
|
|
1473
|
+
* @returns A fixer function that applies the changes
|
|
1474
|
+
*/
|
|
1470
1475
|
function getFix$1(context, node) {
|
|
1471
1476
|
return (fixer) => {
|
|
1472
1477
|
const [componentNode] = node.arguments;
|
|
@@ -1478,6 +1483,14 @@ function getFix$1(context, node) {
|
|
|
1478
1483
|
];
|
|
1479
1484
|
};
|
|
1480
1485
|
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Generates fixes for the component's props and ref arguments
|
|
1488
|
+
* @param context - The rule context
|
|
1489
|
+
* @param fixer - The rule fixer
|
|
1490
|
+
* @param node - The function component node
|
|
1491
|
+
* @param typeArguments - The type arguments from the `forwardRef` call
|
|
1492
|
+
* @returns An array of fixes for the component's signature
|
|
1493
|
+
*/
|
|
1481
1494
|
function getComponentPropsFixes(context, fixer, node, typeArguments) {
|
|
1482
1495
|
const getText = (node$1) => context.sourceCode.getText(node$1);
|
|
1483
1496
|
const [arg0, arg1] = node.params;
|
|
@@ -1577,6 +1590,11 @@ function create$31(context) {
|
|
|
1577
1590
|
...compare(version$1, "18.0.0", "<") ? [] : ["string", "falsy string"]
|
|
1578
1591
|
];
|
|
1579
1592
|
const services = ESLintUtils.getParserServices(context, false);
|
|
1593
|
+
/**
|
|
1594
|
+
* Recursively inspects a node to find potential leaked conditional rendering
|
|
1595
|
+
* @param node The AST node to inspect
|
|
1596
|
+
* @returns A report descriptor if a problem is found, otherwise `unit`
|
|
1597
|
+
*/
|
|
1580
1598
|
function getReportDescriptor(node) {
|
|
1581
1599
|
if (node == null) return unit;
|
|
1582
1600
|
if (AST.is(AST_NODE_TYPES.JSXExpressionContainer)(node)) return getReportDescriptor(node.expression);
|
|
@@ -1835,8 +1853,8 @@ var no_misused_capture_owner_stack_default = createRule({
|
|
|
1835
1853
|
},
|
|
1836
1854
|
fixable: "code",
|
|
1837
1855
|
messages: {
|
|
1838
|
-
|
|
1839
|
-
|
|
1856
|
+
missingDevelopmentOnlyCheck: `Don't call 'captureOwnerStack' directly. Use 'if (process.env.NODE_ENV !== "production") {...}' to conditionally access it.`,
|
|
1857
|
+
useNamespaceImport: "Don't use named imports of 'captureOwnerStack' in files that are bundled for development and production. Use a namespace import instead."
|
|
1840
1858
|
},
|
|
1841
1859
|
schema: []
|
|
1842
1860
|
},
|
|
@@ -1977,28 +1995,19 @@ function isInsideJSXAttributeValue(node) {
|
|
|
1977
1995
|
return node.parent.type === AST_NODE_TYPES.JSXAttribute || findParentJsxAttribute(node, (n) => n.value?.type === AST_NODE_TYPES.JSXExpressionContainer) != null;
|
|
1978
1996
|
}
|
|
1979
1997
|
/**
|
|
1980
|
-
*
|
|
1981
|
-
*
|
|
1982
|
-
* class Component extends React.Component {
|
|
1983
|
-
* render() {
|
|
1984
|
-
* class NestedClassComponent extends React.Component {
|
|
1985
|
-
* render() { return <div />; }
|
|
1986
|
-
* }
|
|
1987
|
-
* const nestedFunctionComponent = () => <div />;
|
|
1988
|
-
* }
|
|
1989
|
-
* }
|
|
1990
|
-
* ```
|
|
1998
|
+
* Checks whether a given node is declared inside a class component's render block
|
|
1999
|
+
* Ex: class C extends React.Component { render() { const Nested = () => <div />; } }
|
|
1991
2000
|
* @param node The AST node being checked
|
|
1992
|
-
* @returns `true` if node is inside class component's render block
|
|
2001
|
+
* @returns `true` if the node is inside a class component's render block
|
|
1993
2002
|
*/
|
|
1994
2003
|
function isInsideRenderMethod(node) {
|
|
1995
2004
|
return AST.findParentNode(node, (n) => isRenderMethodLike(n) && isClassComponent(n.parent.parent)) != null;
|
|
1996
2005
|
}
|
|
1997
2006
|
/**
|
|
1998
|
-
* Determines whether inside `createElement`'s props
|
|
2007
|
+
* Determines whether the node is inside `createElement`'s props argument
|
|
1999
2008
|
* @param context The rule context
|
|
2000
2009
|
* @param node The AST node to check
|
|
2001
|
-
* @returns `true` if the node is inside createElement's props
|
|
2010
|
+
* @returns `true` if the node is inside `createElement`'s props
|
|
2002
2011
|
*/
|
|
2003
2012
|
function isInsideCreateElementProps(context, node) {
|
|
2004
2013
|
const call = AST.findParentNode(node, isCreateElementCall(context));
|
|
@@ -2163,12 +2172,12 @@ function create$22(context) {
|
|
|
2163
2172
|
if (!context.sourceCode.text.includes("componentDidMount")) return {};
|
|
2164
2173
|
return { CallExpression(node) {
|
|
2165
2174
|
if (!isThisSetState(node)) return;
|
|
2166
|
-
const
|
|
2167
|
-
const
|
|
2168
|
-
if (
|
|
2169
|
-
const
|
|
2170
|
-
const
|
|
2171
|
-
if (
|
|
2175
|
+
const enclosingClassNode = AST.findParentNode(node, isClassComponent);
|
|
2176
|
+
const enclosingMethodNode = AST.findParentNode(node, (n) => n === enclosingClassNode || isComponentDidMount(n));
|
|
2177
|
+
if (enclosingClassNode == null || enclosingMethodNode == null || enclosingMethodNode === enclosingClassNode) return;
|
|
2178
|
+
const enclosingMethodScope = context.sourceCode.getScope(enclosingMethodNode);
|
|
2179
|
+
const setStateCallParentScope = context.sourceCode.getScope(node).upper;
|
|
2180
|
+
if (enclosingMethodNode.parent === enclosingClassNode.body && setStateCallParentScope === enclosingMethodScope) context.report({
|
|
2172
2181
|
messageId: "noSetStateInComponentDidMount",
|
|
2173
2182
|
node
|
|
2174
2183
|
});
|
|
@@ -2197,12 +2206,12 @@ function create$21(context) {
|
|
|
2197
2206
|
if (!context.sourceCode.text.includes("componentDidUpdate")) return {};
|
|
2198
2207
|
return { CallExpression(node) {
|
|
2199
2208
|
if (!isThisSetState(node)) return;
|
|
2200
|
-
const
|
|
2201
|
-
const
|
|
2202
|
-
if (
|
|
2203
|
-
const
|
|
2204
|
-
const
|
|
2205
|
-
if (
|
|
2209
|
+
const enclosingClassNode = AST.findParentNode(node, isClassComponent);
|
|
2210
|
+
const enclosingMethodNode = AST.findParentNode(node, (n) => n === enclosingClassNode || isComponentDidUpdate(n));
|
|
2211
|
+
if (enclosingClassNode == null || enclosingMethodNode == null || enclosingMethodNode === enclosingClassNode) return;
|
|
2212
|
+
const enclosingMethodScope = context.sourceCode.getScope(enclosingMethodNode);
|
|
2213
|
+
const setStateCallParentScope = context.sourceCode.getScope(node).upper;
|
|
2214
|
+
if (enclosingMethodNode.parent === enclosingClassNode.body && setStateCallParentScope === enclosingMethodScope) context.report({
|
|
2206
2215
|
messageId: "noSetStateInComponentDidUpdate",
|
|
2207
2216
|
node
|
|
2208
2217
|
});
|
|
@@ -2217,7 +2226,7 @@ var no_set_state_in_component_will_update_default = createRule({
|
|
|
2217
2226
|
meta: {
|
|
2218
2227
|
type: "problem",
|
|
2219
2228
|
docs: {
|
|
2220
|
-
description: "
|
|
2229
|
+
description: "Disallow calling `this.setState` in `componentWillUpdate` outside of functions, such as callbacks.",
|
|
2221
2230
|
[Symbol.for("rule_features")]: RULE_FEATURES$19
|
|
2222
2231
|
},
|
|
2223
2232
|
messages: { noSetStateInComponentWillUpdate: "Do not call `this.setState` in `componentWillUpdate` outside of functions, such as callbacks." },
|
|
@@ -2231,12 +2240,12 @@ function create$20(context) {
|
|
|
2231
2240
|
if (!context.sourceCode.text.includes("componentWillUpdate")) return {};
|
|
2232
2241
|
return { CallExpression(node) {
|
|
2233
2242
|
if (!isThisSetState(node)) return;
|
|
2234
|
-
const
|
|
2235
|
-
const
|
|
2236
|
-
if (
|
|
2237
|
-
const
|
|
2238
|
-
const
|
|
2239
|
-
if (
|
|
2243
|
+
const enclosingClassNode = AST.findParentNode(node, isClassComponent);
|
|
2244
|
+
const enclosingMethodNode = AST.findParentNode(node, (n) => n === enclosingClassNode || isComponentWillUpdate(n));
|
|
2245
|
+
if (enclosingClassNode == null || enclosingMethodNode == null || enclosingMethodNode === enclosingClassNode) return;
|
|
2246
|
+
const enclosingMethodScope = context.sourceCode.getScope(enclosingMethodNode);
|
|
2247
|
+
const setStateCallParentScope = context.sourceCode.getScope(node).upper;
|
|
2248
|
+
if (enclosingMethodNode.parent === enclosingClassNode.body && setStateCallParentScope === enclosingMethodScope) context.report({
|
|
2240
2249
|
messageId: "noSetStateInComponentWillUpdate",
|
|
2241
2250
|
node
|
|
2242
2251
|
});
|
|
@@ -2275,21 +2284,27 @@ function create$19(context) {
|
|
|
2275
2284
|
"ClassBody:exit": onClassBodyExit,
|
|
2276
2285
|
JSXAttribute(node) {
|
|
2277
2286
|
if (node.name.name !== "ref") return;
|
|
2278
|
-
const
|
|
2279
|
-
if (
|
|
2287
|
+
const refName = getJsxAttributeValueText(context, node.value);
|
|
2288
|
+
if (refName == null) return;
|
|
2280
2289
|
context.report({
|
|
2281
2290
|
messageId: "noStringRefs",
|
|
2282
2291
|
node,
|
|
2283
2292
|
fix(fixer) {
|
|
2284
2293
|
if (node.value == null) return null;
|
|
2285
2294
|
if (!state.isWithinClassComponent) return null;
|
|
2286
|
-
return fixer.replaceText(node.value, `{(ref) => { this.refs[${
|
|
2295
|
+
return fixer.replaceText(node.value, `{(ref) => { this.refs[${refName}] = ref; }}`);
|
|
2287
2296
|
}
|
|
2288
2297
|
});
|
|
2289
2298
|
}
|
|
2290
2299
|
};
|
|
2291
2300
|
}
|
|
2292
|
-
|
|
2301
|
+
/**
|
|
2302
|
+
* Extracts the text content from a JSX attribute's value
|
|
2303
|
+
* @param context - The rule context
|
|
2304
|
+
* @param node - The JSX attribute value node
|
|
2305
|
+
* @returns The text of the attribute value, or null if not a string-like value
|
|
2306
|
+
*/
|
|
2307
|
+
function getJsxAttributeValueText(context, node) {
|
|
2293
2308
|
if (node == null) return null;
|
|
2294
2309
|
switch (true) {
|
|
2295
2310
|
case node.type === AST_NODE_TYPES.Literal && typeof node.value === "string": return context.sourceCode.getText(node);
|
|
@@ -2336,6 +2351,11 @@ function create$18(context) {
|
|
|
2336
2351
|
});
|
|
2337
2352
|
} };
|
|
2338
2353
|
}
|
|
2354
|
+
/**
|
|
2355
|
+
* Checks if a node is a callback function passed to an array's `.map()` method
|
|
2356
|
+
* @param node The node to check
|
|
2357
|
+
* @returns `true` if the node is a map callback, `false` otherwise
|
|
2358
|
+
*/
|
|
2339
2359
|
function isMapCallback(node) {
|
|
2340
2360
|
if (node.parent == null) return false;
|
|
2341
2361
|
if (!AST.isArrayMapCall(node.parent)) return false;
|
|
@@ -2781,7 +2801,7 @@ function create$9(context) {
|
|
|
2781
2801
|
for (const def of defs) {
|
|
2782
2802
|
const methodName = AST.getPropertyName(def);
|
|
2783
2803
|
if (methodName == null) continue;
|
|
2784
|
-
if (usages?.has(methodName) || LIFECYCLE_METHODS.has(methodName)) continue;
|
|
2804
|
+
if ((usages?.has(methodName) ?? false) || LIFECYCLE_METHODS.has(methodName)) continue;
|
|
2785
2805
|
context.report({
|
|
2786
2806
|
messageId: "noUnusedClassComponentMembers",
|
|
2787
2807
|
node: def,
|
|
@@ -3308,9 +3328,6 @@ function checkNode(context, node, allowExpressions) {
|
|
|
3308
3328
|
fix: getFix(context, node)
|
|
3309
3329
|
});
|
|
3310
3330
|
}
|
|
3311
|
-
/**
|
|
3312
|
-
* Generate fix for removing useless fragment
|
|
3313
|
-
*/
|
|
3314
3331
|
function getFix(context, node) {
|
|
3315
3332
|
if (!canFix(context, node)) return null;
|
|
3316
3333
|
return (fixer) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-x",
|
|
3
|
-
"version": "2.0.5-next.
|
|
3
|
+
"version": "2.0.5-next.5",
|
|
4
4
|
"description": "A set of composable ESLint rules for for libraries and frameworks that use React as a UI runtime.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -43,16 +43,16 @@
|
|
|
43
43
|
"string-ts": "^2.2.1",
|
|
44
44
|
"ts-api-utils": "^2.1.0",
|
|
45
45
|
"ts-pattern": "^5.8.0",
|
|
46
|
-
"@eslint-react/ast": "2.0.5-next.
|
|
47
|
-
"@eslint-react/eff": "2.0.5-next.
|
|
48
|
-
"@eslint-react/kit": "2.0.5-next.
|
|
49
|
-
"@eslint-react/
|
|
50
|
-
"@eslint-react/
|
|
51
|
-
"@eslint-react/
|
|
46
|
+
"@eslint-react/ast": "2.0.5-next.5",
|
|
47
|
+
"@eslint-react/eff": "2.0.5-next.5",
|
|
48
|
+
"@eslint-react/kit": "2.0.5-next.5",
|
|
49
|
+
"@eslint-react/var": "2.0.5-next.5",
|
|
50
|
+
"@eslint-react/shared": "2.0.5-next.5",
|
|
51
|
+
"@eslint-react/core": "2.0.5-next.5"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@types/react": "^19.
|
|
55
|
-
"@types/react-dom": "^19.
|
|
54
|
+
"@types/react": "^19.2.0",
|
|
55
|
+
"@types/react-dom": "^19.2.0",
|
|
56
56
|
"tsdown": "^0.15.6",
|
|
57
57
|
"@local/configs": "0.0.0"
|
|
58
58
|
},
|