eslint-plugin-react-dom 2.0.0-next.12 → 2.0.0-next.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +19 -6
- package/dist/index.js +142 -119
- 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,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<
|
|
20
|
-
readonly "no-missing-iframe-sandbox": _typescript_eslint_utils_ts_eslint.RuleModule<
|
|
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<
|
|
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<
|
|
52
|
-
readonly "no-missing-iframe-sandbox": _typescript_eslint_utils_ts_eslint.RuleModule<
|
|
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<
|
|
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-next.
|
|
47
|
+
var version = "2.0.0-next.120";
|
|
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
|
|
350
|
-
|
|
351
|
-
|
|
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
|
-
|
|
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
|
|
426
|
-
|
|
427
|
-
|
|
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:
|
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
|
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
|
|
1759
|
-
|
|
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
|
|
1823
|
-
|
|
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
|
-
|
|
1839
|
+
const hrefAttribute = resolveAttribute(context, attributes, node, "href");
|
|
1840
|
+
if (!isExternalLinkLike(hrefAttribute.attributeValueString)) {
|
|
1843
1841
|
return;
|
|
1844
1842
|
}
|
|
1845
|
-
|
|
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 =
|
|
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-next.
|
|
3
|
+
"version": "2.0.0-next.120",
|
|
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.
|
|
39
|
-
"@typescript-eslint/types": "^8.
|
|
40
|
-
"@typescript-eslint/utils": "^8.
|
|
38
|
+
"@typescript-eslint/scope-manager": "^8.38.0",
|
|
39
|
+
"@typescript-eslint/types": "^8.38.0",
|
|
40
|
+
"@typescript-eslint/utils": "^8.38.0",
|
|
41
41
|
"compare-versions": "^6.1.1",
|
|
42
42
|
"string-ts": "^2.2.1",
|
|
43
|
-
"ts-pattern": "^5.
|
|
44
|
-
"@eslint-react/
|
|
45
|
-
"@eslint-react/
|
|
46
|
-
"@eslint-react/
|
|
47
|
-
"@eslint-react/
|
|
48
|
-
"@eslint-react/
|
|
49
|
-
"@eslint-react/
|
|
43
|
+
"ts-pattern": "^5.8.0",
|
|
44
|
+
"@eslint-react/ast": "2.0.0-next.120",
|
|
45
|
+
"@eslint-react/core": "2.0.0-next.120",
|
|
46
|
+
"@eslint-react/eff": "2.0.0-next.120",
|
|
47
|
+
"@eslint-react/shared": "2.0.0-next.120",
|
|
48
|
+
"@eslint-react/kit": "2.0.0-next.120",
|
|
49
|
+
"@eslint-react/var": "2.0.0-next.120"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@types/react": "^19.1.
|
|
53
|
-
"@types/react-dom": "^19.1.
|
|
54
|
-
"tsup": "^8.
|
|
52
|
+
"@types/react": "^19.1.9",
|
|
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.
|
|
58
|
+
"eslint": "^9.31.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": {
|