eslint-plugin-react-dom 2.0.0-next.154 → 2.0.0-next.156

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 +193 -138
  2. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -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.0-next.154";
50
+ var version = "2.0.0-next.156";
51
51
 
52
52
  //#endregion
53
53
  //#region src/utils/create-jsx-element-resolver.ts
@@ -81,6 +81,13 @@ const createRule = ESLintUtils.RuleCreator(getDocsUrl("dom"));
81
81
 
82
82
  //#endregion
83
83
  //#region src/utils/find-custom-component.ts
84
+ /**
85
+ * Finds a custom component prop by its "as" name.
86
+ *
87
+ * @param name - The name to match against the prop's "as" property
88
+ * @param props - Array of normalized custom component props to search through
89
+ * @returns The matching prop if found, undefined otherwise
90
+ */
84
91
  function findCustomComponentProp(name$2, props) {
85
92
  return props.findLast((a) => a.as === name$2);
86
93
  }
@@ -706,6 +713,9 @@ const DEFAULTS = {
706
713
  ignore: [],
707
714
  requireDataLowercase: false
708
715
  };
716
+ /**
717
+ * Map of standard HTML attributes to their React counterparts
718
+ */
709
719
  const DOM_ATTRIBUTE_NAMES = {
710
720
  "accept-charset": "acceptCharset",
711
721
  class: "className",
@@ -714,6 +724,96 @@ const DOM_ATTRIBUTE_NAMES = {
714
724
  "http-equiv": "httpEquiv",
715
725
  nomodule: "noModule"
716
726
  };
727
+ /**
728
+ * Map of SVG attributes to their React camelCase equivalents
729
+ */
730
+ const SVGDOM_ATTRIBUTE_NAMES = {
731
+ "accent-height": "accentHeight",
732
+ "alignment-baseline": "alignmentBaseline",
733
+ "arabic-form": "arabicForm",
734
+ "baseline-shift": "baselineShift",
735
+ "cap-height": "capHeight",
736
+ "clip-path": "clipPath",
737
+ "clip-rule": "clipRule",
738
+ "color-interpolation": "colorInterpolation",
739
+ "color-interpolation-filters": "colorInterpolationFilters",
740
+ "color-profile": "colorProfile",
741
+ "color-rendering": "colorRendering",
742
+ "dominant-baseline": "dominantBaseline",
743
+ "enable-background": "enableBackground",
744
+ "fill-opacity": "fillOpacity",
745
+ "fill-rule": "fillRule",
746
+ "flood-color": "floodColor",
747
+ "flood-opacity": "floodOpacity",
748
+ "font-family": "fontFamily",
749
+ "font-size": "fontSize",
750
+ "font-size-adjust": "fontSizeAdjust",
751
+ "font-stretch": "fontStretch",
752
+ "font-style": "fontStyle",
753
+ "font-variant": "fontVariant",
754
+ "font-weight": "fontWeight",
755
+ "glyph-name": "glyphName",
756
+ "glyph-orientation-horizontal": "glyphOrientationHorizontal",
757
+ "glyph-orientation-vertical": "glyphOrientationVertical",
758
+ "horiz-adv-x": "horizAdvX",
759
+ "horiz-origin-x": "horizOriginX",
760
+ "image-rendering": "imageRendering",
761
+ "letter-spacing": "letterSpacing",
762
+ "lighting-color": "lightingColor",
763
+ "marker-end": "markerEnd",
764
+ "marker-mid": "markerMid",
765
+ "marker-start": "markerStart",
766
+ "overline-position": "overlinePosition",
767
+ "overline-thickness": "overlineThickness",
768
+ "paint-order": "paintOrder",
769
+ "panose-1": "panose1",
770
+ "pointer-events": "pointerEvents",
771
+ "rendering-intent": "renderingIntent",
772
+ "shape-rendering": "shapeRendering",
773
+ "stop-color": "stopColor",
774
+ "stop-opacity": "stopOpacity",
775
+ "strikethrough-position": "strikethroughPosition",
776
+ "strikethrough-thickness": "strikethroughThickness",
777
+ "stroke-dasharray": "strokeDasharray",
778
+ "stroke-dashoffset": "strokeDashoffset",
779
+ "stroke-linecap": "strokeLinecap",
780
+ "stroke-linejoin": "strokeLinejoin",
781
+ "stroke-miterlimit": "strokeMiterlimit",
782
+ "stroke-opacity": "strokeOpacity",
783
+ "stroke-width": "strokeWidth",
784
+ "text-anchor": "textAnchor",
785
+ "text-decoration": "textDecoration",
786
+ "text-rendering": "textRendering",
787
+ "underline-position": "underlinePosition",
788
+ "underline-thickness": "underlineThickness",
789
+ "unicode-bidi": "unicodeBidi",
790
+ "unicode-range": "unicodeRange",
791
+ "units-per-em": "unitsPerEm",
792
+ "v-alphabetic": "vAlphabetic",
793
+ "v-hanging": "vHanging",
794
+ "v-ideographic": "vIdeographic",
795
+ "v-mathematical": "vMathematical",
796
+ "vector-effect": "vectorEffect",
797
+ "vert-adv-y": "vertAdvY",
798
+ "vert-origin-x": "vertOriginX",
799
+ "vert-origin-y": "vertOriginY",
800
+ "word-spacing": "wordSpacing",
801
+ "writing-mode": "writingMode",
802
+ "x-height": "xHeight",
803
+ "xlink:actuate": "xlinkActuate",
804
+ "xlink:arcrole": "xlinkArcrole",
805
+ "xlink:href": "xlinkHref",
806
+ "xlink:role": "xlinkRole",
807
+ "xlink:show": "xlinkShow",
808
+ "xlink:title": "xlinkTitle",
809
+ "xlink:type": "xlinkType",
810
+ "xml:base": "xmlBase",
811
+ "xml:lang": "xmlLang",
812
+ "xml:space": "xmlSpace"
813
+ };
814
+ /**
815
+ * Map of attributes that are only valid on specific HTML tags
816
+ */
717
817
  const ATTRIBUTE_TAGS_MAP = {
718
818
  as: ["link"],
719
819
  abbr: ["th", "td"],
@@ -853,90 +953,9 @@ const ATTRIBUTE_TAGS_MAP = {
853
953
  webkitAllowFullScreen: ["iframe", "video"],
854
954
  webkitDirectory: ["input"]
855
955
  };
856
- const SVGDOM_ATTRIBUTE_NAMES = {
857
- "accent-height": "accentHeight",
858
- "alignment-baseline": "alignmentBaseline",
859
- "arabic-form": "arabicForm",
860
- "baseline-shift": "baselineShift",
861
- "cap-height": "capHeight",
862
- "clip-path": "clipPath",
863
- "clip-rule": "clipRule",
864
- "color-interpolation": "colorInterpolation",
865
- "color-interpolation-filters": "colorInterpolationFilters",
866
- "color-profile": "colorProfile",
867
- "color-rendering": "colorRendering",
868
- "dominant-baseline": "dominantBaseline",
869
- "enable-background": "enableBackground",
870
- "fill-opacity": "fillOpacity",
871
- "fill-rule": "fillRule",
872
- "flood-color": "floodColor",
873
- "flood-opacity": "floodOpacity",
874
- "font-family": "fontFamily",
875
- "font-size": "fontSize",
876
- "font-size-adjust": "fontSizeAdjust",
877
- "font-stretch": "fontStretch",
878
- "font-style": "fontStyle",
879
- "font-variant": "fontVariant",
880
- "font-weight": "fontWeight",
881
- "glyph-name": "glyphName",
882
- "glyph-orientation-horizontal": "glyphOrientationHorizontal",
883
- "glyph-orientation-vertical": "glyphOrientationVertical",
884
- "horiz-adv-x": "horizAdvX",
885
- "horiz-origin-x": "horizOriginX",
886
- "image-rendering": "imageRendering",
887
- "letter-spacing": "letterSpacing",
888
- "lighting-color": "lightingColor",
889
- "marker-end": "markerEnd",
890
- "marker-mid": "markerMid",
891
- "marker-start": "markerStart",
892
- "overline-position": "overlinePosition",
893
- "overline-thickness": "overlineThickness",
894
- "paint-order": "paintOrder",
895
- "panose-1": "panose1",
896
- "pointer-events": "pointerEvents",
897
- "rendering-intent": "renderingIntent",
898
- "shape-rendering": "shapeRendering",
899
- "stop-color": "stopColor",
900
- "stop-opacity": "stopOpacity",
901
- "strikethrough-position": "strikethroughPosition",
902
- "strikethrough-thickness": "strikethroughThickness",
903
- "stroke-dasharray": "strokeDasharray",
904
- "stroke-dashoffset": "strokeDashoffset",
905
- "stroke-linecap": "strokeLinecap",
906
- "stroke-linejoin": "strokeLinejoin",
907
- "stroke-miterlimit": "strokeMiterlimit",
908
- "stroke-opacity": "strokeOpacity",
909
- "stroke-width": "strokeWidth",
910
- "text-anchor": "textAnchor",
911
- "text-decoration": "textDecoration",
912
- "text-rendering": "textRendering",
913
- "underline-position": "underlinePosition",
914
- "underline-thickness": "underlineThickness",
915
- "unicode-bidi": "unicodeBidi",
916
- "unicode-range": "unicodeRange",
917
- "units-per-em": "unitsPerEm",
918
- "v-alphabetic": "vAlphabetic",
919
- "v-hanging": "vHanging",
920
- "v-ideographic": "vIdeographic",
921
- "v-mathematical": "vMathematical",
922
- "vector-effect": "vectorEffect",
923
- "vert-adv-y": "vertAdvY",
924
- "vert-origin-x": "vertOriginX",
925
- "vert-origin-y": "vertOriginY",
926
- "word-spacing": "wordSpacing",
927
- "writing-mode": "writingMode",
928
- "x-height": "xHeight",
929
- "xlink:actuate": "xlinkActuate",
930
- "xlink:arcrole": "xlinkArcrole",
931
- "xlink:href": "xlinkHref",
932
- "xlink:role": "xlinkRole",
933
- "xlink:show": "xlinkShow",
934
- "xlink:title": "xlinkTitle",
935
- "xlink:type": "xlinkType",
936
- "xml:base": "xmlBase",
937
- "xml:lang": "xmlLang",
938
- "xml:space": "xmlSpace"
939
- };
956
+ /**
957
+ * Single-word HTML/DOM properties
958
+ */
940
959
  const DOM_PROPERTY_NAMES_ONE_WORD = [
941
960
  "dir",
942
961
  "draggable",
@@ -1129,6 +1148,9 @@ const DOM_PROPERTY_NAMES_ONE_WORD = [
1129
1148
  "security",
1130
1149
  "controls"
1131
1150
  ];
1151
+ /**
1152
+ * Multi-word (camelCase) HTML/DOM properties
1153
+ */
1132
1154
  const DOM_PROPERTY_NAMES_TWO_WORDS = [
1133
1155
  "accessKey",
1134
1156
  "autoCapitalize",
@@ -1490,6 +1512,9 @@ const DOM_PROPERTY_NAMES_TWO_WORDS = [
1490
1512
  "disablePictureInPicture",
1491
1513
  "disableRemotePlayback"
1492
1514
  ];
1515
+ /**
1516
+ * DOM properties that are exempt from case sensitivity checks
1517
+ */
1493
1518
  const DOM_PROPERTIES_IGNORE_CASE = [
1494
1519
  "charset",
1495
1520
  "allowFullScreen",
@@ -1497,6 +1522,9 @@ const DOM_PROPERTIES_IGNORE_CASE = [
1497
1522
  "mozAllowFullScreen",
1498
1523
  "webkitDirectory"
1499
1524
  ];
1525
+ /**
1526
+ * List of ARIA attributes
1527
+ */
1500
1528
  const ARIA_PROPERTIES = [
1501
1529
  "aria-atomic",
1502
1530
  "aria-braillelabel",
@@ -1552,6 +1580,9 @@ const ARIA_PROPERTIES = [
1552
1580
  "aria-rowspan",
1553
1581
  "aria-setsize"
1554
1582
  ];
1583
+ /**
1584
+ * React-specific pointer event handlers added in React 16.4
1585
+ */
1555
1586
  const REACT_ON_PROPS = [
1556
1587
  "onGotPointerCapture",
1557
1588
  "onGotPointerCaptureCapture",
@@ -1575,6 +1606,9 @@ const REACT_ON_PROPS = [
1575
1606
  "onPointerUp",
1576
1607
  "onPointerUpCapture"
1577
1608
  ];
1609
+ /**
1610
+ * Popover API properties added in React 19
1611
+ */
1578
1612
  const POPOVER_API_PROPS = [
1579
1613
  "popover",
1580
1614
  "popoverTarget",
@@ -1582,6 +1616,11 @@ const POPOVER_API_PROPS = [
1582
1616
  "onToggle",
1583
1617
  "onBeforeToggle"
1584
1618
  ];
1619
+ /**
1620
+ * Gets all valid DOM property names based on React version
1621
+ * @param context - ESLint rule context
1622
+ * @returns Array of valid DOM property names
1623
+ */
1585
1624
  function getDOMPropertyNames(context) {
1586
1625
  const ALL_DOM_PROPERTY_NAMES = DOM_PROPERTY_NAMES_TWO_WORDS.concat(DOM_PROPERTY_NAMES_ONE_WORD);
1587
1626
  if (testReactVersion(context, "<=", "16.1.0")) {
@@ -1594,14 +1633,9 @@ function getDOMPropertyNames(context) {
1594
1633
  }
1595
1634
  /**
1596
1635
  * Checks if a node's parent is a JSX tag that is written with lowercase letters,
1597
- * and is not a custom web component. Custom web components have a hyphen in tag name,
1598
- * or have an `is="some-elem"` attribute.
1599
- *
1600
- * Note: does not check if a tag's parent against a list of standard HTML/DOM tags. For example,
1601
- * a `<fake>`'s child would return `true` because "fake" is written only with lowercase letters
1602
- * without a hyphen and does not have a `is="some-elem"` attribute.
1603
- * @param childNode - JSX element being tested.
1604
- * @returns Whether or not the node name match the JSX tag convention.
1636
+ * and is not a custom web component.
1637
+ * @param childNode - JSX element being tested
1638
+ * @returns Whether the node is a valid HTML tag in JSX
1605
1639
  */
1606
1640
  function isValidHTMLTagInJSX(childNode) {
1607
1641
  const tagConvention = /^[a-z][^-]*$/;
@@ -1609,70 +1643,59 @@ function isValidHTMLTagInJSX(childNode) {
1609
1643
  return false;
1610
1644
  }
1611
1645
  /**
1612
- * Checks if the attribute name is included in the attributes that are excluded
1613
- * from the camel casing.
1614
- *
1615
- * // returns 'charSet'
1616
- * @example normalizeAttributeCase('charset')
1617
- *
1618
- * Note - these exclusions are not made by React core team, but `eslint-plugin-react` community.
1619
- * @param name - Attribute name to be normalized
1620
- * @returns Result
1646
+ * Normalizes attribute names that should be case-insensitive
1647
+ * @param name - Attribute name to normalize
1648
+ * @returns Normalized attribute name
1621
1649
  */
1622
1650
  function normalizeAttributeCase(name$2) {
1623
1651
  return DOM_PROPERTIES_IGNORE_CASE.find((element) => element.toLowerCase() === name$2.toLowerCase()) || name$2;
1624
1652
  }
1625
1653
  /**
1626
- * Checks if an attribute name is a valid `data-*` attribute:
1627
- * if the name starts with "data-" and has alphanumeric words (browsers require lowercase, but React and TS lowercase them),
1628
- * not start with any casing of "xml", and separated by hyphens (-) (which is also called "kebab case" or "dash case"),
1629
- * then the attribute is a valid data attribute.
1630
- * @param name - Attribute name to be tested
1631
- * @returns Result
1654
+ * Checks if an attribute name is a valid data-* attribute
1655
+ * @param name - Attribute name to test
1656
+ * @returns Whether the attribute is a valid data attribute
1632
1657
  */
1633
1658
  function isValidDataAttribute(name$2) {
1634
1659
  return !/^data-xml/i.test(name$2) && /^data-[^:]*$/.test(name$2);
1635
1660
  }
1636
1661
  /**
1637
- * Checks if an attribute name has at least one uppercase characters
1638
- * @param name
1639
- * @returns Result
1662
+ * Checks if an attribute name has uppercase characters
1663
+ * @param name - Attribute name to test
1664
+ * @returns Whether the name has uppercase characters
1640
1665
  */
1641
1666
  function hasUpperCaseCharacter(name$2) {
1642
1667
  return name$2.toLowerCase() !== name$2;
1643
1668
  }
1644
1669
  /**
1645
- * Checks if an attribute name is a standard aria attribute by compering it to a list
1646
- * of standard aria property names
1647
- * @param {string} name - Attribute name to be tested
1648
- * @returns {boolean} Result
1670
+ * Checks if an attribute is a valid ARIA attribute
1671
+ * @param name - Attribute name to test
1672
+ * @returns Whether the attribute is a valid ARIA attribute
1649
1673
  */
1650
1674
  function isValidAriaAttribute(name$2) {
1651
1675
  return ARIA_PROPERTIES.some((element) => element === name$2);
1652
1676
  }
1653
1677
  /**
1654
- * Extracts the tag name for the JSXAttribute
1655
- * @param node - JSXAttribute being tested.
1656
- * @returns tag name
1678
+ * Gets the tag name for a JSXAttribute
1679
+ * @param node - JSXAttribute to get tag name from
1680
+ * @returns Tag name or null
1657
1681
  */
1658
1682
  function getTagName(node) {
1659
1683
  if (node?.parent?.name) return node.parent.name.name;
1660
1684
  return null;
1661
1685
  }
1662
1686
  /**
1663
- * Test wether the tag name for the JSXAttribute is
1664
- * something like <Foo.bar />
1665
- * @param node - JSXAttribute being tested.
1666
- * @returns result
1687
+ * Checks if the tag name has a dot (member expression)
1688
+ * @param node - JSXAttribute to check
1689
+ * @returns Whether the tag name has a dot
1667
1690
  */
1668
1691
  function tagNameHasDot(node) {
1669
1692
  return !!(node.parent?.name && node.parent.name.type === "JSXMemberExpression");
1670
1693
  }
1671
1694
  /**
1672
- * Get the standard name of the attribute.
1673
- * @param name - Name of the attribute.
1674
- * @param context - eslint context
1675
- * @returns The standard name of the attribute, or undefined if no standard name was found.
1695
+ * Gets the standard name of an attribute
1696
+ * @param name - Attribute name
1697
+ * @param context - ESLint context
1698
+ * @returns Standard name or undefined
1676
1699
  */
1677
1700
  function getStandardName(name$2, context) {
1678
1701
  if (has(DOM_ATTRIBUTE_NAMES, name$2)) return DOM_ATTRIBUTE_NAMES[name$2];
@@ -1680,6 +1703,35 @@ function getStandardName(name$2, context) {
1680
1703
  const names = getDOMPropertyNames(context);
1681
1704
  return names.find((element) => element.toLowerCase() === name$2.toLowerCase());
1682
1705
  }
1706
+ /**
1707
+ * Checks if an object has a property
1708
+ * @param obj - Object to check
1709
+ * @param key - Key to check for
1710
+ * @returns Whether the object has the property
1711
+ */
1712
+ function has(obj, key) {
1713
+ return Object.hasOwn(obj, key);
1714
+ }
1715
+ /**
1716
+ * Gets text of a node
1717
+ * @param context - ESLint context
1718
+ * @param node - Node to get text from
1719
+ * @returns Node's text
1720
+ */
1721
+ function getText(context, node) {
1722
+ return context.sourceCode.getText(node);
1723
+ }
1724
+ /**
1725
+ * Tests React version against a comparator
1726
+ * @param context - ESLint context
1727
+ * @param comparator - Comparison operator
1728
+ * @param version - Version to compare against
1729
+ * @returns Comparison result
1730
+ */
1731
+ function testReactVersion(context, comparator, version$1) {
1732
+ const { version: localVersion } = getSettingsFromContext(context);
1733
+ return compare(localVersion, version$1, comparator);
1734
+ }
1683
1735
  const messages = {
1684
1736
  dataLowercaseRequired: "React does not recognize data-* props with uppercase characters on a DOM element. Found '{{name}}', use '{{lowerCaseName}}' instead",
1685
1737
  invalidPropOnTag: "Invalid property '{{name}}' found on tag '{{tagName}}', but it is only allowed on: {{allowedTags}}",
@@ -1711,11 +1763,24 @@ var no_unknown_property_default = createRule({
1711
1763
  create: create$4,
1712
1764
  defaultOptions: []
1713
1765
  });
1766
+ /**
1767
+ * Create function for the ESLint rule
1768
+ * @param context - ESLint rule context
1769
+ * @returns Rule listener
1770
+ */
1714
1771
  function create$4(context) {
1715
1772
  const report = Reporter.make(context);
1773
+ /**
1774
+ * Gets the ignore configuration from rule options
1775
+ * @returns Array of attribute names to ignore
1776
+ */
1716
1777
  function getIgnoreConfig() {
1717
1778
  return context.options[0]?.ignore || DEFAULTS.ignore;
1718
1779
  }
1780
+ /**
1781
+ * Gets the requireDataLowercase option from rule options
1782
+ * @returns Whether data attributes must be lowercase
1783
+ */
1719
1784
  function getRequireDataLowercase() {
1720
1785
  return context.options[0] && typeof context.options[0].requireDataLowercase !== "undefined" ? !!context.options[0].requireDataLowercase : DEFAULTS.requireDataLowercase;
1721
1786
  }
@@ -1754,8 +1819,8 @@ function create$4(context) {
1754
1819
  return;
1755
1820
  }
1756
1821
  const standardName = getStandardName(name$2, context);
1757
- const hasStandardNameButIsNotUsed = standardName && standardName !== name$2;
1758
- const usesStandardName = standardName && standardName === name$2;
1822
+ const hasStandardNameButIsNotUsed = !!standardName && standardName !== name$2;
1823
+ const usesStandardName = !!standardName && standardName === name$2;
1759
1824
  if (usesStandardName) return;
1760
1825
  if (hasStandardNameButIsNotUsed) {
1761
1826
  report.send({
@@ -1778,16 +1843,6 @@ function create$4(context) {
1778
1843
  });
1779
1844
  } };
1780
1845
  }
1781
- function has(obj, key) {
1782
- return Object.hasOwn(obj, key);
1783
- }
1784
- function getText(context, node) {
1785
- return context.sourceCode.getText(node);
1786
- }
1787
- function testReactVersion(context, comparator, version$1) {
1788
- const { version: localVersion } = getSettingsFromContext(context);
1789
- return compare(localVersion, version$1, comparator);
1790
- }
1791
1846
 
1792
1847
  //#endregion
1793
1848
  //#region src/rules/no-unsafe-iframe-sandbox.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-dom",
3
- "version": "2.0.0-next.154",
3
+ "version": "2.0.0-next.156",
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.0-next.154",
45
- "@eslint-react/core": "2.0.0-next.154",
46
- "@eslint-react/eff": "2.0.0-next.154",
47
- "@eslint-react/shared": "2.0.0-next.154",
48
- "@eslint-react/var": "2.0.0-next.154",
49
- "@eslint-react/kit": "2.0.0-next.154"
44
+ "@eslint-react/ast": "2.0.0-next.156",
45
+ "@eslint-react/core": "2.0.0-next.156",
46
+ "@eslint-react/eff": "2.0.0-next.156",
47
+ "@eslint-react/shared": "2.0.0-next.156",
48
+ "@eslint-react/var": "2.0.0-next.156",
49
+ "@eslint-react/kit": "2.0.0-next.156"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/react": "^19.1.12",