eslint-plugin-react-dom 2.0.4-next.0 → 2.0.5-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.
Files changed (2) hide show
  1. package/dist/index.js +81 -89
  2. package/package.json +9 -9
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 { getAttribute, getElementType, hasAttribute, isHostElement, isJsxText, resolveAttributeValue } from "@eslint-react/core";
2
+ import { getJsxAttribute, getJsxElementType, hasJsxAttribute, 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.4-next.0";
50
+ var version = "2.0.5-beta.0";
51
51
 
52
52
  //#endregion
53
53
  //#region src/utils/create-jsx-element-resolver.ts
@@ -65,15 +65,15 @@ var version = "2.0.4-next.0";
65
65
  function createJsxElementResolver(context) {
66
66
  const { polymorphicPropName } = getSettingsFromContext(context);
67
67
  return { resolve(node) {
68
- const elementName = getElementType(context, node);
68
+ const elementName = getJsxElementType(context, node);
69
69
  const result = {
70
70
  domElementType: elementName,
71
71
  jsxElementType: elementName
72
72
  };
73
73
  if (elementName === elementName.toLowerCase() || polymorphicPropName == null) return result;
74
- const polymorphicProp = getAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))(polymorphicPropName);
74
+ const polymorphicProp = getJsxAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))(polymorphicPropName);
75
75
  if (polymorphicProp != null) {
76
- const staticValue = resolveAttributeValue(context, polymorphicProp).toStatic(polymorphicPropName);
76
+ const staticValue = resolveJsxAttributeValue(context, polymorphicProp).toStatic(polymorphicPropName);
77
77
  if (typeof staticValue === "string") return {
78
78
  ...result,
79
79
  domElementType: staticValue
@@ -91,6 +91,7 @@ const createRule = ESLintUtils.RuleCreator(getDocsUrl("dom"));
91
91
  //#region src/rules/no-dangerously-set-innerhtml.ts
92
92
  const RULE_NAME$17 = "no-dangerously-set-innerhtml";
93
93
  const RULE_FEATURES$16 = [];
94
+ const DSIH$1 = "dangerouslySetInnerHTML";
94
95
  var no_dangerously_set_innerhtml_default = createRule({
95
96
  meta: {
96
97
  type: "problem",
@@ -105,15 +106,14 @@ var no_dangerously_set_innerhtml_default = createRule({
105
106
  create: create$17,
106
107
  defaultOptions: []
107
108
  });
108
- const dangerouslySetInnerHTML$1 = "dangerouslySetInnerHTML";
109
109
  function create$17(context) {
110
- if (!context.sourceCode.text.includes(dangerouslySetInnerHTML$1)) return {};
110
+ if (!context.sourceCode.text.includes(DSIH$1)) return {};
111
111
  return { JSXElement(node) {
112
- const attribute = getAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))(dangerouslySetInnerHTML$1);
113
- if (attribute == null) return;
112
+ const attr = getJsxAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))(DSIH$1);
113
+ if (attr == null) return;
114
114
  context.report({
115
115
  messageId: "noDangerouslySetInnerhtml",
116
- node: attribute
116
+ node: attr
117
117
  });
118
118
  } };
119
119
  }
@@ -136,36 +136,36 @@ var no_dangerously_set_innerhtml_with_children_default = createRule({
136
136
  create: create$16,
137
137
  defaultOptions: []
138
138
  });
139
- const dangerouslySetInnerHTML = "dangerouslySetInnerHTML";
140
- function create$16(context) {
141
- if (!context.sourceCode.text.includes(dangerouslySetInnerHTML)) return {};
142
- return { JSXElement(node) {
143
- const attributes = node.openingElement.attributes;
144
- const initialScope = context.sourceCode.getScope(node);
145
- if ((node.children.some(isSignificantChildren) || hasAttribute(context, "children", attributes, initialScope)) && hasAttribute(context, dangerouslySetInnerHTML, attributes, initialScope)) context.report({
146
- messageId: "noDangerouslySetInnerhtmlWithChildren",
147
- node
148
- });
149
- } };
150
- }
139
+ const DSIH = "dangerouslySetInnerHTML";
151
140
  /**
152
- * Check if a Literal or JSXText node is whitespace
153
- * @param node The AST node to check
154
- * @returns boolean `true` if the node is whitespace
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.
155
144
  */
156
- function isWhiteSpace(node) {
157
- return typeof node.value === "string" && node.raw.trim() === "";
145
+ function isSignificantChildren(node) {
146
+ if (!isJsxText(node)) return true;
147
+ return !(node.raw.trim() === "" && node.raw.includes("\n"));
158
148
  }
159
149
  /**
160
- * Check if a Literal or JSXText node is padding spaces
161
- * @param node The AST node to check
162
- * @returns boolean
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.
163
154
  */
164
- function isPaddingSpaces(node) {
165
- return isJsxText(node) && isWhiteSpace(node) && node.raw.includes("\n");
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);
166
158
  }
167
- function isSignificantChildren(node) {
168
- return node.type !== AST_NODE_TYPES.JSXText || !isPaddingSpaces(node);
159
+ function create$16(context) {
160
+ if (!context.sourceCode.text.includes(DSIH)) return {};
161
+ return { JSXElement(node) {
162
+ const DSIHAttr = getJsxAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))(DSIH);
163
+ if (DSIHAttr == null) return;
164
+ if (hasChildren(context, node)) context.report({
165
+ messageId: "noDangerouslySetInnerhtmlWithChildren",
166
+ node: DSIHAttr
167
+ });
168
+ } };
169
169
  }
170
170
 
171
171
  //#endregion
@@ -348,25 +348,19 @@ var no_missing_button_type_default = createRule({
348
348
  function create$12(context) {
349
349
  const resolver = createJsxElementResolver(context);
350
350
  return { JSXElement(node) {
351
- const { domElementType } = resolver.resolve(node);
352
- if (domElementType !== "button") return;
353
- if (getAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))("type") != null) return;
351
+ if (resolver.resolve(node).domElementType !== "button") return;
352
+ if (getJsxAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))("type") != null) return;
354
353
  context.report({
355
354
  messageId: "noMissingButtonType",
356
355
  node: node.openingElement,
357
- suggest: getSuggest((type) => (fixer) => {
358
- return fixer.insertTextAfter(node.openingElement.name, ` type="${type}"`);
359
- })
356
+ suggest: BUTTON_TYPES.map((type) => ({
357
+ messageId: "addButtonType",
358
+ data: { type },
359
+ fix: (fixer) => fixer.insertTextAfter(node.openingElement.name, ` type="${type}"`)
360
+ }))
360
361
  });
361
362
  } };
362
363
  }
363
- function getSuggest(getFix$3) {
364
- return BUTTON_TYPES.map((type) => ({
365
- messageId: "addButtonType",
366
- data: { type },
367
- fix: getFix$3(type)
368
- }));
369
- }
370
364
 
371
365
  //#endregion
372
366
  //#region src/rules/no-missing-iframe-sandbox.ts
@@ -396,8 +390,8 @@ function create$11(context) {
396
390
  return { JSXElement(node) {
397
391
  const { domElementType } = resolver.resolve(node);
398
392
  if (domElementType !== "iframe") return;
399
- const sandboxAttribute = getAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))("sandbox");
400
- if (sandboxAttribute == null) {
393
+ const sandboxAttr = getJsxAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))("sandbox");
394
+ if (sandboxAttr == null) {
401
395
  context.report({
402
396
  messageId: "noMissingIframeSandbox",
403
397
  node: node.openingElement,
@@ -411,17 +405,17 @@ function create$11(context) {
411
405
  });
412
406
  return;
413
407
  }
414
- const sandboxAttributeValue = resolveAttributeValue(context, sandboxAttribute);
415
- if (typeof sandboxAttributeValue.toStatic("sandbox") === "string") return;
408
+ const sandboxValue = resolveJsxAttributeValue(context, sandboxAttr);
409
+ if (typeof sandboxValue.toStatic("sandbox") === "string") return;
416
410
  context.report({
417
411
  messageId: "noMissingIframeSandbox",
418
- node: sandboxAttributeValue.node ?? sandboxAttribute,
412
+ node: sandboxValue.node ?? sandboxAttr,
419
413
  suggest: [{
420
414
  messageId: "addIframeSandbox",
421
415
  data: { value: "" },
422
416
  fix(fixer) {
423
- if (sandboxAttributeValue.kind.startsWith("spread")) return null;
424
- return fixer.replaceText(sandboxAttribute, `sandbox=""`);
417
+ if (sandboxValue.kind.startsWith("spread")) return null;
418
+ return fixer.replaceText(sandboxAttr, `sandbox=""`);
425
419
  }
426
420
  }]
427
421
  });
@@ -448,7 +442,7 @@ var no_namespace_default = createRule({
448
442
  });
449
443
  function create$10(context) {
450
444
  return { JSXElement(node) {
451
- const name$2 = getElementType(context, node);
445
+ const name$2 = getJsxElementType(context, node);
452
446
  if (typeof name$2 !== "string" || !name$2.includes(":")) return;
453
447
  context.report({
454
448
  messageId: "noNamespace",
@@ -610,7 +604,7 @@ var no_script_url_default = createRule({
610
604
  function create$7(context) {
611
605
  return { JSXAttribute(node) {
612
606
  if (node.name.type !== AST_NODE_TYPES.JSXIdentifier || node.value == null) return;
613
- const value = resolveAttributeValue(context, node).toStatic();
607
+ const value = resolveJsxAttributeValue(context, node).toStatic();
614
608
  if (typeof value === "string" && RE_JAVASCRIPT_PROTOCOL.test(value)) context.report({
615
609
  messageId: "noScriptUrl",
616
610
  node: node.value
@@ -638,13 +632,13 @@ var no_string_style_prop_default = createRule({
638
632
  });
639
633
  function create$6(context) {
640
634
  return { JSXElement(node) {
641
- if (!isHostElement(context, node)) return;
642
- const attribute = getAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))("style");
643
- if (attribute == null) return;
644
- const attributeValue = resolveAttributeValue(context, attribute);
645
- if (typeof attributeValue.toStatic() === "string") context.report({
635
+ if (!isJsxHostElement(context, node)) return;
636
+ const styleAttr = getJsxAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))("style");
637
+ if (styleAttr == null) return;
638
+ const styleValue = resolveJsxAttributeValue(context, styleAttr);
639
+ if (typeof styleValue.toStatic() === "string") context.report({
646
640
  messageId: "noStringStyleProp",
647
- node: attributeValue.node ?? attribute
641
+ node: styleValue.node ?? styleAttr
648
642
  });
649
643
  } };
650
644
  }
@@ -1787,12 +1781,15 @@ function create$5(context) {
1787
1781
  //#region src/rules/no-unsafe-iframe-sandbox.ts
1788
1782
  const RULE_NAME$4 = "no-unsafe-iframe-sandbox";
1789
1783
  const RULE_FEATURES$4 = [];
1790
- const unsafeSandboxValues = [["allow-scripts", "allow-same-origin"]];
1791
- function isSafeSandbox(value) {
1784
+ const UNSAFE_SANDBOX_VALUES = ["allow-scripts", "allow-same-origin"];
1785
+ /**
1786
+ * Checks if the sandbox attribute value contains an unsafe combination.
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.
1789
+ */
1790
+ function isUnsafeSandboxCombination(value) {
1792
1791
  if (typeof value !== "string") return false;
1793
- return !unsafeSandboxValues.some((values) => {
1794
- return values.every((v) => value.includes(v));
1795
- });
1792
+ return UNSAFE_SANDBOX_VALUES.every((v) => value.includes(v));
1796
1793
  }
1797
1794
  var no_unsafe_iframe_sandbox_default = createRule({
1798
1795
  meta: {
@@ -1811,15 +1808,14 @@ var no_unsafe_iframe_sandbox_default = createRule({
1811
1808
  function create$4(context) {
1812
1809
  const resolver = createJsxElementResolver(context);
1813
1810
  return { JSXElement(node) {
1814
- const { domElementType } = resolver.resolve(node);
1815
- if (domElementType !== "iframe") return;
1816
- const sandboxAttribute = getAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))("sandbox");
1817
- if (sandboxAttribute == null) return;
1818
- const sandboxValue = resolveAttributeValue(context, sandboxAttribute);
1811
+ if (resolver.resolve(node).domElementType !== "iframe") return;
1812
+ const sandboxAttr = getJsxAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node))("sandbox");
1813
+ if (sandboxAttr == null) return;
1814
+ const sandboxValue = resolveJsxAttributeValue(context, sandboxAttr);
1819
1815
  const sandboxValueStatic = sandboxValue.toStatic("sandbox");
1820
- if (!isSafeSandbox(sandboxValueStatic)) context.report({
1816
+ if (isUnsafeSandboxCombination(sandboxValueStatic)) context.report({
1821
1817
  messageId: "noUnsafeIframeSandbox",
1822
- node: sandboxValue.node ?? sandboxAttribute
1818
+ node: sandboxValue.node ?? sandboxAttr
1823
1819
  });
1824
1820
  } };
1825
1821
  }
@@ -1872,15 +1868,15 @@ function create$3(context) {
1872
1868
  return { JSXElement(node) {
1873
1869
  const { domElementType } = resolver.resolve(node);
1874
1870
  if (domElementType !== "a") return;
1875
- const getAttributeEx = getAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node));
1876
- const targetAttribute = getAttributeEx("target");
1871
+ const findAttribute = getJsxAttribute(context, node.openingElement.attributes, context.sourceCode.getScope(node));
1872
+ const targetAttribute = findAttribute("target");
1877
1873
  if (targetAttribute == null) return;
1878
- if (resolveAttributeValue(context, targetAttribute).toStatic("target") !== "_blank") return;
1879
- const hrefAttribute = getAttributeEx("href");
1874
+ if (resolveJsxAttributeValue(context, targetAttribute).toStatic("target") !== "_blank") return;
1875
+ const hrefAttribute = findAttribute("href");
1880
1876
  if (hrefAttribute == null) return;
1881
- const hrefAttributeValue = resolveAttributeValue(context, hrefAttribute).toStatic("href");
1877
+ const hrefAttributeValue = resolveJsxAttributeValue(context, hrefAttribute).toStatic("href");
1882
1878
  if (!isExternalLinkLike(hrefAttributeValue)) return;
1883
- const relAttribute = getAttributeEx("rel");
1879
+ const relAttribute = findAttribute("rel");
1884
1880
  if (relAttribute == null) {
1885
1881
  context.report({
1886
1882
  messageId: "noUnsafeTargetBlank",
@@ -1894,7 +1890,7 @@ function create$3(context) {
1894
1890
  });
1895
1891
  return;
1896
1892
  }
1897
- const relAttributeValue = resolveAttributeValue(context, relAttribute).toStatic("rel");
1893
+ const relAttributeValue = resolveJsxAttributeValue(context, relAttribute).toStatic("rel");
1898
1894
  if (isSafeRel(relAttributeValue)) return;
1899
1895
  context.report({
1900
1896
  messageId: "noUnsafeTargetBlank",
@@ -2016,16 +2012,12 @@ function create$1(context) {
2016
2012
  const resolver = createJsxElementResolver(context);
2017
2013
  return { JSXElement(node) {
2018
2014
  const { domElementType: elementName } = resolver.resolve(node);
2019
- if (elementName.length === 0 || !voidElements.has(elementName)) return;
2020
- if (node.children.length > 0) context.report({
2021
- messageId: "noVoidElementsWithChildren",
2022
- node,
2023
- data: { element: elementName }
2024
- });
2015
+ if (!voidElements.has(elementName)) return;
2025
2016
  const { attributes } = node.openingElement;
2026
2017
  const initialScope = context.sourceCode.getScope(node);
2027
- const hasAttributeEx = (name$2) => hasAttribute(context, name$2, attributes, initialScope);
2028
- if (hasAttributeEx("children") || hasAttributeEx("dangerouslySetInnerHTML")) context.report({
2018
+ const hasChildrenProp = hasJsxAttribute(context, "children", attributes, initialScope);
2019
+ const hasDangerouslySetInnerHTML = hasJsxAttribute(context, "dangerouslySetInnerHTML", attributes, initialScope);
2020
+ if (node.children.length > 0 || hasChildrenProp || hasDangerouslySetInnerHTML) context.report({
2029
2021
  messageId: "noVoidElementsWithChildren",
2030
2022
  node,
2031
2023
  data: { element: elementName }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-dom",
3
- "version": "2.0.4-next.0",
3
+ "version": "2.0.5-beta.0",
4
4
  "description": "ESLint React's ESLint plugin for React DOM related rules.",
5
5
  "keywords": [
6
6
  "react",
@@ -41,17 +41,17 @@
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.4-next.0",
45
- "@eslint-react/core": "2.0.4-next.0",
46
- "@eslint-react/eff": "2.0.4-next.0",
47
- "@eslint-react/kit": "2.0.4-next.0",
48
- "@eslint-react/shared": "2.0.4-next.0",
49
- "@eslint-react/var": "2.0.4-next.0"
44
+ "@eslint-react/ast": "2.0.5-beta.0",
45
+ "@eslint-react/core": "2.0.5-beta.0",
46
+ "@eslint-react/shared": "2.0.5-beta.0",
47
+ "@eslint-react/eff": "2.0.5-beta.0",
48
+ "@eslint-react/kit": "2.0.5-beta.0",
49
+ "@eslint-react/var": "2.0.5-beta.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@types/react": "^19.1.15",
52
+ "@types/react": "^19.1.16",
53
53
  "@types/react-dom": "^19.1.9",
54
- "tsdown": "^0.15.5",
54
+ "tsdown": "^0.15.6",
55
55
  "@local/configs": "0.0.0"
56
56
  },
57
57
  "peerDependencies": {