@eslint-react/jsx 5.8.5 → 5.8.7-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.ts +23 -9
- package/dist/index.js +64 -13
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -215,10 +215,18 @@ declare function getAttributeValue(context: RuleContext, element: TSESTree.JSXEl
|
|
|
215
215
|
/**
|
|
216
216
|
* Get the **meaningful** children of a JSX element or fragment.
|
|
217
217
|
*
|
|
218
|
-
* Filters out
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
218
|
+
* Filters out nodes that React will not render into the DOM:
|
|
219
|
+
*
|
|
220
|
+
* 1. "Padding spaces" — `JSXText` nodes that consist entirely of whitespace
|
|
221
|
+
* and contain at least one newline. These are code-formatting artefacts
|
|
222
|
+
* (indentation between tags). While React's client renderer preserves them
|
|
223
|
+
* as text nodes, browser HTML parsers may discard them during hydration,
|
|
224
|
+
* causing hydration mismatches.
|
|
225
|
+
*
|
|
226
|
+
* 2. Empty string expressions — `JSXExpressionContainer` nodes whose expression
|
|
227
|
+
* is a string literal with value `""`. React's reconciler and SSR renderer
|
|
228
|
+
* explicitly skip empty strings, producing no DOM node
|
|
229
|
+
* (see ReactChildFiber.js and ReactFizzConfigDOM.js).
|
|
222
230
|
*
|
|
223
231
|
* @param element - A `JSXElement` or `JSXFragment` node.
|
|
224
232
|
* @returns An array of children nodes that contribute to rendered output.
|
|
@@ -320,12 +328,17 @@ declare function hasAttribute(context: RuleContext, element: TSESTree.JSXElement
|
|
|
320
328
|
//#region src/has-children.d.ts
|
|
321
329
|
/**
|
|
322
330
|
* Check whether a JSX element (or fragment) has **meaningful** children —
|
|
323
|
-
* that is, at least one child that is not purely whitespace text
|
|
331
|
+
* that is, at least one child that is not purely whitespace text or an empty
|
|
332
|
+
* string expression.
|
|
333
|
+
*
|
|
334
|
+
* A `JSXText` child whose `raw` content is empty after trimming is considered
|
|
335
|
+
* non-meaningful because it is typically a code-formatting artefact
|
|
336
|
+
* (indentation between tags). While React's client renderer preserves these
|
|
337
|
+
* nodes as text nodes, they rarely represent intentionally rendered content.
|
|
324
338
|
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
* do not produce visible output.
|
|
339
|
+
* An empty string expression (`children={""}`) is also considered
|
|
340
|
+
* non-meaningful because React's reconciler and SSR renderer explicitly skip
|
|
341
|
+
* empty strings, producing no DOM node.
|
|
329
342
|
*
|
|
330
343
|
* @param element - A `JSXElement` or `JSXFragment` node.
|
|
331
344
|
* @returns `true` when the element has at least one meaningful child.
|
|
@@ -340,6 +353,7 @@ declare function hasAttribute(context: RuleContext, element: TSESTree.JSXElement
|
|
|
340
353
|
* // <div> -> false (whitespace-only, with newlines)
|
|
341
354
|
* // </div>
|
|
342
355
|
* // <div></div> -> false (no children at all)
|
|
356
|
+
* // <div>{""}</div> -> false (empty string expression)
|
|
343
357
|
*
|
|
344
358
|
* if (hasChildren(node)) {
|
|
345
359
|
* // element renders visible content
|
package/dist/index.js
CHANGED
|
@@ -297,10 +297,18 @@ function getAttributeValue(context, element, name) {
|
|
|
297
297
|
/**
|
|
298
298
|
* Get the **meaningful** children of a JSX element or fragment.
|
|
299
299
|
*
|
|
300
|
-
* Filters out
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
300
|
+
* Filters out nodes that React will not render into the DOM:
|
|
301
|
+
*
|
|
302
|
+
* 1. "Padding spaces" — `JSXText` nodes that consist entirely of whitespace
|
|
303
|
+
* and contain at least one newline. These are code-formatting artefacts
|
|
304
|
+
* (indentation between tags). While React's client renderer preserves them
|
|
305
|
+
* as text nodes, browser HTML parsers may discard them during hydration,
|
|
306
|
+
* causing hydration mismatches.
|
|
307
|
+
*
|
|
308
|
+
* 2. Empty string expressions — `JSXExpressionContainer` nodes whose expression
|
|
309
|
+
* is a string literal with value `""`. React's reconciler and SSR renderer
|
|
310
|
+
* explicitly skip empty strings, producing no DOM node
|
|
311
|
+
* (see ReactChildFiber.js and ReactFizzConfigDOM.js).
|
|
304
312
|
*
|
|
305
313
|
* @param element - A `JSXElement` or `JSXFragment` node.
|
|
306
314
|
* @returns An array of children nodes that contribute to rendered output.
|
|
@@ -320,14 +328,19 @@ function getAttributeValue(context, element, name) {
|
|
|
320
328
|
* ```
|
|
321
329
|
*/
|
|
322
330
|
function getChildren(element) {
|
|
323
|
-
return element.children.filter((child) =>
|
|
331
|
+
return element.children.filter((child) => {
|
|
332
|
+
if (isPaddingSpaces(child)) return false;
|
|
333
|
+
if (isEmptyStringExpression$1(child)) return false;
|
|
334
|
+
return true;
|
|
335
|
+
});
|
|
324
336
|
}
|
|
325
337
|
/**
|
|
326
338
|
* A `JSXText` node is considered **padding spaces** when it is purely
|
|
327
339
|
* whitespace *and* contains at least one newline character.
|
|
328
340
|
*
|
|
329
|
-
* These nodes are formatting artefacts (indentation between JSX tags)
|
|
330
|
-
* React
|
|
341
|
+
* These nodes are code-formatting artefacts (indentation between JSX tags).
|
|
342
|
+
* While React's client renderer preserves them as text nodes, browser HTML
|
|
343
|
+
* parsers may discard them during hydration, leading to hydration mismatches.
|
|
331
344
|
*
|
|
332
345
|
* @param node The JSX child node to check.
|
|
333
346
|
* @internal
|
|
@@ -336,6 +349,24 @@ function isPaddingSpaces(node) {
|
|
|
336
349
|
if (node.type !== AST_NODE_TYPES.JSXText) return false;
|
|
337
350
|
return node.raw.trim() === "" && node.raw.includes("\n");
|
|
338
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* A `JSXExpressionContainer` node is considered an empty string expression
|
|
354
|
+
* when it wraps a string literal with value `""`.
|
|
355
|
+
*
|
|
356
|
+
* React's reconciler explicitly ignores empty strings
|
|
357
|
+
* (`typeof newChild === 'string' && newChild !== ''` in ReactChildFiber.js),
|
|
358
|
+
* and the SSR renderer skips them as well (`if (text === '') { return; }`
|
|
359
|
+
* in ReactFizzConfigDOM.js). They produce no DOM node.
|
|
360
|
+
*
|
|
361
|
+
* @param node The JSX child node to check.
|
|
362
|
+
* @internal
|
|
363
|
+
*/
|
|
364
|
+
function isEmptyStringExpression$1(node) {
|
|
365
|
+
if (node.type !== AST_NODE_TYPES.JSXExpressionContainer) return false;
|
|
366
|
+
const expr = node.expression;
|
|
367
|
+
if (expr.type !== AST_NODE_TYPES.Literal) return false;
|
|
368
|
+
return expr.value === "";
|
|
369
|
+
}
|
|
339
370
|
|
|
340
371
|
//#endregion
|
|
341
372
|
//#region src/get-element-type.ts
|
|
@@ -436,12 +467,17 @@ function hasAttribute(context, element, name) {
|
|
|
436
467
|
//#region src/has-children.ts
|
|
437
468
|
/**
|
|
438
469
|
* Check whether a JSX element (or fragment) has **meaningful** children —
|
|
439
|
-
* that is, at least one child that is not purely whitespace text
|
|
470
|
+
* that is, at least one child that is not purely whitespace text or an empty
|
|
471
|
+
* string expression.
|
|
472
|
+
*
|
|
473
|
+
* A `JSXText` child whose `raw` content is empty after trimming is considered
|
|
474
|
+
* non-meaningful because it is typically a code-formatting artefact
|
|
475
|
+
* (indentation between tags). While React's client renderer preserves these
|
|
476
|
+
* nodes as text nodes, they rarely represent intentionally rendered content.
|
|
440
477
|
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
* do not produce visible output.
|
|
478
|
+
* An empty string expression (`children={""}`) is also considered
|
|
479
|
+
* non-meaningful because React's reconciler and SSR renderer explicitly skip
|
|
480
|
+
* empty strings, producing no DOM node.
|
|
445
481
|
*
|
|
446
482
|
* @param element - A `JSXElement` or `JSXFragment` node.
|
|
447
483
|
* @returns `true` when the element has at least one meaningful child.
|
|
@@ -456,6 +492,7 @@ function hasAttribute(context, element, name) {
|
|
|
456
492
|
* // <div> -> false (whitespace-only, with newlines)
|
|
457
493
|
* // </div>
|
|
458
494
|
* // <div></div> -> false (no children at all)
|
|
495
|
+
* // <div>{""}</div> -> false (empty string expression)
|
|
459
496
|
*
|
|
460
497
|
* if (hasChildren(node)) {
|
|
461
498
|
* // element renders visible content
|
|
@@ -464,7 +501,7 @@ function hasAttribute(context, element, name) {
|
|
|
464
501
|
*/
|
|
465
502
|
function hasChildren(element) {
|
|
466
503
|
if (element.children.length === 0) return false;
|
|
467
|
-
return !element.children.every((child) => isWhitespaceText$1(child));
|
|
504
|
+
return !element.children.every((child) => isWhitespaceText$1(child) || isEmptyStringExpression(child));
|
|
468
505
|
}
|
|
469
506
|
/**
|
|
470
507
|
* Whether a JSX child node is a whitespace-only `JSXText` node.
|
|
@@ -478,6 +515,20 @@ function isWhitespaceText$1(node) {
|
|
|
478
515
|
if (node.type !== AST_NODE_TYPES.JSXText) return false;
|
|
479
516
|
return node.raw.trim() === "";
|
|
480
517
|
}
|
|
518
|
+
/**
|
|
519
|
+
* Whether a JSX child node is an empty string expression (`{""}`).
|
|
520
|
+
*
|
|
521
|
+
* React's reconciler and SSR renderer skip empty strings, producing no DOM
|
|
522
|
+
* node. These expressions are therefore considered non-meaningful children.
|
|
523
|
+
*
|
|
524
|
+
* @param node The JSX child node to check.
|
|
525
|
+
*/
|
|
526
|
+
function isEmptyStringExpression(node) {
|
|
527
|
+
if (node.type !== AST_NODE_TYPES.JSXExpressionContainer) return false;
|
|
528
|
+
const expr = node.expression;
|
|
529
|
+
if (expr.type !== AST_NODE_TYPES.Literal) return false;
|
|
530
|
+
return expr.value === "";
|
|
531
|
+
}
|
|
481
532
|
|
|
482
533
|
//#endregion
|
|
483
534
|
//#region src/has-every-attribute.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/jsx",
|
|
3
|
-
"version": "5.8.
|
|
3
|
+
"version": "5.8.7-beta.0",
|
|
4
4
|
"description": "ESLint React's TSESTree JSX utility module for static analysis of JSX patterns.",
|
|
5
5
|
"homepage": "https://github.com/Rel1cx/eslint-react",
|
|
6
6
|
"bugs": {
|
|
@@ -29,18 +29,18 @@
|
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@typescript-eslint/types": "^8.
|
|
33
|
-
"@typescript-eslint/utils": "^8.
|
|
32
|
+
"@typescript-eslint/types": "^8.60.0",
|
|
33
|
+
"@typescript-eslint/utils": "^8.60.0",
|
|
34
34
|
"ts-pattern": "^5.9.0",
|
|
35
|
-
"@eslint-react/ast": "5.8.
|
|
36
|
-
"@eslint-react/eslint": "5.8.
|
|
37
|
-
"@eslint-react/
|
|
38
|
-
"@eslint-react/
|
|
35
|
+
"@eslint-react/ast": "5.8.7-beta.0",
|
|
36
|
+
"@eslint-react/eslint": "5.8.7-beta.0",
|
|
37
|
+
"@eslint-react/var": "5.8.7-beta.0",
|
|
38
|
+
"@eslint-react/shared": "5.8.7-beta.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"eslint": "^10.4.0",
|
|
42
42
|
"tsdown": "^0.22.0",
|
|
43
|
-
"typescript": "
|
|
43
|
+
"typescript": "5.9.3",
|
|
44
44
|
"@local/configs": "0.0.0",
|
|
45
45
|
"@local/eff": "3.0.0-beta.72"
|
|
46
46
|
},
|