eslint-plugin-react-dom 2.0.5-next.1 → 2.0.5-next.3
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 +49 -58
- package/package.json +8 -8
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.3";
|
|
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
|
}
|
|
@@ -129,7 +129,7 @@ var no_dangerously_set_innerhtml_with_children_default = createRule({
|
|
|
129
129
|
description: "Disallow `dangerouslySetInnerHTML` and `children` at the same time.",
|
|
130
130
|
[Symbol.for("rule_features")]: RULE_FEATURES$15
|
|
131
131
|
},
|
|
132
|
-
messages: { noDangerouslySetInnerhtmlWithChildren: "A DOM component cannot use both
|
|
132
|
+
messages: { noDangerouslySetInnerhtmlWithChildren: "A DOM component cannot use both children and 'dangerouslySetInnerHTML'." },
|
|
133
133
|
schema: []
|
|
134
134
|
},
|
|
135
135
|
name: RULE_NAME$16,
|
|
@@ -146,24 +146,16 @@ function isSignificantChildren(node) {
|
|
|
146
146
|
if (!isJsxText(node)) return true;
|
|
147
147
|
return !(node.raw.trim() === "" && node.raw.includes("\n"));
|
|
148
148
|
}
|
|
149
|
-
/**
|
|
150
|
-
* Checks if a JSX element has children, either through the `children` prop or as JSX children.
|
|
151
|
-
* @param context The rule context.
|
|
152
|
-
* @param node The JSX element to check.
|
|
153
|
-
* @returns `true` if the element has children, `false` otherwise.
|
|
154
|
-
*/
|
|
155
|
-
function hasChildren(context, node) {
|
|
156
|
-
if (getJsxAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))("children") != null) return true;
|
|
157
|
-
return node.children.some(isSignificantChildren);
|
|
158
|
-
}
|
|
159
149
|
function create$16(context) {
|
|
160
150
|
if (!context.sourceCode.text.includes(DSIH)) return {};
|
|
161
151
|
return { JSXElement(node) {
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
164
|
-
|
|
152
|
+
const findJsxAttribute = getJsxAttribute(context, node);
|
|
153
|
+
if (findJsxAttribute(DSIH) == null) return;
|
|
154
|
+
const childrenPropOrNode = findJsxAttribute("children") ?? node.children.find(isSignificantChildren);
|
|
155
|
+
if (childrenPropOrNode == null) return;
|
|
156
|
+
context.report({
|
|
165
157
|
messageId: "noDangerouslySetInnerhtmlWithChildren",
|
|
166
|
-
node:
|
|
158
|
+
node: childrenPropOrNode
|
|
167
159
|
});
|
|
168
160
|
} };
|
|
169
161
|
}
|
|
@@ -349,7 +341,7 @@ function create$12(context) {
|
|
|
349
341
|
const resolver = createJsxElementResolver(context);
|
|
350
342
|
return { JSXElement(node) {
|
|
351
343
|
if (resolver.resolve(node).domElementType !== "button") return;
|
|
352
|
-
if (getJsxAttribute(context, node
|
|
344
|
+
if (getJsxAttribute(context, node)("type") != null) return;
|
|
353
345
|
context.report({
|
|
354
346
|
messageId: "noMissingButtonType",
|
|
355
347
|
node: node.openingElement,
|
|
@@ -370,14 +362,14 @@ var no_missing_iframe_sandbox_default = createRule({
|
|
|
370
362
|
meta: {
|
|
371
363
|
type: "problem",
|
|
372
364
|
docs: {
|
|
373
|
-
description: "Enforces explicit `sandbox`
|
|
365
|
+
description: "Enforces explicit `sandbox` prop for `iframe` elements.",
|
|
374
366
|
[Symbol.for("rule_features")]: RULE_FEATURES$10
|
|
375
367
|
},
|
|
376
368
|
fixable: "code",
|
|
377
369
|
hasSuggestions: true,
|
|
378
370
|
messages: {
|
|
379
|
-
addIframeSandbox: "Add 'sandbox'
|
|
380
|
-
noMissingIframeSandbox: "Add missing 'sandbox'
|
|
371
|
+
addIframeSandbox: "Add 'sandbox' prop with value '{{value}}'.",
|
|
372
|
+
noMissingIframeSandbox: "Add missing 'sandbox' prop on 'iframe' component."
|
|
381
373
|
},
|
|
382
374
|
schema: []
|
|
383
375
|
},
|
|
@@ -390,8 +382,8 @@ function create$11(context) {
|
|
|
390
382
|
return { JSXElement(node) {
|
|
391
383
|
const { domElementType } = resolver.resolve(node);
|
|
392
384
|
if (domElementType !== "iframe") return;
|
|
393
|
-
const
|
|
394
|
-
if (
|
|
385
|
+
const sandboxProp = getJsxAttribute(context, node)("sandbox");
|
|
386
|
+
if (sandboxProp == null) {
|
|
395
387
|
context.report({
|
|
396
388
|
messageId: "noMissingIframeSandbox",
|
|
397
389
|
node: node.openingElement,
|
|
@@ -405,17 +397,17 @@ function create$11(context) {
|
|
|
405
397
|
});
|
|
406
398
|
return;
|
|
407
399
|
}
|
|
408
|
-
const sandboxValue = resolveJsxAttributeValue(context,
|
|
400
|
+
const sandboxValue = resolveJsxAttributeValue(context, sandboxProp);
|
|
409
401
|
if (typeof sandboxValue.toStatic("sandbox") === "string") return;
|
|
410
402
|
context.report({
|
|
411
403
|
messageId: "noMissingIframeSandbox",
|
|
412
|
-
node: sandboxValue.node ??
|
|
404
|
+
node: sandboxValue.node ?? sandboxProp,
|
|
413
405
|
suggest: [{
|
|
414
406
|
messageId: "addIframeSandbox",
|
|
415
407
|
data: { value: "" },
|
|
416
408
|
fix(fixer) {
|
|
417
409
|
if (sandboxValue.kind.startsWith("spread")) return null;
|
|
418
|
-
return fixer.replaceText(
|
|
410
|
+
return fixer.replaceText(sandboxProp, `sandbox=""`);
|
|
419
411
|
}
|
|
420
412
|
}]
|
|
421
413
|
});
|
|
@@ -633,12 +625,12 @@ var no_string_style_prop_default = createRule({
|
|
|
633
625
|
function create$6(context) {
|
|
634
626
|
return { JSXElement(node) {
|
|
635
627
|
if (!isJsxHostElement(context, node)) return;
|
|
636
|
-
const
|
|
637
|
-
if (
|
|
638
|
-
const styleValue = resolveJsxAttributeValue(context,
|
|
628
|
+
const styleProp = getJsxAttribute(context, node)("style");
|
|
629
|
+
if (styleProp == null) return;
|
|
630
|
+
const styleValue = resolveJsxAttributeValue(context, styleProp);
|
|
639
631
|
if (typeof styleValue.toStatic() === "string") context.report({
|
|
640
632
|
messageId: "noStringStyleProp",
|
|
641
|
-
node: styleValue.node ??
|
|
633
|
+
node: styleValue.node ?? styleProp
|
|
642
634
|
});
|
|
643
635
|
} };
|
|
644
636
|
}
|
|
@@ -1809,13 +1801,13 @@ function create$4(context) {
|
|
|
1809
1801
|
const resolver = createJsxElementResolver(context);
|
|
1810
1802
|
return { JSXElement(node) {
|
|
1811
1803
|
if (resolver.resolve(node).domElementType !== "iframe") return;
|
|
1812
|
-
const
|
|
1813
|
-
if (
|
|
1814
|
-
const sandboxValue = resolveJsxAttributeValue(context,
|
|
1804
|
+
const sandboxProp = getJsxAttribute(context, node)("sandbox");
|
|
1805
|
+
if (sandboxProp == null) return;
|
|
1806
|
+
const sandboxValue = resolveJsxAttributeValue(context, sandboxProp);
|
|
1815
1807
|
const sandboxValueStatic = sandboxValue.toStatic("sandbox");
|
|
1816
1808
|
if (isUnsafeSandboxCombination(sandboxValueStatic)) context.report({
|
|
1817
1809
|
messageId: "noUnsafeIframeSandbox",
|
|
1818
|
-
node: sandboxValue.node ??
|
|
1810
|
+
node: sandboxValue.node ?? sandboxProp
|
|
1819
1811
|
});
|
|
1820
1812
|
} };
|
|
1821
1813
|
}
|
|
@@ -1835,9 +1827,9 @@ function isExternalLinkLike(value) {
|
|
|
1835
1827
|
return value.startsWith("https://") || /^(?:\w+:|\/\/)/u.test(value);
|
|
1836
1828
|
}
|
|
1837
1829
|
/**
|
|
1838
|
-
* Checks if a rel
|
|
1830
|
+
* Checks if a rel prop value contains the necessary security attributes.
|
|
1839
1831
|
* At minimum, it should contain "noreferrer".
|
|
1840
|
-
* @param value - The rel
|
|
1832
|
+
* @param value - The rel prop value to check
|
|
1841
1833
|
* @returns Whether the rel value is considered secure
|
|
1842
1834
|
*/
|
|
1843
1835
|
function isSafeRel(value) {
|
|
@@ -1868,16 +1860,16 @@ function create$3(context) {
|
|
|
1868
1860
|
return { JSXElement(node) {
|
|
1869
1861
|
const { domElementType } = resolver.resolve(node);
|
|
1870
1862
|
if (domElementType !== "a") return;
|
|
1871
|
-
const findAttribute = getJsxAttribute(context, node
|
|
1872
|
-
const
|
|
1873
|
-
if (
|
|
1874
|
-
if (resolveJsxAttributeValue(context,
|
|
1875
|
-
const
|
|
1876
|
-
if (
|
|
1877
|
-
const
|
|
1878
|
-
if (!isExternalLinkLike(
|
|
1879
|
-
const
|
|
1880
|
-
if (
|
|
1863
|
+
const findAttribute = getJsxAttribute(context, node);
|
|
1864
|
+
const targetProp = findAttribute("target");
|
|
1865
|
+
if (targetProp == null) return;
|
|
1866
|
+
if (resolveJsxAttributeValue(context, targetProp).toStatic("target") !== "_blank") return;
|
|
1867
|
+
const hrefProp = findAttribute("href");
|
|
1868
|
+
if (hrefProp == null) return;
|
|
1869
|
+
const hrefValue = resolveJsxAttributeValue(context, hrefProp).toStatic("href");
|
|
1870
|
+
if (!isExternalLinkLike(hrefValue)) return;
|
|
1871
|
+
const relProp = findAttribute("rel");
|
|
1872
|
+
if (relProp == null) {
|
|
1881
1873
|
context.report({
|
|
1882
1874
|
messageId: "noUnsafeTargetBlank",
|
|
1883
1875
|
node: node.openingElement,
|
|
@@ -1890,15 +1882,15 @@ function create$3(context) {
|
|
|
1890
1882
|
});
|
|
1891
1883
|
return;
|
|
1892
1884
|
}
|
|
1893
|
-
const
|
|
1894
|
-
if (isSafeRel(
|
|
1885
|
+
const relValue = resolveJsxAttributeValue(context, relProp).toStatic("rel");
|
|
1886
|
+
if (isSafeRel(relValue)) return;
|
|
1895
1887
|
context.report({
|
|
1896
1888
|
messageId: "noUnsafeTargetBlank",
|
|
1897
|
-
node:
|
|
1889
|
+
node: relProp,
|
|
1898
1890
|
suggest: [{
|
|
1899
1891
|
messageId: "addRelNoreferrerNoopener",
|
|
1900
1892
|
fix(fixer) {
|
|
1901
|
-
return fixer.replaceText(
|
|
1893
|
+
return fixer.replaceText(relProp, `rel="noreferrer noopener"`);
|
|
1902
1894
|
}
|
|
1903
1895
|
}]
|
|
1904
1896
|
});
|
|
@@ -2013,10 +2005,9 @@ function create$1(context) {
|
|
|
2013
2005
|
return { JSXElement(node) {
|
|
2014
2006
|
const { domElementType: elementName } = resolver.resolve(node);
|
|
2015
2007
|
if (!voidElements.has(elementName)) return;
|
|
2016
|
-
const
|
|
2017
|
-
const
|
|
2018
|
-
const
|
|
2019
|
-
const hasDangerouslySetInnerHTML = hasJsxAttribute(context, "dangerouslySetInnerHTML", attributes, initialScope);
|
|
2008
|
+
const findJsxAttribute = getJsxAttribute(context, node);
|
|
2009
|
+
const hasChildrenProp = findJsxAttribute("children") != null;
|
|
2010
|
+
const hasDangerouslySetInnerHTML = findJsxAttribute("dangerouslySetInnerHTML") != null;
|
|
2020
2011
|
if (node.children.length > 0 || hasChildrenProp || hasDangerouslySetInnerHTML) context.report({
|
|
2021
2012
|
messageId: "noVoidElementsWithChildren",
|
|
2022
2013
|
node,
|
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.3",
|
|
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/ast": "2.0.5-next.
|
|
45
|
-
"@eslint-react/
|
|
46
|
-
"@eslint-react/eff": "2.0.5-next.
|
|
47
|
-
"@eslint-react/
|
|
48
|
-
"@eslint-react/var": "2.0.5-next.
|
|
49
|
-
"@eslint-react/
|
|
44
|
+
"@eslint-react/ast": "2.0.5-next.3",
|
|
45
|
+
"@eslint-react/core": "2.0.5-next.3",
|
|
46
|
+
"@eslint-react/eff": "2.0.5-next.3",
|
|
47
|
+
"@eslint-react/kit": "2.0.5-next.3",
|
|
48
|
+
"@eslint-react/var": "2.0.5-next.3",
|
|
49
|
+
"@eslint-react/shared": "2.0.5-next.3"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/react": "^19.1.16",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"eslint": "^9.36.0",
|
|
59
|
-
"typescript": "^5.9.
|
|
59
|
+
"typescript": "^5.9.3"
|
|
60
60
|
},
|
|
61
61
|
"engines": {
|
|
62
62
|
"node": ">=20.19.0"
|