eslint-plugin-react-dom 2.0.5-next.2 → 2.0.5-next.4
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 +64 -57
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_ESLINT_REACT_SETTINGS, getConfigAdapters, getDocsUrl, getSettingsFromContext } from "@eslint-react/shared";
|
|
2
|
-
import { getJsxAttribute, getJsxElementType,
|
|
2
|
+
import { getJsxAttribute, getJsxElementType, isJsxHostElement, isJsxText, resolveJsxAttributeValue } from "@eslint-react/core";
|
|
3
3
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
4
4
|
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
5
5
|
import { compare } from "compare-versions";
|
|
@@ -47,7 +47,7 @@ const settings = { "react-x": DEFAULT_ESLINT_REACT_SETTINGS };
|
|
|
47
47
|
//#endregion
|
|
48
48
|
//#region package.json
|
|
49
49
|
var name = "eslint-plugin-react-dom";
|
|
50
|
-
var version = "2.0.5-next.
|
|
50
|
+
var version = "2.0.5-next.4";
|
|
51
51
|
|
|
52
52
|
//#endregion
|
|
53
53
|
//#region src/utils/create-jsx-element-resolver.ts
|
|
@@ -71,7 +71,7 @@ function createJsxElementResolver(context) {
|
|
|
71
71
|
jsxElementType: elementName
|
|
72
72
|
};
|
|
73
73
|
if (elementName === elementName.toLowerCase() || polymorphicPropName == null) return result;
|
|
74
|
-
const polymorphicProp = getJsxAttribute(context, node
|
|
74
|
+
const polymorphicProp = getJsxAttribute(context, node)(polymorphicPropName);
|
|
75
75
|
if (polymorphicProp != null) {
|
|
76
76
|
const staticValue = resolveJsxAttributeValue(context, polymorphicProp).toStatic(polymorphicPropName);
|
|
77
77
|
if (typeof staticValue === "string") return {
|
|
@@ -109,11 +109,11 @@ var no_dangerously_set_innerhtml_default = createRule({
|
|
|
109
109
|
function create$17(context) {
|
|
110
110
|
if (!context.sourceCode.text.includes(DSIH$1)) return {};
|
|
111
111
|
return { JSXElement(node) {
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
112
|
+
const dsihProp = getJsxAttribute(context, node)(DSIH$1);
|
|
113
|
+
if (dsihProp == null) return;
|
|
114
114
|
context.report({
|
|
115
115
|
messageId: "noDangerouslySetInnerhtml",
|
|
116
|
-
node:
|
|
116
|
+
node: dsihProp
|
|
117
117
|
});
|
|
118
118
|
} };
|
|
119
119
|
}
|
|
@@ -138,9 +138,9 @@ var no_dangerously_set_innerhtml_with_children_default = createRule({
|
|
|
138
138
|
});
|
|
139
139
|
const DSIH = "dangerouslySetInnerHTML";
|
|
140
140
|
/**
|
|
141
|
-
* Checks if a JSX child node is considered significant (i.e., not just whitespace for formatting)
|
|
142
|
-
* @param node The JSX child node to check
|
|
143
|
-
* @returns `true` if the node is significant, `false` otherwise
|
|
141
|
+
* Checks if a JSX child node is considered significant (i.e., not just whitespace for formatting)
|
|
142
|
+
* @param node The JSX child node to check
|
|
143
|
+
* @returns `true` if the node is significant, `false` otherwise
|
|
144
144
|
*/
|
|
145
145
|
function isSignificantChildren(node) {
|
|
146
146
|
if (!isJsxText(node)) return true;
|
|
@@ -149,13 +149,13 @@ function isSignificantChildren(node) {
|
|
|
149
149
|
function create$16(context) {
|
|
150
150
|
if (!context.sourceCode.text.includes(DSIH)) return {};
|
|
151
151
|
return { JSXElement(node) {
|
|
152
|
-
const findJsxAttribute = getJsxAttribute(context, node
|
|
152
|
+
const findJsxAttribute = getJsxAttribute(context, node);
|
|
153
153
|
if (findJsxAttribute(DSIH) == null) return;
|
|
154
|
-
const
|
|
155
|
-
if (
|
|
154
|
+
const childrenPropOrNode = findJsxAttribute("children") ?? node.children.find(isSignificantChildren);
|
|
155
|
+
if (childrenPropOrNode == null) return;
|
|
156
156
|
context.report({
|
|
157
157
|
messageId: "noDangerouslySetInnerhtmlWithChildren",
|
|
158
|
-
node:
|
|
158
|
+
node: childrenPropOrNode
|
|
159
159
|
});
|
|
160
160
|
} };
|
|
161
161
|
}
|
|
@@ -341,7 +341,7 @@ function create$12(context) {
|
|
|
341
341
|
const resolver = createJsxElementResolver(context);
|
|
342
342
|
return { JSXElement(node) {
|
|
343
343
|
if (resolver.resolve(node).domElementType !== "button") return;
|
|
344
|
-
if (getJsxAttribute(context, node
|
|
344
|
+
if (getJsxAttribute(context, node)("type") != null) return;
|
|
345
345
|
context.report({
|
|
346
346
|
messageId: "noMissingButtonType",
|
|
347
347
|
node: node.openingElement,
|
|
@@ -362,14 +362,14 @@ var no_missing_iframe_sandbox_default = createRule({
|
|
|
362
362
|
meta: {
|
|
363
363
|
type: "problem",
|
|
364
364
|
docs: {
|
|
365
|
-
description: "Enforces explicit `sandbox`
|
|
365
|
+
description: "Enforces explicit `sandbox` prop for `iframe` elements.",
|
|
366
366
|
[Symbol.for("rule_features")]: RULE_FEATURES$10
|
|
367
367
|
},
|
|
368
368
|
fixable: "code",
|
|
369
369
|
hasSuggestions: true,
|
|
370
370
|
messages: {
|
|
371
|
-
addIframeSandbox: "Add 'sandbox'
|
|
372
|
-
noMissingIframeSandbox: "Add missing 'sandbox'
|
|
371
|
+
addIframeSandbox: "Add 'sandbox' prop with value '{{value}}'.",
|
|
372
|
+
noMissingIframeSandbox: "Add missing 'sandbox' prop on 'iframe' component."
|
|
373
373
|
},
|
|
374
374
|
schema: []
|
|
375
375
|
},
|
|
@@ -382,8 +382,8 @@ function create$11(context) {
|
|
|
382
382
|
return { JSXElement(node) {
|
|
383
383
|
const { domElementType } = resolver.resolve(node);
|
|
384
384
|
if (domElementType !== "iframe") return;
|
|
385
|
-
const
|
|
386
|
-
if (
|
|
385
|
+
const sandboxProp = getJsxAttribute(context, node)("sandbox");
|
|
386
|
+
if (sandboxProp == null) {
|
|
387
387
|
context.report({
|
|
388
388
|
messageId: "noMissingIframeSandbox",
|
|
389
389
|
node: node.openingElement,
|
|
@@ -397,17 +397,17 @@ function create$11(context) {
|
|
|
397
397
|
});
|
|
398
398
|
return;
|
|
399
399
|
}
|
|
400
|
-
const sandboxValue = resolveJsxAttributeValue(context,
|
|
400
|
+
const sandboxValue = resolveJsxAttributeValue(context, sandboxProp);
|
|
401
401
|
if (typeof sandboxValue.toStatic("sandbox") === "string") return;
|
|
402
402
|
context.report({
|
|
403
403
|
messageId: "noMissingIframeSandbox",
|
|
404
|
-
node: sandboxValue.node ??
|
|
404
|
+
node: sandboxValue.node ?? sandboxProp,
|
|
405
405
|
suggest: [{
|
|
406
406
|
messageId: "addIframeSandbox",
|
|
407
407
|
data: { value: "" },
|
|
408
408
|
fix(fixer) {
|
|
409
409
|
if (sandboxValue.kind.startsWith("spread")) return null;
|
|
410
|
-
return fixer.replaceText(
|
|
410
|
+
return fixer.replaceText(sandboxProp, `sandbox=""`);
|
|
411
411
|
}
|
|
412
412
|
}]
|
|
413
413
|
});
|
|
@@ -504,6 +504,12 @@ function create$9(context) {
|
|
|
504
504
|
}
|
|
505
505
|
};
|
|
506
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Provides a fixer function to replace `render(app, container)` with `createRoot(container).render(app)`
|
|
509
|
+
* @param context The rule context
|
|
510
|
+
* @param node The `CallExpression` node to fix
|
|
511
|
+
* @returns A fixer function or null if the fix cannot be applied
|
|
512
|
+
*/
|
|
507
513
|
function getFix$1(context, node) {
|
|
508
514
|
const getText$1 = (n) => context.sourceCode.getText(n);
|
|
509
515
|
return (fixer) => {
|
|
@@ -625,12 +631,12 @@ var no_string_style_prop_default = createRule({
|
|
|
625
631
|
function create$6(context) {
|
|
626
632
|
return { JSXElement(node) {
|
|
627
633
|
if (!isJsxHostElement(context, node)) return;
|
|
628
|
-
const
|
|
629
|
-
if (
|
|
630
|
-
const styleValue = resolveJsxAttributeValue(context,
|
|
634
|
+
const styleProp = getJsxAttribute(context, node)("style");
|
|
635
|
+
if (styleProp == null) return;
|
|
636
|
+
const styleValue = resolveJsxAttributeValue(context, styleProp);
|
|
631
637
|
if (typeof styleValue.toStatic() === "string") context.report({
|
|
632
638
|
messageId: "noStringStyleProp",
|
|
633
|
-
node: styleValue.node ??
|
|
639
|
+
node: styleValue.node ?? styleProp
|
|
634
640
|
});
|
|
635
641
|
} };
|
|
636
642
|
}
|
|
@@ -1775,9 +1781,11 @@ const RULE_NAME$4 = "no-unsafe-iframe-sandbox";
|
|
|
1775
1781
|
const RULE_FEATURES$4 = [];
|
|
1776
1782
|
const UNSAFE_SANDBOX_VALUES = ["allow-scripts", "allow-same-origin"];
|
|
1777
1783
|
/**
|
|
1778
|
-
* Checks if the sandbox attribute value contains an unsafe combination
|
|
1779
|
-
*
|
|
1780
|
-
*
|
|
1784
|
+
* Checks if the sandbox attribute value contains an unsafe combination
|
|
1785
|
+
* An iframe with both "allow-scripts" and "allow-same-origin" can remove its sandbox attribute,
|
|
1786
|
+
* making it as insecure as an iframe without any sandboxing
|
|
1787
|
+
* @param value The value of the sandbox attribute
|
|
1788
|
+
* @returns `true` if the value is a string and contains an unsafe combination, `false` otherwise
|
|
1781
1789
|
*/
|
|
1782
1790
|
function isUnsafeSandboxCombination(value) {
|
|
1783
1791
|
if (typeof value !== "string") return false;
|
|
@@ -1801,13 +1809,13 @@ function create$4(context) {
|
|
|
1801
1809
|
const resolver = createJsxElementResolver(context);
|
|
1802
1810
|
return { JSXElement(node) {
|
|
1803
1811
|
if (resolver.resolve(node).domElementType !== "iframe") return;
|
|
1804
|
-
const
|
|
1805
|
-
if (
|
|
1806
|
-
const sandboxValue = resolveJsxAttributeValue(context,
|
|
1812
|
+
const sandboxProp = getJsxAttribute(context, node)("sandbox");
|
|
1813
|
+
if (sandboxProp == null) return;
|
|
1814
|
+
const sandboxValue = resolveJsxAttributeValue(context, sandboxProp);
|
|
1807
1815
|
const sandboxValueStatic = sandboxValue.toStatic("sandbox");
|
|
1808
1816
|
if (isUnsafeSandboxCombination(sandboxValueStatic)) context.report({
|
|
1809
1817
|
messageId: "noUnsafeIframeSandbox",
|
|
1810
|
-
node: sandboxValue.node ??
|
|
1818
|
+
node: sandboxValue.node ?? sandboxProp
|
|
1811
1819
|
});
|
|
1812
1820
|
} };
|
|
1813
1821
|
}
|
|
@@ -1827,9 +1835,9 @@ function isExternalLinkLike(value) {
|
|
|
1827
1835
|
return value.startsWith("https://") || /^(?:\w+:|\/\/)/u.test(value);
|
|
1828
1836
|
}
|
|
1829
1837
|
/**
|
|
1830
|
-
* Checks if a rel
|
|
1838
|
+
* Checks if a rel prop value contains the necessary security attributes.
|
|
1831
1839
|
* At minimum, it should contain "noreferrer".
|
|
1832
|
-
* @param value - The rel
|
|
1840
|
+
* @param value - The rel prop value to check
|
|
1833
1841
|
* @returns Whether the rel value is considered secure
|
|
1834
1842
|
*/
|
|
1835
1843
|
function isSafeRel(value) {
|
|
@@ -1860,16 +1868,16 @@ function create$3(context) {
|
|
|
1860
1868
|
return { JSXElement(node) {
|
|
1861
1869
|
const { domElementType } = resolver.resolve(node);
|
|
1862
1870
|
if (domElementType !== "a") return;
|
|
1863
|
-
const findAttribute = getJsxAttribute(context, node
|
|
1864
|
-
const
|
|
1865
|
-
if (
|
|
1866
|
-
if (resolveJsxAttributeValue(context,
|
|
1867
|
-
const
|
|
1868
|
-
if (
|
|
1869
|
-
const
|
|
1870
|
-
if (!isExternalLinkLike(
|
|
1871
|
-
const
|
|
1872
|
-
if (
|
|
1871
|
+
const findAttribute = getJsxAttribute(context, node);
|
|
1872
|
+
const targetProp = findAttribute("target");
|
|
1873
|
+
if (targetProp == null) return;
|
|
1874
|
+
if (resolveJsxAttributeValue(context, targetProp).toStatic("target") !== "_blank") return;
|
|
1875
|
+
const hrefProp = findAttribute("href");
|
|
1876
|
+
if (hrefProp == null) return;
|
|
1877
|
+
const hrefValue = resolveJsxAttributeValue(context, hrefProp).toStatic("href");
|
|
1878
|
+
if (!isExternalLinkLike(hrefValue)) return;
|
|
1879
|
+
const relProp = findAttribute("rel");
|
|
1880
|
+
if (relProp == null) {
|
|
1873
1881
|
context.report({
|
|
1874
1882
|
messageId: "noUnsafeTargetBlank",
|
|
1875
1883
|
node: node.openingElement,
|
|
@@ -1882,15 +1890,15 @@ function create$3(context) {
|
|
|
1882
1890
|
});
|
|
1883
1891
|
return;
|
|
1884
1892
|
}
|
|
1885
|
-
const
|
|
1886
|
-
if (isSafeRel(
|
|
1893
|
+
const relValue = resolveJsxAttributeValue(context, relProp).toStatic("rel");
|
|
1894
|
+
if (isSafeRel(relValue)) return;
|
|
1887
1895
|
context.report({
|
|
1888
1896
|
messageId: "noUnsafeTargetBlank",
|
|
1889
|
-
node:
|
|
1897
|
+
node: relProp,
|
|
1890
1898
|
suggest: [{
|
|
1891
1899
|
messageId: "addRelNoreferrerNoopener",
|
|
1892
1900
|
fix(fixer) {
|
|
1893
|
-
return fixer.replaceText(
|
|
1901
|
+
return fixer.replaceText(relProp, `rel="noreferrer noopener"`);
|
|
1894
1902
|
}
|
|
1895
1903
|
}]
|
|
1896
1904
|
});
|
|
@@ -1993,7 +2001,7 @@ var no_void_elements_with_children_default = createRule({
|
|
|
1993
2001
|
description: "Disallow `children` in void DOM elements.",
|
|
1994
2002
|
[Symbol.for("rule_features")]: RULE_FEATURES$1
|
|
1995
2003
|
},
|
|
1996
|
-
messages: { noVoidElementsWithChildren: "'{{
|
|
2004
|
+
messages: { noVoidElementsWithChildren: "'{{elementType}}' is a void element tag and must not have children." },
|
|
1997
2005
|
schema: []
|
|
1998
2006
|
},
|
|
1999
2007
|
name: RULE_NAME$1,
|
|
@@ -2003,16 +2011,15 @@ var no_void_elements_with_children_default = createRule({
|
|
|
2003
2011
|
function create$1(context) {
|
|
2004
2012
|
const resolver = createJsxElementResolver(context);
|
|
2005
2013
|
return { JSXElement(node) {
|
|
2006
|
-
const { domElementType
|
|
2007
|
-
if (!voidElements.has(
|
|
2008
|
-
const
|
|
2009
|
-
const
|
|
2010
|
-
const
|
|
2011
|
-
const hasDangerouslySetInnerHTML = hasJsxAttribute(context, "dangerouslySetInnerHTML", attributes, initialScope);
|
|
2014
|
+
const { domElementType } = resolver.resolve(node);
|
|
2015
|
+
if (!voidElements.has(domElementType)) return;
|
|
2016
|
+
const findJsxAttribute = getJsxAttribute(context, node);
|
|
2017
|
+
const hasChildrenProp = findJsxAttribute("children") != null;
|
|
2018
|
+
const hasDangerouslySetInnerHTML = findJsxAttribute("dangerouslySetInnerHTML") != null;
|
|
2012
2019
|
if (node.children.length > 0 || hasChildrenProp || hasDangerouslySetInnerHTML) context.report({
|
|
2013
2020
|
messageId: "noVoidElementsWithChildren",
|
|
2014
2021
|
node,
|
|
2015
|
-
data: {
|
|
2022
|
+
data: { elementType: domElementType }
|
|
2016
2023
|
});
|
|
2017
2024
|
} };
|
|
2018
2025
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-react-dom",
|
|
3
|
-
"version": "2.0.5-next.
|
|
3
|
+
"version": "2.0.5-next.4",
|
|
4
4
|
"description": "ESLint React's ESLint plugin for React DOM related rules.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
"compare-versions": "^6.1.1",
|
|
42
42
|
"string-ts": "^2.2.1",
|
|
43
43
|
"ts-pattern": "^5.8.0",
|
|
44
|
-
"@eslint-react/
|
|
45
|
-
"@eslint-react/
|
|
46
|
-
"@eslint-react/
|
|
47
|
-
"@eslint-react/
|
|
48
|
-
"@eslint-react/
|
|
49
|
-
"@eslint-react/
|
|
44
|
+
"@eslint-react/ast": "2.0.5-next.4",
|
|
45
|
+
"@eslint-react/core": "2.0.5-next.4",
|
|
46
|
+
"@eslint-react/kit": "2.0.5-next.4",
|
|
47
|
+
"@eslint-react/eff": "2.0.5-next.4",
|
|
48
|
+
"@eslint-react/shared": "2.0.5-next.4",
|
|
49
|
+
"@eslint-react/var": "2.0.5-next.4"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/react": "^19.1.16",
|