eslint-plugin-react-dom 2.0.0-next.14 → 2.0.0-next.141

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 +21 -6
  2. package/dist/index.js +224 -150
  3. package/package.json +15 -16
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,16 @@ 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>;
38
+ readonly "no-string-style-prop": _typescript_eslint_utils_ts_eslint.RuleModule<"noStringStyleProp", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
25
39
  readonly "no-unknown-property": _typescript_eslint_utils_ts_eslint.RuleModule<"dataLowercaseRequired" | "invalidPropOnTag" | "unknownProp" | "unknownPropWithStandardName", unknown[], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
26
40
  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>;
41
+ readonly "no-unsafe-target-blank": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
28
42
  readonly "no-use-form-state": _typescript_eslint_utils_ts_eslint.RuleModule<"noUseFormState", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
29
43
  readonly "no-void-elements-with-children": _typescript_eslint_utils_ts_eslint.RuleModule<"noVoidElementsWithChildren", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
30
44
  };
@@ -48,15 +62,16 @@ declare const _default: {
48
62
  readonly "no-find-dom-node": _typescript_eslint_utils_ts_eslint.RuleModule<"noFindDomNode", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
49
63
  readonly "no-flush-sync": _typescript_eslint_utils_ts_eslint.RuleModule<"noFlushSync", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
50
64
  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>;
65
+ readonly "no-missing-button-type": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
66
+ readonly "no-missing-iframe-sandbox": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$1, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
53
67
  readonly "no-namespace": _typescript_eslint_utils_ts_eslint.RuleModule<"noNamespace", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
54
68
  readonly "no-render": _typescript_eslint_utils_ts_eslint.RuleModule<"noRender", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
55
69
  readonly "no-render-return-value": _typescript_eslint_utils_ts_eslint.RuleModule<"noRenderReturnValue", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
56
70
  readonly "no-script-url": _typescript_eslint_utils_ts_eslint.RuleModule<"noScriptUrl", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
71
+ readonly "no-string-style-prop": _typescript_eslint_utils_ts_eslint.RuleModule<"noStringStyleProp", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
57
72
  readonly "no-unknown-property": _typescript_eslint_utils_ts_eslint.RuleModule<"dataLowercaseRequired" | "invalidPropOnTag" | "unknownProp" | "unknownPropWithStandardName", unknown[], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
58
73
  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>;
74
+ readonly "no-unsafe-target-blank": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID$2, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
60
75
  readonly "no-use-form-state": _typescript_eslint_utils_ts_eslint.RuleModule<"noUseFormState", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
61
76
  readonly "no-void-elements-with-children": _typescript_eslint_utils_ts_eslint.RuleModule<"noVoidElementsWithChildren", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
62
77
  };
package/dist/index.js CHANGED
@@ -1,11 +1,10 @@
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 * as AST from '@eslint-react/ast';
4
+ import { unit } from '@eslint-react/eff';
5
5
  import { AST_NODE_TYPES } from '@typescript-eslint/types';
6
6
  import { compare } from 'compare-versions';
7
7
  import { RegExp, Reporter } from '@eslint-react/kit';
8
- import { _ } from '@eslint-react/eff';
9
8
 
10
9
  var __defProp = Object.defineProperty;
11
10
  var __export = (target, all) => {
@@ -33,6 +32,7 @@ var rules = {
33
32
  "react-dom/no-render": "error",
34
33
  "react-dom/no-render-return-value": "error",
35
34
  "react-dom/no-script-url": "warn",
35
+ "react-dom/no-string-style-prop": "error",
36
36
  "react-dom/no-unsafe-iframe-sandbox": "warn",
37
37
  "react-dom/no-unsafe-target-blank": "warn",
38
38
  "react-dom/no-use-form-state": "error",
@@ -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-next.14";
47
+ var version = "2.0.0-next.141";
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";
@@ -153,7 +186,7 @@ function create2(context) {
153
186
  JSXElement(node) {
154
187
  const attributes = node.openingElement.attributes;
155
188
  const initialScope = context.sourceCode.getScope(node);
156
- const hasChildren = hasChildrenWithin(node) || ER.hasAttribute(context, "children", attributes, initialScope);
189
+ const hasChildren = node.children.some(isSignificantChildren) || ER.hasAttribute(context, "children", attributes, initialScope);
157
190
  if (hasChildren && ER.hasAttribute(context, dangerouslySetInnerHTML2, attributes, initialScope)) {
158
191
  context.report({
159
192
  messageId: "noDangerouslySetInnerhtmlWithChildren",
@@ -163,8 +196,14 @@ function create2(context) {
163
196
  }
164
197
  };
165
198
  }
166
- function hasChildrenWithin(node) {
167
- return node.children.length > 0 && node.children[0] != null && !AST.isLineBreak(node.children[0]);
199
+ function isWhiteSpace(node) {
200
+ return typeof node.value === "string" && node.raw.trim() === "";
201
+ }
202
+ function isPaddingSpaces(node) {
203
+ return ER.isJsxText(node) && isWhiteSpace(node) && node.raw.includes("\n");
204
+ }
205
+ function isSignificantChildren(node) {
206
+ return node.type !== AST_NODE_TYPES.JSXText || !isPaddingSpaces(node);
168
207
  }
169
208
  var RULE_NAME3 = "no-find-dom-node";
170
209
  var RULE_FEATURES3 = [];
@@ -322,8 +361,13 @@ function getFix(context, node) {
322
361
  ];
323
362
  };
324
363
  }
364
+
365
+ // src/rules/no-missing-button-type.ts
325
366
  var RULE_NAME6 = "no-missing-button-type";
326
- var RULE_FEATURES6 = [];
367
+ var RULE_FEATURES6 = [
368
+ "FIX"
369
+ ];
370
+ var BUTTON_TYPES = ["button", "submit", "reset"];
327
371
  var no_missing_button_type_default = createRule({
328
372
  meta: {
329
373
  type: "problem",
@@ -331,7 +375,9 @@ var no_missing_button_type_default = createRule({
331
375
  description: "Enforces explicit `type` attribute for `button` elements.",
332
376
  [Symbol.for("rule_features")]: RULE_FEATURES6
333
377
  },
378
+ hasSuggestions: true,
334
379
  messages: {
380
+ addButtonType: "Add 'type' attribute with value '{{type}}'.",
335
381
  noMissingButtonType: "Add missing 'type' attribute on 'button' component."
336
382
  },
337
383
  schema: []
@@ -346,60 +392,42 @@ function create6(context) {
346
392
  JSXElement(node) {
347
393
  const { attributes, domElementType } = resolver.resolve(node);
348
394
  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") {
395
+ const typeAttribute = resolveAttribute(context, attributes, node, "type");
396
+ if (typeAttribute.attributeValueString != null) return;
397
+ if (typeAttribute.attribute == null) {
372
398
  context.report({
373
399
  messageId: "noMissingButtonType",
374
- node
400
+ node: node.openingElement,
401
+ suggest: getSuggest((type) => (fixer) => {
402
+ return fixer.insertTextAfter(node.openingElement.name, ` ${typeAttribute.attributeName}="${type}"`);
403
+ })
375
404
  });
405
+ return;
376
406
  }
407
+ context.report({
408
+ messageId: "noMissingButtonType",
409
+ node: typeAttribute.attributeValue?.node ?? typeAttribute.attribute,
410
+ suggest: getSuggest((type) => (fixer) => {
411
+ if (typeAttribute.attribute == null) return null;
412
+ return fixer.replaceText(typeAttribute.attribute, `${typeAttribute.attributeName}="${type}"`);
413
+ })
414
+ });
377
415
  }
378
416
  };
379
417
  }
418
+ function getSuggest(getFix4) {
419
+ return BUTTON_TYPES.map((type) => ({
420
+ messageId: "addButtonType",
421
+ data: { type },
422
+ fix: getFix4(type)
423
+ }));
424
+ }
425
+
426
+ // src/rules/no-missing-iframe-sandbox.ts
380
427
  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"
428
+ var RULE_FEATURES7 = [
429
+ "FIX"
399
430
  ];
400
- function hasValidSandBox(value) {
401
- return typeof value === "string" && value.split(" ").every((value2) => validTypes.some((valid) => valid === value2));
402
- }
403
431
  var no_missing_iframe_sandbox_default = createRule({
404
432
  meta: {
405
433
  type: "problem",
@@ -407,7 +435,10 @@ var no_missing_iframe_sandbox_default = createRule({
407
435
  description: "Enforces explicit `sandbox` attribute for `iframe` elements.",
408
436
  [Symbol.for("rule_features")]: RULE_FEATURES7
409
437
  },
438
+ fixable: "code",
439
+ hasSuggestions: true,
410
440
  messages: {
441
+ addIframeSandbox: "Add 'sandbox' attribute with value '{{value}}'.",
411
442
  noMissingIframeSandbox: "Add missing 'sandbox' attribute on 'iframe' component."
412
443
  },
413
444
  schema: []
@@ -422,33 +453,34 @@ function create7(context) {
422
453
  JSXElement(node) {
423
454
  const { attributes, domElementType } = resolver.resolve(node);
424
455
  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;
456
+ const sandboxAttribute = resolveAttribute(context, attributes, node, "sandbox");
457
+ if (sandboxAttribute.attributeValueString != null) return;
458
+ if (sandboxAttribute.attribute == null) {
440
459
  context.report({
441
460
  messageId: "noMissingIframeSandbox",
442
- node: attributeNode
461
+ node: node.openingElement,
462
+ suggest: [{
463
+ messageId: "addIframeSandbox",
464
+ data: { value: "" },
465
+ fix(fixer) {
466
+ return fixer.insertTextAfter(node.openingElement.name, ` ${sandboxAttribute.attributeName}=""`);
467
+ }
468
+ }]
443
469
  });
444
470
  return;
445
471
  }
446
- if (!hasValidSandBox(customComponentProp?.defaultValue)) {
447
- context.report({
448
- messageId: "noMissingIframeSandbox",
449
- node
450
- });
451
- }
472
+ context.report({
473
+ messageId: "noMissingIframeSandbox",
474
+ node: sandboxAttribute.attributeValue?.node ?? sandboxAttribute.attribute,
475
+ suggest: [{
476
+ messageId: "addIframeSandbox",
477
+ data: { value: "" },
478
+ fix(fixer) {
479
+ if (sandboxAttribute.attribute == null) return null;
480
+ return fixer.replaceText(sandboxAttribute.attribute, `${sandboxAttribute.attributeName}=""`);
481
+ }
482
+ }]
483
+ });
452
484
  }
453
485
  };
454
486
  }
@@ -664,7 +696,51 @@ function create11(context) {
664
696
  }
665
697
  };
666
698
  }
667
- var RULE_NAME12 = "no-unknown-property";
699
+ var RULE_NAME12 = "no-string-style-prop";
700
+ var RULE_FEATURES12 = [];
701
+ var no_string_style_prop_default = createRule({
702
+ meta: {
703
+ type: "problem",
704
+ docs: {
705
+ description: "Disallows the use of string style prop.",
706
+ [Symbol.for("rule_features")]: RULE_FEATURES12
707
+ },
708
+ messages: {
709
+ noStringStyleProp: "Do not use string style prop. Use an object instead."
710
+ },
711
+ schema: []
712
+ },
713
+ name: RULE_NAME12,
714
+ create: create12,
715
+ defaultOptions: []
716
+ });
717
+ function create12(context) {
718
+ return {
719
+ JSXAttribute(node) {
720
+ if (node.name.name !== "style") return;
721
+ const styleText = getAttributeValueText(context, node.value);
722
+ if (styleText == null) return;
723
+ context.report({
724
+ messageId: "noStringStyleProp",
725
+ node
726
+ });
727
+ }
728
+ };
729
+ }
730
+ function getAttributeValueText(context, node) {
731
+ if (node == null) return null;
732
+ switch (true) {
733
+ case (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string"):
734
+ return context.sourceCode.getText(node);
735
+ case (node.type === AST_NODE_TYPES.JSXExpressionContainer && node.expression.type === AST_NODE_TYPES.Literal && typeof node.expression.value === "string"):
736
+ return context.sourceCode.getText(node.expression);
737
+ case (node.type === AST_NODE_TYPES.JSXExpressionContainer && node.expression.type === AST_NODE_TYPES.TemplateLiteral):
738
+ return context.sourceCode.getText(node.expression);
739
+ default:
740
+ return null;
741
+ }
742
+ }
743
+ var RULE_NAME13 = "no-unknown-property";
668
744
  var DEFAULTS = {
669
745
  ignore: [],
670
746
  requireDataLowercase: false
@@ -1627,11 +1703,11 @@ var no_unknown_property_default = createRule({
1627
1703
  }
1628
1704
  }]
1629
1705
  },
1630
- name: RULE_NAME12,
1631
- create: create12,
1706
+ name: RULE_NAME13,
1707
+ create: create13,
1632
1708
  defaultOptions: []
1633
1709
  });
1634
- function create12(context) {
1710
+ function create13(context) {
1635
1711
  const report = Reporter.make(context);
1636
1712
  function getIgnoreConfig() {
1637
1713
  return context.options[0]?.ignore || DEFAULTS.ignore;
@@ -1722,12 +1798,14 @@ function testReactVersion(context, comparator, version2) {
1722
1798
  const { version: localVersion } = getSettingsFromContext(context);
1723
1799
  return compare(localVersion, version2, comparator);
1724
1800
  }
1725
- var RULE_NAME13 = "no-unsafe-iframe-sandbox";
1726
- var RULE_FEATURES12 = [];
1801
+
1802
+ // src/rules/no-unsafe-iframe-sandbox.ts
1803
+ var RULE_NAME14 = "no-unsafe-iframe-sandbox";
1804
+ var RULE_FEATURES13 = [];
1727
1805
  var unsafeSandboxValues = [
1728
1806
  ["allow-scripts", "allow-same-origin"]
1729
1807
  ];
1730
- function hasSafeSandbox(value) {
1808
+ function isSafeSandbox(value) {
1731
1809
  if (typeof value !== "string") return false;
1732
1810
  return !unsafeSandboxValues.some((values) => {
1733
1811
  return values.every((v) => value.includes(v));
@@ -1738,57 +1816,39 @@ var no_unsafe_iframe_sandbox_default = createRule({
1738
1816
  type: "problem",
1739
1817
  docs: {
1740
1818
  description: "Enforces `sandbox` attribute for `iframe` elements is not set to unsafe combinations.",
1741
- [Symbol.for("rule_features")]: RULE_FEATURES12
1819
+ [Symbol.for("rule_features")]: RULE_FEATURES13
1742
1820
  },
1743
1821
  messages: {
1744
1822
  noUnsafeIframeSandbox: "Unsafe 'sandbox' attribute value on 'iframe' component."
1745
1823
  },
1746
1824
  schema: []
1747
1825
  },
1748
- name: RULE_NAME13,
1749
- create: create13,
1826
+ name: RULE_NAME14,
1827
+ create: create14,
1750
1828
  defaultOptions: []
1751
1829
  });
1752
- function create13(context) {
1830
+ function create14(context) {
1753
1831
  const resolver = createJsxElementResolver(context);
1754
1832
  return {
1755
1833
  JSXElement(node) {
1756
1834
  const { attributes, domElementType } = resolver.resolve(node);
1757
1835
  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)) {
1836
+ const sandboxAttribute = resolveAttribute(context, attributes, node, "sandbox");
1837
+ if (!isSafeSandbox(sandboxAttribute.attributeValueString)) {
1782
1838
  context.report({
1783
1839
  messageId: "noUnsafeIframeSandbox",
1784
- node
1840
+ node: sandboxAttribute.attributeValue?.node ?? sandboxAttribute.attribute ?? node
1785
1841
  });
1786
1842
  }
1787
1843
  }
1788
1844
  };
1789
1845
  }
1790
- var RULE_NAME14 = "no-unsafe-target-blank";
1791
- var RULE_FEATURES13 = [];
1846
+
1847
+ // src/rules/no-unsafe-target-blank.ts
1848
+ var RULE_NAME15 = "no-unsafe-target-blank";
1849
+ var RULE_FEATURES14 = [
1850
+ "FIX"
1851
+ ];
1792
1852
  function isExternalLinkLike(value) {
1793
1853
  if (value == null) return false;
1794
1854
  return value.startsWith("https://") || /^(?:\w+:|\/\/)/u.test(value);
@@ -1802,58 +1862,70 @@ var no_unsafe_target_blank_default = createRule({
1802
1862
  type: "problem",
1803
1863
  docs: {
1804
1864
  description: 'Disallow `target="_blank"` without `rel="noreferrer noopener"`.',
1805
- [Symbol.for("rule_features")]: RULE_FEATURES13
1865
+ [Symbol.for("rule_features")]: RULE_FEATURES14
1806
1866
  },
1867
+ fixable: "code",
1868
+ hasSuggestions: true,
1807
1869
  messages: {
1870
+ addRelNoreferrerNoopener: `Add 'rel="noreferrer noopener"' to the link to prevent security risks.`,
1808
1871
  noUnsafeTargetBlank: `Using 'target="_blank"' on an external link without 'rel="noreferrer noopener"' is a security risk.`
1809
1872
  },
1810
1873
  schema: []
1811
1874
  },
1812
- name: RULE_NAME14,
1813
- create: create14,
1875
+ name: RULE_NAME15,
1876
+ create: create15,
1814
1877
  defaultOptions: []
1815
1878
  });
1816
- function create14(context) {
1879
+ function create15(context) {
1817
1880
  const resolver = createJsxElementResolver(context);
1818
1881
  return {
1819
1882
  JSXElement(node) {
1820
1883
  const { attributes, domElementType } = resolver.resolve(node);
1821
1884
  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") {
1885
+ const targetAttribute = resolveAttribute(context, attributes, node, "target");
1886
+ if (targetAttribute.attributeValueString !== "_blank") {
1887
+ return;
1888
+ }
1889
+ const hrefAttribute = resolveAttribute(context, attributes, node, "href");
1890
+ if (!isExternalLinkLike(hrefAttribute.attributeValueString)) {
1840
1891
  return;
1841
1892
  }
1842
- if (!isExternalLinkLike(getAttributeStringValue("href"))) {
1893
+ const relAttribute = resolveAttribute(context, attributes, node, "rel");
1894
+ if (isSafeRel(relAttribute.attributeValueString)) {
1843
1895
  return;
1844
1896
  }
1845
- if (isSafeRel(getAttributeStringValue("rel"))) {
1897
+ if (relAttribute.attribute == null) {
1898
+ context.report({
1899
+ messageId: "noUnsafeTargetBlank",
1900
+ node: node.openingElement,
1901
+ suggest: [{
1902
+ messageId: "addRelNoreferrerNoopener",
1903
+ fix(fixer) {
1904
+ return fixer.insertTextAfter(
1905
+ node.openingElement.name,
1906
+ ` ${relAttribute.attributeName}="noreferrer noopener"`
1907
+ );
1908
+ }
1909
+ }]
1910
+ });
1846
1911
  return;
1847
1912
  }
1848
1913
  context.report({
1849
1914
  messageId: "noUnsafeTargetBlank",
1850
- node
1915
+ node: relAttribute.attributeValue?.node ?? relAttribute.attribute,
1916
+ suggest: [{
1917
+ messageId: "addRelNoreferrerNoopener",
1918
+ fix(fixer) {
1919
+ if (relAttribute.attribute == null) return null;
1920
+ return fixer.replaceText(relAttribute.attribute, `${relAttribute.attributeName}="noreferrer noopener"`);
1921
+ }
1922
+ }]
1851
1923
  });
1852
1924
  }
1853
1925
  };
1854
1926
  }
1855
- var RULE_NAME15 = "no-use-form-state";
1856
- var RULE_FEATURES14 = [
1927
+ var RULE_NAME16 = "no-use-form-state";
1928
+ var RULE_FEATURES15 = [
1857
1929
  "MOD"
1858
1930
  ];
1859
1931
  var no_use_form_state_default = createRule({
@@ -1861,7 +1933,7 @@ var no_use_form_state_default = createRule({
1861
1933
  type: "problem",
1862
1934
  docs: {
1863
1935
  description: "Replaces usages of `useFormState` with `useActionState`.",
1864
- [Symbol.for("rule_features")]: RULE_FEATURES14
1936
+ [Symbol.for("rule_features")]: RULE_FEATURES15
1865
1937
  },
1866
1938
  fixable: "code",
1867
1939
  messages: {
@@ -1869,11 +1941,11 @@ var no_use_form_state_default = createRule({
1869
1941
  },
1870
1942
  schema: []
1871
1943
  },
1872
- name: RULE_NAME15,
1873
- create: create15,
1944
+ name: RULE_NAME16,
1945
+ create: create16,
1874
1946
  defaultOptions: []
1875
1947
  });
1876
- function create15(context) {
1948
+ function create16(context) {
1877
1949
  if (!context.sourceCode.text.includes("useFormState")) return {};
1878
1950
  const settings2 = getSettingsFromContext(context);
1879
1951
  if (compare(settings2.version, "19.0.0", "<")) return {};
@@ -1928,8 +2000,8 @@ function getFix3(context, node) {
1928
2000
  ];
1929
2001
  };
1930
2002
  }
1931
- var RULE_NAME16 = "no-void-elements-with-children";
1932
- var RULE_FEATURES15 = [];
2003
+ var RULE_NAME17 = "no-void-elements-with-children";
2004
+ var RULE_FEATURES16 = [];
1933
2005
  var voidElements = /* @__PURE__ */ new Set([
1934
2006
  "area",
1935
2007
  "base",
@@ -1953,21 +2025,22 @@ var no_void_elements_with_children_default = createRule({
1953
2025
  type: "problem",
1954
2026
  docs: {
1955
2027
  description: "Disallow `children` in void DOM elements.",
1956
- [Symbol.for("rule_features")]: RULE_FEATURES15
2028
+ [Symbol.for("rule_features")]: RULE_FEATURES16
1957
2029
  },
1958
2030
  messages: {
1959
2031
  noVoidElementsWithChildren: "'{{element}}' is a void element tag and must not have children."
1960
2032
  },
1961
2033
  schema: []
1962
2034
  },
1963
- name: RULE_NAME16,
1964
- create: create16,
2035
+ name: RULE_NAME17,
2036
+ create: create17,
1965
2037
  defaultOptions: []
1966
2038
  });
1967
- function create16(context) {
2039
+ function create17(context) {
2040
+ const resolver = createJsxElementResolver(context);
1968
2041
  return {
1969
2042
  JSXElement(node) {
1970
- const elementName = ER.getElementType(context, node);
2043
+ const { domElementType: elementName } = resolver.resolve(node);
1971
2044
  if (elementName.length === 0 || !voidElements.has(elementName)) {
1972
2045
  return;
1973
2046
  }
@@ -2014,6 +2087,7 @@ var plugin = {
2014
2087
  "no-render": no_render_default,
2015
2088
  "no-render-return-value": no_render_return_value_default,
2016
2089
  "no-script-url": no_script_url_default,
2090
+ "no-string-style-prop": no_string_style_prop_default,
2017
2091
  "no-unknown-property": no_unknown_property_default,
2018
2092
  "no-unsafe-iframe-sandbox": no_unsafe_iframe_sandbox_default,
2019
2093
  "no-unsafe-target-blank": no_unsafe_target_blank_default,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-dom",
3
- "version": "2.0.0-next.14",
3
+ "version": "2.0.0-next.141",
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.31.1",
39
- "@typescript-eslint/types": "^8.31.1",
40
- "@typescript-eslint/utils": "^8.31.1",
38
+ "@typescript-eslint/scope-manager": "^8.40.0",
39
+ "@typescript-eslint/types": "^8.40.0",
40
+ "@typescript-eslint/utils": "^8.40.0",
41
41
  "compare-versions": "^6.1.1",
42
42
  "string-ts": "^2.2.1",
43
- "ts-pattern": "^5.7.0",
44
- "@eslint-react/core": "2.0.0-next.14",
45
- "@eslint-react/ast": "2.0.0-next.14",
46
- "@eslint-react/shared": "2.0.0-next.14",
47
- "@eslint-react/kit": "2.0.0-next.14",
48
- "@eslint-react/eff": "2.0.0-next.14",
49
- "@eslint-react/var": "2.0.0-next.14"
43
+ "ts-pattern": "^5.8.0",
44
+ "@eslint-react/ast": "2.0.0-next.141",
45
+ "@eslint-react/core": "2.0.0-next.141",
46
+ "@eslint-react/kit": "2.0.0-next.141",
47
+ "@eslint-react/var": "2.0.0-next.141",
48
+ "@eslint-react/eff": "2.0.0-next.141",
49
+ "@eslint-react/shared": "2.0.0-next.141"
50
50
  },
51
51
  "devDependencies": {
52
- "@types/react": "^19.1.2",
53
- "@types/react-dom": "^19.1.3",
54
- "tsup": "^8.4.0",
52
+ "@types/react": "^19.1.11",
53
+ "@types/react-dom": "^19.1.7",
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.33.0",
59
59
  "typescript": "^4.9.5 || ^5.4.5"
60
60
  },
61
61
  "peerDependenciesMeta": {
@@ -67,7 +67,6 @@
67
67
  }
68
68
  },
69
69
  "engines": {
70
- "bun": ">=1.0.15",
71
70
  "node": ">=20.19.0"
72
71
  },
73
72
  "publishConfig": {