eslint-plugin-react-dom 2.0.0-beta.18 → 2.0.0-beta.2

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 (3) hide show
  1. package/dist/index.d.ts +19 -6
  2. package/dist/index.js +142 -119
  3. package/package.json +15 -15
package/dist/index.d.ts CHANGED
@@ -1,6 +1,19 @@
1
+ import { CamelCase } from 'string-ts';
1
2
  import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
2
3
  import { RulePreset } from '@eslint-react/kit';
3
4
 
5
+ declare const RULE_NAME$2 = "no-unsafe-target-blank";
6
+ type MessageID$2 = CamelCase<typeof RULE_NAME$2> | RuleSuggestMessageID$2;
7
+ type RuleSuggestMessageID$2 = "addRelNoreferrerNoopener";
8
+
9
+ declare const RULE_NAME$1 = "no-missing-iframe-sandbox";
10
+ type MessageID$1 = CamelCase<typeof RULE_NAME$1> | RuleSuggestMessageID$1;
11
+ type RuleSuggestMessageID$1 = "addIframeSandbox";
12
+
13
+ declare const RULE_NAME = "no-missing-button-type";
14
+ type MessageID = CamelCase<typeof RULE_NAME> | RuleSuggestMessageID;
15
+ type RuleSuggestMessageID = "addButtonType";
16
+
4
17
  declare const _default: {
5
18
  configs: {
6
19
  recommended: {
@@ -16,15 +29,15 @@ declare const _default: {
16
29
  readonly "no-find-dom-node": _typescript_eslint_utils_ts_eslint.RuleModule<"noFindDomNode", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
17
30
  readonly "no-flush-sync": _typescript_eslint_utils_ts_eslint.RuleModule<"noFlushSync", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
18
31
  readonly "no-hydrate": _typescript_eslint_utils_ts_eslint.RuleModule<"noHydrate", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
19
- readonly "no-missing-button-type": _typescript_eslint_utils_ts_eslint.RuleModule<"noMissingButtonType", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
20
- readonly "no-missing-iframe-sandbox": _typescript_eslint_utils_ts_eslint.RuleModule<"noMissingIframeSandbox", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
32
+ readonly "no-missing-button-type": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
33
+ readonly "no-missing-iframe-sandbox": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
21
34
  readonly "no-namespace": _typescript_eslint_utils_ts_eslint.RuleModule<"noNamespace", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
22
35
  readonly "no-render": _typescript_eslint_utils_ts_eslint.RuleModule<"noRender", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
23
36
  readonly "no-render-return-value": _typescript_eslint_utils_ts_eslint.RuleModule<"noRenderReturnValue", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
24
37
  readonly "no-script-url": _typescript_eslint_utils_ts_eslint.RuleModule<"noScriptUrl", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
25
38
  readonly "no-unknown-property": _typescript_eslint_utils_ts_eslint.RuleModule<"dataLowercaseRequired" | "invalidPropOnTag" | "unknownProp" | "unknownPropWithStandardName", unknown[], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
26
39
  readonly "no-unsafe-iframe-sandbox": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnsafeIframeSandbox", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
27
- readonly "no-unsafe-target-blank": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnsafeTargetBlank", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
40
+ readonly "no-unsafe-target-blank": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
28
41
  readonly "no-use-form-state": _typescript_eslint_utils_ts_eslint.RuleModule<"noUseFormState", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
29
42
  readonly "no-void-elements-with-children": _typescript_eslint_utils_ts_eslint.RuleModule<"noVoidElementsWithChildren", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
30
43
  };
@@ -48,15 +61,15 @@ declare const _default: {
48
61
  readonly "no-find-dom-node": _typescript_eslint_utils_ts_eslint.RuleModule<"noFindDomNode", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
49
62
  readonly "no-flush-sync": _typescript_eslint_utils_ts_eslint.RuleModule<"noFlushSync", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
50
63
  readonly "no-hydrate": _typescript_eslint_utils_ts_eslint.RuleModule<"noHydrate", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
51
- readonly "no-missing-button-type": _typescript_eslint_utils_ts_eslint.RuleModule<"noMissingButtonType", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
52
- readonly "no-missing-iframe-sandbox": _typescript_eslint_utils_ts_eslint.RuleModule<"noMissingIframeSandbox", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
64
+ readonly "no-missing-button-type": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
65
+ readonly "no-missing-iframe-sandbox": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
53
66
  readonly "no-namespace": _typescript_eslint_utils_ts_eslint.RuleModule<"noNamespace", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
54
67
  readonly "no-render": _typescript_eslint_utils_ts_eslint.RuleModule<"noRender", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
55
68
  readonly "no-render-return-value": _typescript_eslint_utils_ts_eslint.RuleModule<"noRenderReturnValue", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
56
69
  readonly "no-script-url": _typescript_eslint_utils_ts_eslint.RuleModule<"noScriptUrl", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
57
70
  readonly "no-unknown-property": _typescript_eslint_utils_ts_eslint.RuleModule<"dataLowercaseRequired" | "invalidPropOnTag" | "unknownProp" | "unknownPropWithStandardName", unknown[], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
58
71
  readonly "no-unsafe-iframe-sandbox": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnsafeIframeSandbox", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
59
- readonly "no-unsafe-target-blank": _typescript_eslint_utils_ts_eslint.RuleModule<"noUnsafeTargetBlank", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
72
+ readonly "no-unsafe-target-blank": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
60
73
  readonly "no-use-form-state": _typescript_eslint_utils_ts_eslint.RuleModule<"noUseFormState", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
61
74
  readonly "no-void-elements-with-children": _typescript_eslint_utils_ts_eslint.RuleModule<"noVoidElementsWithChildren", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
62
75
  };
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { getDocsUrl, getSettingsFromContext, DEFAULT_ESLINT_REACT_SETTINGS } from '@eslint-react/shared';
2
2
  import * as ER from '@eslint-react/core';
3
3
  import { ESLintUtils } from '@typescript-eslint/utils';
4
+ import { unit } from '@eslint-react/eff';
4
5
  import * as AST from '@eslint-react/ast';
5
6
  import { AST_NODE_TYPES } from '@typescript-eslint/types';
6
7
  import { compare } from 'compare-versions';
7
8
  import { RegExp, Reporter } from '@eslint-react/kit';
8
- import { _ } from '@eslint-react/eff';
9
9
 
10
10
  var __defProp = Object.defineProperty;
11
11
  var __export = (target, all) => {
@@ -44,7 +44,7 @@ var settings = {
44
44
 
45
45
  // package.json
46
46
  var name2 = "eslint-plugin-react-dom";
47
- var version = "2.0.0-beta.18";
47
+ var version = "2.0.0-beta.2";
48
48
  function createJsxElementResolver(context) {
49
49
  const { components, polymorphicPropName } = getSettingsFromContext(context);
50
50
  return {
@@ -89,6 +89,39 @@ var createRule = ESLintUtils.RuleCreator(getDocsUrl("dom"));
89
89
  function findCustomComponentProp(name3, props) {
90
90
  return props.findLast((a) => a.as === name3);
91
91
  }
92
+ function resolveAttribute(context, attributes, elementNode, attributeName) {
93
+ const customComponentProp = findCustomComponentProp(attributeName, attributes);
94
+ const propNameOnJsx = customComponentProp?.name ?? attributeName;
95
+ const attribute = ER.getAttribute(
96
+ context,
97
+ propNameOnJsx,
98
+ elementNode.openingElement.attributes,
99
+ context.sourceCode.getScope(elementNode)
100
+ );
101
+ if (attribute == null) {
102
+ return {
103
+ attribute: unit,
104
+ attributeName: propNameOnJsx,
105
+ attributeValue: unit,
106
+ attributeValueString: customComponentProp?.defaultValue
107
+ };
108
+ }
109
+ const attributeValue = ER.getAttributeValue(context, attribute, propNameOnJsx);
110
+ if (attributeValue.kind === "some" && typeof attributeValue.value === "string") {
111
+ return {
112
+ attribute,
113
+ attributeName: propNameOnJsx,
114
+ attributeValue,
115
+ attributeValueString: attributeValue.value
116
+ };
117
+ }
118
+ return {
119
+ attribute,
120
+ attributeName: propNameOnJsx,
121
+ attributeValue: unit,
122
+ attributeValueString: customComponentProp?.defaultValue ?? unit
123
+ };
124
+ }
92
125
 
93
126
  // src/rules/no-dangerously-set-innerhtml.ts
94
127
  var RULE_NAME = "no-dangerously-set-innerhtml";
@@ -322,8 +355,13 @@ function getFix(context, node) {
322
355
  ];
323
356
  };
324
357
  }
358
+
359
+ // src/rules/no-missing-button-type.ts
325
360
  var RULE_NAME6 = "no-missing-button-type";
326
- var RULE_FEATURES6 = [];
361
+ var RULE_FEATURES6 = [
362
+ "FIX"
363
+ ];
364
+ var BUTTON_TYPES = ["button", "submit", "reset"];
327
365
  var no_missing_button_type_default = createRule({
328
366
  meta: {
329
367
  type: "problem",
@@ -331,7 +369,9 @@ var no_missing_button_type_default = createRule({
331
369
  description: "Enforces explicit `type` attribute for `button` elements.",
332
370
  [Symbol.for("rule_features")]: RULE_FEATURES6
333
371
  },
372
+ hasSuggestions: true,
334
373
  messages: {
374
+ addButtonType: "Add 'type' attribute with value '{{type}}'.",
335
375
  noMissingButtonType: "Add missing 'type' attribute on 'button' component."
336
376
  },
337
377
  schema: []
@@ -346,60 +386,42 @@ function create6(context) {
346
386
  JSXElement(node) {
347
387
  const { attributes, domElementType } = resolver.resolve(node);
348
388
  if (domElementType !== "button") return;
349
- const customComponentProp = findCustomComponentProp("type", attributes);
350
- const propNameOnJsx = customComponentProp?.name ?? "type";
351
- const attributeNode = ER.getAttribute(
352
- context,
353
- propNameOnJsx,
354
- node.openingElement.attributes,
355
- context.sourceCode.getScope(node)
356
- );
357
- if (attributeNode != null) {
358
- const attributeValue = ER.getAttributeValue(
359
- context,
360
- attributeNode,
361
- propNameOnJsx
362
- );
363
- if (attributeValue.kind === "some" && typeof attributeValue.value !== "string") {
364
- context.report({
365
- messageId: "noMissingButtonType",
366
- node: attributeNode
367
- });
368
- }
369
- return;
370
- }
371
- if (typeof customComponentProp?.defaultValue !== "string") {
389
+ const typeAttribute = resolveAttribute(context, attributes, node, "type");
390
+ if (typeAttribute.attributeValueString != null) return;
391
+ if (typeAttribute.attribute == null) {
372
392
  context.report({
373
393
  messageId: "noMissingButtonType",
374
- node
394
+ node: node.openingElement,
395
+ suggest: getSuggest((type) => (fixer) => {
396
+ return fixer.insertTextAfter(node.openingElement.name, ` ${typeAttribute.attributeName}="${type}"`);
397
+ })
375
398
  });
399
+ return;
376
400
  }
401
+ context.report({
402
+ messageId: "noMissingButtonType",
403
+ node: typeAttribute.attributeValue?.node ?? typeAttribute.attribute,
404
+ suggest: getSuggest((type) => (fixer) => {
405
+ if (typeAttribute.attribute == null) return null;
406
+ return fixer.replaceText(typeAttribute.attribute, `${typeAttribute.attributeName}="${type}"`);
407
+ })
408
+ });
377
409
  }
378
410
  };
379
411
  }
412
+ function getSuggest(getFix4) {
413
+ return BUTTON_TYPES.map((type) => ({
414
+ messageId: "addButtonType",
415
+ data: { type },
416
+ fix: getFix4(type)
417
+ }));
418
+ }
419
+
420
+ // src/rules/no-missing-iframe-sandbox.ts
380
421
  var RULE_NAME7 = "no-missing-iframe-sandbox";
381
- var RULE_FEATURES7 = [];
382
- var validTypes = [
383
- "",
384
- "allow-downloads",
385
- "allow-downloads-without-user-activation",
386
- "allow-forms",
387
- "allow-modals",
388
- "allow-orientation-lock",
389
- "allow-pointer-lock",
390
- "allow-popups",
391
- "allow-popups-to-escape-sandbox",
392
- "allow-presentation",
393
- "allow-same-origin",
394
- "allow-scripts",
395
- "allow-storage-access-by-user-activation",
396
- "allow-top-navigation",
397
- "allow-top-navigation-by-user-activation",
398
- "allow-top-navigation-to-custom-protocols"
422
+ var RULE_FEATURES7 = [
423
+ "FIX"
399
424
  ];
400
- function hasValidSandBox(value) {
401
- return typeof value === "string" && value.split(" ").every((value2) => validTypes.some((valid) => valid === value2));
402
- }
403
425
  var no_missing_iframe_sandbox_default = createRule({
404
426
  meta: {
405
427
  type: "problem",
@@ -407,7 +429,10 @@ var no_missing_iframe_sandbox_default = createRule({
407
429
  description: "Enforces explicit `sandbox` attribute for `iframe` elements.",
408
430
  [Symbol.for("rule_features")]: RULE_FEATURES7
409
431
  },
432
+ fixable: "code",
433
+ hasSuggestions: true,
410
434
  messages: {
435
+ addIframeSandbox: "Add 'sandbox' attribute with value '{{value}}'.",
411
436
  noMissingIframeSandbox: "Add missing 'sandbox' attribute on 'iframe' component."
412
437
  },
413
438
  schema: []
@@ -422,33 +447,34 @@ function create7(context) {
422
447
  JSXElement(node) {
423
448
  const { attributes, domElementType } = resolver.resolve(node);
424
449
  if (domElementType !== "iframe") return;
425
- const customComponentProp = findCustomComponentProp("sandbox", attributes);
426
- const propNameOnJsx = customComponentProp?.name ?? "sandbox";
427
- const attributeNode = ER.getAttribute(
428
- context,
429
- propNameOnJsx,
430
- node.openingElement.attributes,
431
- context.sourceCode.getScope(node)
432
- );
433
- if (attributeNode != null) {
434
- const attributeValue = ER.getAttributeValue(
435
- context,
436
- attributeNode,
437
- propNameOnJsx
438
- );
439
- if (attributeValue.kind === "some" && hasValidSandBox(attributeValue.value)) return;
450
+ const sandboxAttribute = resolveAttribute(context, attributes, node, "sandbox");
451
+ if (sandboxAttribute.attributeValueString != null) return;
452
+ if (sandboxAttribute.attribute == null) {
440
453
  context.report({
441
454
  messageId: "noMissingIframeSandbox",
442
- node: attributeNode
455
+ node: node.openingElement,
456
+ suggest: [{
457
+ messageId: "addIframeSandbox",
458
+ data: { value: "" },
459
+ fix(fixer) {
460
+ return fixer.insertTextAfter(node.openingElement.name, ` ${sandboxAttribute.attributeName}=""`);
461
+ }
462
+ }]
443
463
  });
444
464
  return;
445
465
  }
446
- if (!hasValidSandBox(customComponentProp?.defaultValue)) {
447
- context.report({
448
- messageId: "noMissingIframeSandbox",
449
- node
450
- });
451
- }
466
+ context.report({
467
+ messageId: "noMissingIframeSandbox",
468
+ node: sandboxAttribute.attributeValue?.node ?? sandboxAttribute.attribute,
469
+ suggest: [{
470
+ messageId: "addIframeSandbox",
471
+ data: { value: "" },
472
+ fix(fixer) {
473
+ if (sandboxAttribute.attribute == null) return null;
474
+ return fixer.replaceText(sandboxAttribute.attribute, `${sandboxAttribute.attributeName}=""`);
475
+ }
476
+ }]
477
+ });
452
478
  }
453
479
  };
454
480
  }
@@ -1722,12 +1748,14 @@ function testReactVersion(context, comparator, version2) {
1722
1748
  const { version: localVersion } = getSettingsFromContext(context);
1723
1749
  return compare(localVersion, version2, comparator);
1724
1750
  }
1751
+
1752
+ // src/rules/no-unsafe-iframe-sandbox.ts
1725
1753
  var RULE_NAME13 = "no-unsafe-iframe-sandbox";
1726
1754
  var RULE_FEATURES12 = [];
1727
1755
  var unsafeSandboxValues = [
1728
1756
  ["allow-scripts", "allow-same-origin"]
1729
1757
  ];
1730
- function hasSafeSandbox(value) {
1758
+ function isSafeSandbox(value) {
1731
1759
  if (typeof value !== "string") return false;
1732
1760
  return !unsafeSandboxValues.some((values) => {
1733
1761
  return values.every((v) => value.includes(v));
@@ -1755,40 +1783,22 @@ function create13(context) {
1755
1783
  JSXElement(node) {
1756
1784
  const { attributes, domElementType } = resolver.resolve(node);
1757
1785
  if (domElementType !== "iframe") return;
1758
- const customComponentProp = findCustomComponentProp("sandbox", attributes);
1759
- const propNameOnJsx = customComponentProp?.name ?? "sandbox";
1760
- const attributeNode = ER.getAttribute(
1761
- context,
1762
- propNameOnJsx,
1763
- node.openingElement.attributes,
1764
- context.sourceCode.getScope(node)
1765
- );
1766
- if (attributeNode != null) {
1767
- const attributeValue = ER.getAttributeValue(
1768
- context,
1769
- attributeNode,
1770
- propNameOnJsx
1771
- );
1772
- if (attributeValue.kind === "some" && !hasSafeSandbox(attributeValue.value)) {
1773
- context.report({
1774
- messageId: "noUnsafeIframeSandbox",
1775
- node: attributeNode
1776
- });
1777
- return;
1778
- }
1779
- }
1780
- if (customComponentProp?.defaultValue == null) return;
1781
- if (!hasSafeSandbox(customComponentProp.defaultValue)) {
1786
+ const sandboxAttribute = resolveAttribute(context, attributes, node, "sandbox");
1787
+ if (!isSafeSandbox(sandboxAttribute.attributeValueString)) {
1782
1788
  context.report({
1783
1789
  messageId: "noUnsafeIframeSandbox",
1784
- node
1790
+ node: sandboxAttribute.attributeValue?.node ?? sandboxAttribute.attribute ?? node
1785
1791
  });
1786
1792
  }
1787
1793
  }
1788
1794
  };
1789
1795
  }
1796
+
1797
+ // src/rules/no-unsafe-target-blank.ts
1790
1798
  var RULE_NAME14 = "no-unsafe-target-blank";
1791
- var RULE_FEATURES13 = [];
1799
+ var RULE_FEATURES13 = [
1800
+ "FIX"
1801
+ ];
1792
1802
  function isExternalLinkLike(value) {
1793
1803
  if (value == null) return false;
1794
1804
  return value.startsWith("https://") || /^(?:\w+:|\/\/)/u.test(value);
@@ -1804,7 +1814,10 @@ var no_unsafe_target_blank_default = createRule({
1804
1814
  description: 'Disallow `target="_blank"` without `rel="noreferrer noopener"`.',
1805
1815
  [Symbol.for("rule_features")]: RULE_FEATURES13
1806
1816
  },
1817
+ fixable: "code",
1818
+ hasSuggestions: true,
1807
1819
  messages: {
1820
+ addRelNoreferrerNoopener: `Add 'rel="noreferrer noopener"' to the link to prevent security risks.`,
1808
1821
  noUnsafeTargetBlank: `Using 'target="_blank"' on an external link without 'rel="noreferrer noopener"' is a security risk.`
1809
1822
  },
1810
1823
  schema: []
@@ -1819,35 +1832,44 @@ function create14(context) {
1819
1832
  JSXElement(node) {
1820
1833
  const { attributes, domElementType } = resolver.resolve(node);
1821
1834
  if (domElementType !== "a") return;
1822
- const elementScope = context.sourceCode.getScope(node);
1823
- const getAttributeStringValue = (name3) => {
1824
- const customComponentProp = findCustomComponentProp(name3, attributes);
1825
- const propNameOnJsx = customComponentProp?.name ?? name3;
1826
- const attributeNode = ER.getAttribute(
1827
- context,
1828
- propNameOnJsx,
1829
- node.openingElement.attributes,
1830
- elementScope
1831
- );
1832
- if (attributeNode == null) return customComponentProp?.defaultValue;
1833
- const attributeValue = ER.getAttributeValue(context, attributeNode, propNameOnJsx);
1834
- if (attributeValue.kind === "some" && typeof attributeValue.value === "string") {
1835
- return attributeValue.value;
1836
- }
1837
- return _;
1838
- };
1839
- if (getAttributeStringValue("target") !== "_blank") {
1835
+ const targetAttribute = resolveAttribute(context, attributes, node, "target");
1836
+ if (targetAttribute.attributeValueString !== "_blank") {
1840
1837
  return;
1841
1838
  }
1842
- if (!isExternalLinkLike(getAttributeStringValue("href"))) {
1839
+ const hrefAttribute = resolveAttribute(context, attributes, node, "href");
1840
+ if (!isExternalLinkLike(hrefAttribute.attributeValueString)) {
1843
1841
  return;
1844
1842
  }
1845
- if (isSafeRel(getAttributeStringValue("rel"))) {
1843
+ const relAttribute = resolveAttribute(context, attributes, node, "rel");
1844
+ if (isSafeRel(relAttribute.attributeValueString)) {
1845
+ return;
1846
+ }
1847
+ if (relAttribute.attribute == null) {
1848
+ context.report({
1849
+ messageId: "noUnsafeTargetBlank",
1850
+ node: node.openingElement,
1851
+ suggest: [{
1852
+ messageId: "addRelNoreferrerNoopener",
1853
+ fix(fixer) {
1854
+ return fixer.insertTextAfter(
1855
+ node.openingElement.name,
1856
+ ` ${relAttribute.attributeName}="noreferrer noopener"`
1857
+ );
1858
+ }
1859
+ }]
1860
+ });
1846
1861
  return;
1847
1862
  }
1848
1863
  context.report({
1849
1864
  messageId: "noUnsafeTargetBlank",
1850
- node
1865
+ node: relAttribute.attributeValue?.node ?? relAttribute.attribute,
1866
+ suggest: [{
1867
+ messageId: "addRelNoreferrerNoopener",
1868
+ fix(fixer) {
1869
+ if (relAttribute.attribute == null) return null;
1870
+ return fixer.replaceText(relAttribute.attribute, `${relAttribute.attributeName}="noreferrer noopener"`);
1871
+ }
1872
+ }]
1851
1873
  });
1852
1874
  }
1853
1875
  };
@@ -1965,9 +1987,10 @@ var no_void_elements_with_children_default = createRule({
1965
1987
  defaultOptions: []
1966
1988
  });
1967
1989
  function create16(context) {
1990
+ const resolver = createJsxElementResolver(context);
1968
1991
  return {
1969
1992
  JSXElement(node) {
1970
- const elementName = ER.getElementType(context, node);
1993
+ const { domElementType: elementName } = resolver.resolve(node);
1971
1994
  if (elementName.length === 0 || !voidElements.has(elementName)) {
1972
1995
  return;
1973
1996
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-dom",
3
- "version": "2.0.0-beta.18",
3
+ "version": "2.0.0-beta.2",
4
4
  "description": "ESLint React's ESLint plugin for React DOM related rules.",
5
5
  "keywords": [
6
6
  "react",
@@ -35,27 +35,27 @@
35
35
  "./package.json"
36
36
  ],
37
37
  "dependencies": {
38
- "@typescript-eslint/scope-manager": "^8.32.0",
39
- "@typescript-eslint/types": "^8.32.0",
40
- "@typescript-eslint/utils": "^8.32.0",
38
+ "@typescript-eslint/scope-manager": "^8.35.0",
39
+ "@typescript-eslint/types": "^8.35.0",
40
+ "@typescript-eslint/utils": "^8.35.0",
41
41
  "compare-versions": "^6.1.1",
42
42
  "string-ts": "^2.2.1",
43
- "ts-pattern": "^5.7.0",
44
- "@eslint-react/ast": "2.0.0-beta.18",
45
- "@eslint-react/kit": "2.0.0-beta.18",
46
- "@eslint-react/shared": "2.0.0-beta.18",
47
- "@eslint-react/var": "2.0.0-beta.18",
48
- "@eslint-react/core": "2.0.0-beta.18",
49
- "@eslint-react/eff": "2.0.0-beta.18"
43
+ "ts-pattern": "^5.7.1",
44
+ "@eslint-react/ast": "2.0.0-beta.2",
45
+ "@eslint-react/core": "2.0.0-beta.2",
46
+ "@eslint-react/kit": "2.0.0-beta.2",
47
+ "@eslint-react/eff": "2.0.0-beta.2",
48
+ "@eslint-react/shared": "2.0.0-beta.2",
49
+ "@eslint-react/var": "2.0.0-beta.2"
50
50
  },
51
51
  "devDependencies": {
52
- "@types/react": "^19.1.3",
53
- "@types/react-dom": "^19.1.4",
54
- "tsup": "^8.4.0",
52
+ "@types/react": "^19.1.8",
53
+ "@types/react-dom": "^19.1.6",
54
+ "tsup": "^8.5.0",
55
55
  "@local/configs": "0.0.0"
56
56
  },
57
57
  "peerDependencies": {
58
- "eslint": "^9.26.0",
58
+ "eslint": "^9.29.0",
59
59
  "typescript": "^4.9.5 || ^5.4.5"
60
60
  },
61
61
  "peerDependenciesMeta": {