eslint-plugin-react-dom 2.0.0-next.12 → 2.0.0-next.121
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 +151 -123
- 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,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
|
|
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) => {
|
|
@@ -44,7 +43,7 @@ var settings = {
|
|
|
44
43
|
|
|
45
44
|
// package.json
|
|
46
45
|
var name2 = "eslint-plugin-react-dom";
|
|
47
|
-
var version = "2.0.0-next.
|
|
46
|
+
var version = "2.0.0-next.121";
|
|
48
47
|
function createJsxElementResolver(context) {
|
|
49
48
|
const { components, polymorphicPropName } = getSettingsFromContext(context);
|
|
50
49
|
return {
|
|
@@ -89,6 +88,39 @@ var createRule = ESLintUtils.RuleCreator(getDocsUrl("dom"));
|
|
|
89
88
|
function findCustomComponentProp(name3, props) {
|
|
90
89
|
return props.findLast((a) => a.as === name3);
|
|
91
90
|
}
|
|
91
|
+
function resolveAttribute(context, attributes, elementNode, attributeName) {
|
|
92
|
+
const customComponentProp = findCustomComponentProp(attributeName, attributes);
|
|
93
|
+
const propNameOnJsx = customComponentProp?.name ?? attributeName;
|
|
94
|
+
const attribute = ER.getAttribute(
|
|
95
|
+
context,
|
|
96
|
+
propNameOnJsx,
|
|
97
|
+
elementNode.openingElement.attributes,
|
|
98
|
+
context.sourceCode.getScope(elementNode)
|
|
99
|
+
);
|
|
100
|
+
if (attribute == null) {
|
|
101
|
+
return {
|
|
102
|
+
attribute: unit,
|
|
103
|
+
attributeName: propNameOnJsx,
|
|
104
|
+
attributeValue: unit,
|
|
105
|
+
attributeValueString: customComponentProp?.defaultValue
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const attributeValue = ER.getAttributeValue(context, attribute, propNameOnJsx);
|
|
109
|
+
if (attributeValue.kind === "some" && typeof attributeValue.value === "string") {
|
|
110
|
+
return {
|
|
111
|
+
attribute,
|
|
112
|
+
attributeName: propNameOnJsx,
|
|
113
|
+
attributeValue,
|
|
114
|
+
attributeValueString: attributeValue.value
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
attribute,
|
|
119
|
+
attributeName: propNameOnJsx,
|
|
120
|
+
attributeValue: unit,
|
|
121
|
+
attributeValueString: customComponentProp?.defaultValue ?? unit
|
|
122
|
+
};
|
|
123
|
+
}
|
|
92
124
|
|
|
93
125
|
// src/rules/no-dangerously-set-innerhtml.ts
|
|
94
126
|
var RULE_NAME = "no-dangerously-set-innerhtml";
|
|
@@ -153,7 +185,7 @@ function create2(context) {
|
|
|
153
185
|
JSXElement(node) {
|
|
154
186
|
const attributes = node.openingElement.attributes;
|
|
155
187
|
const initialScope = context.sourceCode.getScope(node);
|
|
156
|
-
const hasChildren =
|
|
188
|
+
const hasChildren = node.children.some(isSignificantChildren) || ER.hasAttribute(context, "children", attributes, initialScope);
|
|
157
189
|
if (hasChildren && ER.hasAttribute(context, dangerouslySetInnerHTML2, attributes, initialScope)) {
|
|
158
190
|
context.report({
|
|
159
191
|
messageId: "noDangerouslySetInnerhtmlWithChildren",
|
|
@@ -163,8 +195,14 @@ function create2(context) {
|
|
|
163
195
|
}
|
|
164
196
|
};
|
|
165
197
|
}
|
|
166
|
-
function
|
|
167
|
-
return node.
|
|
198
|
+
function isWhiteSpace(node) {
|
|
199
|
+
return typeof node.value === "string" && node.raw.trim() === "";
|
|
200
|
+
}
|
|
201
|
+
function isPaddingSpaces(node) {
|
|
202
|
+
return ER.isJsxText(node) && isWhiteSpace(node) && node.raw.includes("\n");
|
|
203
|
+
}
|
|
204
|
+
function isSignificantChildren(node) {
|
|
205
|
+
return node.type !== AST_NODE_TYPES.JSXText || !isPaddingSpaces(node);
|
|
168
206
|
}
|
|
169
207
|
var RULE_NAME3 = "no-find-dom-node";
|
|
170
208
|
var RULE_FEATURES3 = [];
|
|
@@ -322,8 +360,13 @@ function getFix(context, node) {
|
|
|
322
360
|
];
|
|
323
361
|
};
|
|
324
362
|
}
|
|
363
|
+
|
|
364
|
+
// src/rules/no-missing-button-type.ts
|
|
325
365
|
var RULE_NAME6 = "no-missing-button-type";
|
|
326
|
-
var RULE_FEATURES6 = [
|
|
366
|
+
var RULE_FEATURES6 = [
|
|
367
|
+
"FIX"
|
|
368
|
+
];
|
|
369
|
+
var BUTTON_TYPES = ["button", "submit", "reset"];
|
|
327
370
|
var no_missing_button_type_default = createRule({
|
|
328
371
|
meta: {
|
|
329
372
|
type: "problem",
|
|
@@ -331,7 +374,9 @@ var no_missing_button_type_default = createRule({
|
|
|
331
374
|
description: "Enforces explicit `type` attribute for `button` elements.",
|
|
332
375
|
[Symbol.for("rule_features")]: RULE_FEATURES6
|
|
333
376
|
},
|
|
377
|
+
hasSuggestions: true,
|
|
334
378
|
messages: {
|
|
379
|
+
addButtonType: "Add 'type' attribute with value '{{type}}'.",
|
|
335
380
|
noMissingButtonType: "Add missing 'type' attribute on 'button' component."
|
|
336
381
|
},
|
|
337
382
|
schema: []
|
|
@@ -346,60 +391,42 @@ function create6(context) {
|
|
|
346
391
|
JSXElement(node) {
|
|
347
392
|
const { attributes, domElementType } = resolver.resolve(node);
|
|
348
393
|
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") {
|
|
394
|
+
const typeAttribute = resolveAttribute(context, attributes, node, "type");
|
|
395
|
+
if (typeAttribute.attributeValueString != null) return;
|
|
396
|
+
if (typeAttribute.attribute == null) {
|
|
372
397
|
context.report({
|
|
373
398
|
messageId: "noMissingButtonType",
|
|
374
|
-
node
|
|
399
|
+
node: node.openingElement,
|
|
400
|
+
suggest: getSuggest((type) => (fixer) => {
|
|
401
|
+
return fixer.insertTextAfter(node.openingElement.name, ` ${typeAttribute.attributeName}="${type}"`);
|
|
402
|
+
})
|
|
375
403
|
});
|
|
404
|
+
return;
|
|
376
405
|
}
|
|
406
|
+
context.report({
|
|
407
|
+
messageId: "noMissingButtonType",
|
|
408
|
+
node: typeAttribute.attributeValue?.node ?? typeAttribute.attribute,
|
|
409
|
+
suggest: getSuggest((type) => (fixer) => {
|
|
410
|
+
if (typeAttribute.attribute == null) return null;
|
|
411
|
+
return fixer.replaceText(typeAttribute.attribute, `${typeAttribute.attributeName}="${type}"`);
|
|
412
|
+
})
|
|
413
|
+
});
|
|
377
414
|
}
|
|
378
415
|
};
|
|
379
416
|
}
|
|
417
|
+
function getSuggest(getFix4) {
|
|
418
|
+
return BUTTON_TYPES.map((type) => ({
|
|
419
|
+
messageId: "addButtonType",
|
|
420
|
+
data: { type },
|
|
421
|
+
fix: getFix4(type)
|
|
422
|
+
}));
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// src/rules/no-missing-iframe-sandbox.ts
|
|
380
426
|
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"
|
|
427
|
+
var RULE_FEATURES7 = [
|
|
428
|
+
"FIX"
|
|
399
429
|
];
|
|
400
|
-
function hasValidSandBox(value) {
|
|
401
|
-
return typeof value === "string" && value.split(" ").every((value2) => validTypes.some((valid) => valid === value2));
|
|
402
|
-
}
|
|
403
430
|
var no_missing_iframe_sandbox_default = createRule({
|
|
404
431
|
meta: {
|
|
405
432
|
type: "problem",
|
|
@@ -407,7 +434,10 @@ var no_missing_iframe_sandbox_default = createRule({
|
|
|
407
434
|
description: "Enforces explicit `sandbox` attribute for `iframe` elements.",
|
|
408
435
|
[Symbol.for("rule_features")]: RULE_FEATURES7
|
|
409
436
|
},
|
|
437
|
+
fixable: "code",
|
|
438
|
+
hasSuggestions: true,
|
|
410
439
|
messages: {
|
|
440
|
+
addIframeSandbox: "Add 'sandbox' attribute with value '{{value}}'.",
|
|
411
441
|
noMissingIframeSandbox: "Add missing 'sandbox' attribute on 'iframe' component."
|
|
412
442
|
},
|
|
413
443
|
schema: []
|
|
@@ -422,33 +452,34 @@ function create7(context) {
|
|
|
422
452
|
JSXElement(node) {
|
|
423
453
|
const { attributes, domElementType } = resolver.resolve(node);
|
|
424
454
|
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;
|
|
455
|
+
const sandboxAttribute = resolveAttribute(context, attributes, node, "sandbox");
|
|
456
|
+
if (sandboxAttribute.attributeValueString != null) return;
|
|
457
|
+
if (sandboxAttribute.attribute == null) {
|
|
440
458
|
context.report({
|
|
441
459
|
messageId: "noMissingIframeSandbox",
|
|
442
|
-
node:
|
|
460
|
+
node: node.openingElement,
|
|
461
|
+
suggest: [{
|
|
462
|
+
messageId: "addIframeSandbox",
|
|
463
|
+
data: { value: "" },
|
|
464
|
+
fix(fixer) {
|
|
465
|
+
return fixer.insertTextAfter(node.openingElement.name, ` ${sandboxAttribute.attributeName}=""`);
|
|
466
|
+
}
|
|
467
|
+
}]
|
|
443
468
|
});
|
|
444
469
|
return;
|
|
445
470
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
471
|
+
context.report({
|
|
472
|
+
messageId: "noMissingIframeSandbox",
|
|
473
|
+
node: sandboxAttribute.attributeValue?.node ?? sandboxAttribute.attribute,
|
|
474
|
+
suggest: [{
|
|
475
|
+
messageId: "addIframeSandbox",
|
|
476
|
+
data: { value: "" },
|
|
477
|
+
fix(fixer) {
|
|
478
|
+
if (sandboxAttribute.attribute == null) return null;
|
|
479
|
+
return fixer.replaceText(sandboxAttribute.attribute, `${sandboxAttribute.attributeName}=""`);
|
|
480
|
+
}
|
|
481
|
+
}]
|
|
482
|
+
});
|
|
452
483
|
}
|
|
453
484
|
};
|
|
454
485
|
}
|
|
@@ -1722,12 +1753,14 @@ function testReactVersion(context, comparator, version2) {
|
|
|
1722
1753
|
const { version: localVersion } = getSettingsFromContext(context);
|
|
1723
1754
|
return compare(localVersion, version2, comparator);
|
|
1724
1755
|
}
|
|
1756
|
+
|
|
1757
|
+
// src/rules/no-unsafe-iframe-sandbox.ts
|
|
1725
1758
|
var RULE_NAME13 = "no-unsafe-iframe-sandbox";
|
|
1726
1759
|
var RULE_FEATURES12 = [];
|
|
1727
1760
|
var unsafeSandboxValues = [
|
|
1728
1761
|
["allow-scripts", "allow-same-origin"]
|
|
1729
1762
|
];
|
|
1730
|
-
function
|
|
1763
|
+
function isSafeSandbox(value) {
|
|
1731
1764
|
if (typeof value !== "string") return false;
|
|
1732
1765
|
return !unsafeSandboxValues.some((values) => {
|
|
1733
1766
|
return values.every((v) => value.includes(v));
|
|
@@ -1755,40 +1788,22 @@ function create13(context) {
|
|
|
1755
1788
|
JSXElement(node) {
|
|
1756
1789
|
const { attributes, domElementType } = resolver.resolve(node);
|
|
1757
1790
|
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)) {
|
|
1791
|
+
const sandboxAttribute = resolveAttribute(context, attributes, node, "sandbox");
|
|
1792
|
+
if (!isSafeSandbox(sandboxAttribute.attributeValueString)) {
|
|
1782
1793
|
context.report({
|
|
1783
1794
|
messageId: "noUnsafeIframeSandbox",
|
|
1784
|
-
node
|
|
1795
|
+
node: sandboxAttribute.attributeValue?.node ?? sandboxAttribute.attribute ?? node
|
|
1785
1796
|
});
|
|
1786
1797
|
}
|
|
1787
1798
|
}
|
|
1788
1799
|
};
|
|
1789
1800
|
}
|
|
1801
|
+
|
|
1802
|
+
// src/rules/no-unsafe-target-blank.ts
|
|
1790
1803
|
var RULE_NAME14 = "no-unsafe-target-blank";
|
|
1791
|
-
var RULE_FEATURES13 = [
|
|
1804
|
+
var RULE_FEATURES13 = [
|
|
1805
|
+
"FIX"
|
|
1806
|
+
];
|
|
1792
1807
|
function isExternalLinkLike(value) {
|
|
1793
1808
|
if (value == null) return false;
|
|
1794
1809
|
return value.startsWith("https://") || /^(?:\w+:|\/\/)/u.test(value);
|
|
@@ -1804,7 +1819,10 @@ var no_unsafe_target_blank_default = createRule({
|
|
|
1804
1819
|
description: 'Disallow `target="_blank"` without `rel="noreferrer noopener"`.',
|
|
1805
1820
|
[Symbol.for("rule_features")]: RULE_FEATURES13
|
|
1806
1821
|
},
|
|
1822
|
+
fixable: "code",
|
|
1823
|
+
hasSuggestions: true,
|
|
1807
1824
|
messages: {
|
|
1825
|
+
addRelNoreferrerNoopener: `Add 'rel="noreferrer noopener"' to the link to prevent security risks.`,
|
|
1808
1826
|
noUnsafeTargetBlank: `Using 'target="_blank"' on an external link without 'rel="noreferrer noopener"' is a security risk.`
|
|
1809
1827
|
},
|
|
1810
1828
|
schema: []
|
|
@@ -1819,35 +1837,44 @@ function create14(context) {
|
|
|
1819
1837
|
JSXElement(node) {
|
|
1820
1838
|
const { attributes, domElementType } = resolver.resolve(node);
|
|
1821
1839
|
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") {
|
|
1840
|
+
const targetAttribute = resolveAttribute(context, attributes, node, "target");
|
|
1841
|
+
if (targetAttribute.attributeValueString !== "_blank") {
|
|
1840
1842
|
return;
|
|
1841
1843
|
}
|
|
1842
|
-
|
|
1844
|
+
const hrefAttribute = resolveAttribute(context, attributes, node, "href");
|
|
1845
|
+
if (!isExternalLinkLike(hrefAttribute.attributeValueString)) {
|
|
1843
1846
|
return;
|
|
1844
1847
|
}
|
|
1845
|
-
|
|
1848
|
+
const relAttribute = resolveAttribute(context, attributes, node, "rel");
|
|
1849
|
+
if (isSafeRel(relAttribute.attributeValueString)) {
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
if (relAttribute.attribute == null) {
|
|
1853
|
+
context.report({
|
|
1854
|
+
messageId: "noUnsafeTargetBlank",
|
|
1855
|
+
node: node.openingElement,
|
|
1856
|
+
suggest: [{
|
|
1857
|
+
messageId: "addRelNoreferrerNoopener",
|
|
1858
|
+
fix(fixer) {
|
|
1859
|
+
return fixer.insertTextAfter(
|
|
1860
|
+
node.openingElement.name,
|
|
1861
|
+
` ${relAttribute.attributeName}="noreferrer noopener"`
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
}]
|
|
1865
|
+
});
|
|
1846
1866
|
return;
|
|
1847
1867
|
}
|
|
1848
1868
|
context.report({
|
|
1849
1869
|
messageId: "noUnsafeTargetBlank",
|
|
1850
|
-
node
|
|
1870
|
+
node: relAttribute.attributeValue?.node ?? relAttribute.attribute,
|
|
1871
|
+
suggest: [{
|
|
1872
|
+
messageId: "addRelNoreferrerNoopener",
|
|
1873
|
+
fix(fixer) {
|
|
1874
|
+
if (relAttribute.attribute == null) return null;
|
|
1875
|
+
return fixer.replaceText(relAttribute.attribute, `${relAttribute.attributeName}="noreferrer noopener"`);
|
|
1876
|
+
}
|
|
1877
|
+
}]
|
|
1851
1878
|
});
|
|
1852
1879
|
}
|
|
1853
1880
|
};
|
|
@@ -1965,9 +1992,10 @@ var no_void_elements_with_children_default = createRule({
|
|
|
1965
1992
|
defaultOptions: []
|
|
1966
1993
|
});
|
|
1967
1994
|
function create16(context) {
|
|
1995
|
+
const resolver = createJsxElementResolver(context);
|
|
1968
1996
|
return {
|
|
1969
1997
|
JSXElement(node) {
|
|
1970
|
-
const elementName =
|
|
1998
|
+
const { domElementType: elementName } = resolver.resolve(node);
|
|
1971
1999
|
if (elementName.length === 0 || !voidElements.has(elementName)) {
|
|
1972
2000
|
return;
|
|
1973
2001
|
}
|
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.121",
|
|
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/kit": "2.0.0-next.
|
|
47
|
-
"@eslint-react/
|
|
48
|
-
"@eslint-react/
|
|
49
|
-
"@eslint-react/
|
|
43
|
+
"ts-pattern": "^5.8.0",
|
|
44
|
+
"@eslint-react/ast": "2.0.0-next.121",
|
|
45
|
+
"@eslint-react/core": "2.0.0-next.121",
|
|
46
|
+
"@eslint-react/kit": "2.0.0-next.121",
|
|
47
|
+
"@eslint-react/eff": "2.0.0-next.121",
|
|
48
|
+
"@eslint-react/shared": "2.0.0-next.121",
|
|
49
|
+
"@eslint-react/var": "2.0.0-next.121"
|
|
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": {
|