eslint-plugin-react-dom 1.52.3-next.9 → 2.0.0-beta.1
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 -8
- package/dist/index.js +209 -213
- package/package.json +16 -24
- package/dist/index.d.mts +0 -67
- package/dist/index.mjs +0 -2052
package/dist/index.js
CHANGED
|
@@ -1,34 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var kit = require('@eslint-react/kit');
|
|
10
|
-
var eff = require('@eslint-react/eff');
|
|
11
|
-
|
|
12
|
-
function _interopNamespace(e) {
|
|
13
|
-
if (e && e.__esModule) return e;
|
|
14
|
-
var n = Object.create(null);
|
|
15
|
-
if (e) {
|
|
16
|
-
Object.keys(e).forEach(function (k) {
|
|
17
|
-
if (k !== 'default') {
|
|
18
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
19
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
20
|
-
enumerable: true,
|
|
21
|
-
get: function () { return e[k]; }
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
n.default = e;
|
|
27
|
-
return Object.freeze(n);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
var ER__namespace = /*#__PURE__*/_interopNamespace(ER);
|
|
31
|
-
var AST__namespace = /*#__PURE__*/_interopNamespace(AST);
|
|
1
|
+
import { getDocsUrl, getSettingsFromContext, DEFAULT_ESLINT_REACT_SETTINGS } from '@eslint-react/shared';
|
|
2
|
+
import * as ER from '@eslint-react/core';
|
|
3
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
4
|
+
import { unit } from '@eslint-react/eff';
|
|
5
|
+
import * as AST from '@eslint-react/ast';
|
|
6
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/types';
|
|
7
|
+
import { compare } from 'compare-versions';
|
|
8
|
+
import { RegExp, Reporter } from '@eslint-react/kit';
|
|
32
9
|
|
|
33
10
|
var __defProp = Object.defineProperty;
|
|
34
11
|
var __export = (target, all) => {
|
|
@@ -62,17 +39,17 @@ var rules = {
|
|
|
62
39
|
"react-dom/no-void-elements-with-children": "error"
|
|
63
40
|
};
|
|
64
41
|
var settings = {
|
|
65
|
-
"react-x":
|
|
42
|
+
"react-x": DEFAULT_ESLINT_REACT_SETTINGS
|
|
66
43
|
};
|
|
67
44
|
|
|
68
45
|
// package.json
|
|
69
46
|
var name2 = "eslint-plugin-react-dom";
|
|
70
|
-
var version = "
|
|
47
|
+
var version = "2.0.0-beta.1";
|
|
71
48
|
function createJsxElementResolver(context) {
|
|
72
|
-
const { components, polymorphicPropName } =
|
|
49
|
+
const { components, polymorphicPropName } = getSettingsFromContext(context);
|
|
73
50
|
return {
|
|
74
51
|
resolve(node) {
|
|
75
|
-
const name3 =
|
|
52
|
+
const name3 = ER.getElementType(context, node);
|
|
76
53
|
const component = components.findLast((c) => c.name === name3 || c.re.test(name3));
|
|
77
54
|
const result = {
|
|
78
55
|
attributes: component?.attributes ?? [],
|
|
@@ -83,14 +60,14 @@ function createJsxElementResolver(context) {
|
|
|
83
60
|
return result;
|
|
84
61
|
}
|
|
85
62
|
const initialScope = context.sourceCode.getScope(node);
|
|
86
|
-
const polymorphicPropAttr =
|
|
63
|
+
const polymorphicPropAttr = ER.getAttribute(
|
|
87
64
|
context,
|
|
88
65
|
polymorphicPropName,
|
|
89
66
|
node.openingElement.attributes,
|
|
90
67
|
initialScope
|
|
91
68
|
);
|
|
92
69
|
if (polymorphicPropAttr != null) {
|
|
93
|
-
const polymorphicPropValue =
|
|
70
|
+
const polymorphicPropValue = ER.getAttributeValue(
|
|
94
71
|
context,
|
|
95
72
|
polymorphicPropAttr,
|
|
96
73
|
polymorphicPropName
|
|
@@ -106,12 +83,45 @@ function createJsxElementResolver(context) {
|
|
|
106
83
|
}
|
|
107
84
|
};
|
|
108
85
|
}
|
|
109
|
-
var createRule =
|
|
86
|
+
var createRule = ESLintUtils.RuleCreator(getDocsUrl("dom"));
|
|
110
87
|
|
|
111
88
|
// src/utils/find-custom-component.ts
|
|
112
89
|
function findCustomComponentProp(name3, props) {
|
|
113
90
|
return props.findLast((a) => a.as === name3);
|
|
114
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
|
+
}
|
|
115
125
|
|
|
116
126
|
// src/rules/no-dangerously-set-innerhtml.ts
|
|
117
127
|
var RULE_NAME = "no-dangerously-set-innerhtml";
|
|
@@ -137,7 +147,7 @@ function create(context) {
|
|
|
137
147
|
if (!context.sourceCode.text.includes(dangerouslySetInnerHTML)) return {};
|
|
138
148
|
return {
|
|
139
149
|
JSXElement(node) {
|
|
140
|
-
const attribute =
|
|
150
|
+
const attribute = ER.getAttribute(
|
|
141
151
|
context,
|
|
142
152
|
dangerouslySetInnerHTML,
|
|
143
153
|
node.openingElement.attributes,
|
|
@@ -176,8 +186,8 @@ function create2(context) {
|
|
|
176
186
|
JSXElement(node) {
|
|
177
187
|
const attributes = node.openingElement.attributes;
|
|
178
188
|
const initialScope = context.sourceCode.getScope(node);
|
|
179
|
-
const hasChildren = hasChildrenWithin(node) ||
|
|
180
|
-
if (hasChildren &&
|
|
189
|
+
const hasChildren = hasChildrenWithin(node) || ER.hasAttribute(context, "children", attributes, initialScope);
|
|
190
|
+
if (hasChildren && ER.hasAttribute(context, dangerouslySetInnerHTML2, attributes, initialScope)) {
|
|
181
191
|
context.report({
|
|
182
192
|
messageId: "noDangerouslySetInnerhtmlWithChildren",
|
|
183
193
|
node
|
|
@@ -187,7 +197,7 @@ function create2(context) {
|
|
|
187
197
|
};
|
|
188
198
|
}
|
|
189
199
|
function hasChildrenWithin(node) {
|
|
190
|
-
return node.children.length > 0 && node.children[0] != null && !
|
|
200
|
+
return node.children.length > 0 && node.children[0] != null && !AST.isLineBreak(node.children[0]);
|
|
191
201
|
}
|
|
192
202
|
var RULE_NAME3 = "no-find-dom-node";
|
|
193
203
|
var RULE_FEATURES3 = [];
|
|
@@ -214,13 +224,13 @@ function create3(context) {
|
|
|
214
224
|
CallExpression(node) {
|
|
215
225
|
const { callee } = node;
|
|
216
226
|
switch (callee.type) {
|
|
217
|
-
case
|
|
227
|
+
case AST_NODE_TYPES.Identifier:
|
|
218
228
|
if (callee.name === findDOMNode) {
|
|
219
229
|
context.report({ messageId: "noFindDomNode", node });
|
|
220
230
|
}
|
|
221
231
|
return;
|
|
222
|
-
case
|
|
223
|
-
if (callee.property.type ===
|
|
232
|
+
case AST_NODE_TYPES.MemberExpression:
|
|
233
|
+
if (callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === findDOMNode) {
|
|
224
234
|
context.report({ messageId: "noFindDomNode", node });
|
|
225
235
|
}
|
|
226
236
|
return;
|
|
@@ -253,13 +263,13 @@ function create4(context) {
|
|
|
253
263
|
CallExpression(node) {
|
|
254
264
|
const { callee } = node;
|
|
255
265
|
switch (callee.type) {
|
|
256
|
-
case
|
|
266
|
+
case AST_NODE_TYPES.Identifier:
|
|
257
267
|
if (callee.name === flushSync) {
|
|
258
268
|
context.report({ messageId: "noFlushSync", node });
|
|
259
269
|
}
|
|
260
270
|
return;
|
|
261
|
-
case
|
|
262
|
-
if (callee.property.type ===
|
|
271
|
+
case AST_NODE_TYPES.MemberExpression:
|
|
272
|
+
if (callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === flushSync) {
|
|
263
273
|
context.report({ messageId: "noFlushSync", node });
|
|
264
274
|
}
|
|
265
275
|
return;
|
|
@@ -291,21 +301,21 @@ var no_hydrate_default = createRule({
|
|
|
291
301
|
var hydrate = "hydrate";
|
|
292
302
|
function create5(context) {
|
|
293
303
|
if (!context.sourceCode.text.includes(hydrate)) return {};
|
|
294
|
-
const settings2 =
|
|
295
|
-
if (
|
|
304
|
+
const settings2 = getSettingsFromContext(context);
|
|
305
|
+
if (compare(settings2.version, "18.0.0", "<")) return {};
|
|
296
306
|
const reactDomNames = /* @__PURE__ */ new Set();
|
|
297
307
|
const hydrateNames = /* @__PURE__ */ new Set();
|
|
298
308
|
return {
|
|
299
309
|
CallExpression(node) {
|
|
300
310
|
switch (true) {
|
|
301
|
-
case (node.callee.type ===
|
|
311
|
+
case (node.callee.type === AST_NODE_TYPES.Identifier && hydrateNames.has(node.callee.name)):
|
|
302
312
|
context.report({
|
|
303
313
|
messageId: "noHydrate",
|
|
304
314
|
node,
|
|
305
315
|
fix: getFix(context, node)
|
|
306
316
|
});
|
|
307
317
|
return;
|
|
308
|
-
case (node.callee.type ===
|
|
318
|
+
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.object.type === AST_NODE_TYPES.Identifier && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === hydrate && reactDomNames.has(node.callee.object.name)):
|
|
309
319
|
context.report({
|
|
310
320
|
messageId: "noHydrate",
|
|
311
321
|
node,
|
|
@@ -319,14 +329,14 @@ function create5(context) {
|
|
|
319
329
|
if (baseSource !== "react-dom") return;
|
|
320
330
|
for (const specifier of node.specifiers) {
|
|
321
331
|
switch (specifier.type) {
|
|
322
|
-
case
|
|
323
|
-
if (specifier.imported.type !==
|
|
332
|
+
case AST_NODE_TYPES.ImportSpecifier:
|
|
333
|
+
if (specifier.imported.type !== AST_NODE_TYPES.Identifier) continue;
|
|
324
334
|
if (specifier.imported.name === hydrate) {
|
|
325
335
|
hydrateNames.add(specifier.local.name);
|
|
326
336
|
}
|
|
327
337
|
continue;
|
|
328
|
-
case
|
|
329
|
-
case
|
|
338
|
+
case AST_NODE_TYPES.ImportDefaultSpecifier:
|
|
339
|
+
case AST_NODE_TYPES.ImportNamespaceSpecifier:
|
|
330
340
|
reactDomNames.add(specifier.local.name);
|
|
331
341
|
continue;
|
|
332
342
|
}
|
|
@@ -345,8 +355,13 @@ function getFix(context, node) {
|
|
|
345
355
|
];
|
|
346
356
|
};
|
|
347
357
|
}
|
|
358
|
+
|
|
359
|
+
// src/rules/no-missing-button-type.ts
|
|
348
360
|
var RULE_NAME6 = "no-missing-button-type";
|
|
349
|
-
var RULE_FEATURES6 = [
|
|
361
|
+
var RULE_FEATURES6 = [
|
|
362
|
+
"FIX"
|
|
363
|
+
];
|
|
364
|
+
var BUTTON_TYPES = ["button", "submit", "reset"];
|
|
350
365
|
var no_missing_button_type_default = createRule({
|
|
351
366
|
meta: {
|
|
352
367
|
type: "problem",
|
|
@@ -354,7 +369,9 @@ var no_missing_button_type_default = createRule({
|
|
|
354
369
|
description: "Enforces explicit `type` attribute for `button` elements.",
|
|
355
370
|
[Symbol.for("rule_features")]: RULE_FEATURES6
|
|
356
371
|
},
|
|
372
|
+
hasSuggestions: true,
|
|
357
373
|
messages: {
|
|
374
|
+
addButtonType: "Add 'type' attribute with value '{{type}}'.",
|
|
358
375
|
noMissingButtonType: "Add missing 'type' attribute on 'button' component."
|
|
359
376
|
},
|
|
360
377
|
schema: []
|
|
@@ -369,60 +386,42 @@ function create6(context) {
|
|
|
369
386
|
JSXElement(node) {
|
|
370
387
|
const { attributes, domElementType } = resolver.resolve(node);
|
|
371
388
|
if (domElementType !== "button") return;
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
context,
|
|
376
|
-
propNameOnJsx,
|
|
377
|
-
node.openingElement.attributes,
|
|
378
|
-
context.sourceCode.getScope(node)
|
|
379
|
-
);
|
|
380
|
-
if (attributeNode != null) {
|
|
381
|
-
const attributeValue = ER__namespace.getAttributeValue(
|
|
382
|
-
context,
|
|
383
|
-
attributeNode,
|
|
384
|
-
propNameOnJsx
|
|
385
|
-
);
|
|
386
|
-
if (attributeValue.kind === "some" && typeof attributeValue.value !== "string") {
|
|
387
|
-
context.report({
|
|
388
|
-
messageId: "noMissingButtonType",
|
|
389
|
-
node: attributeNode
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
if (typeof customComponentProp?.defaultValue !== "string") {
|
|
389
|
+
const typeAttribute = resolveAttribute(context, attributes, node, "type");
|
|
390
|
+
if (typeAttribute.attributeValueString != null) return;
|
|
391
|
+
if (typeAttribute.attribute == null) {
|
|
395
392
|
context.report({
|
|
396
393
|
messageId: "noMissingButtonType",
|
|
397
|
-
node
|
|
394
|
+
node: node.openingElement,
|
|
395
|
+
suggest: getSuggest((type) => (fixer) => {
|
|
396
|
+
return fixer.insertTextAfter(node.openingElement.name, ` ${typeAttribute.attributeName}="${type}"`);
|
|
397
|
+
})
|
|
398
398
|
});
|
|
399
|
+
return;
|
|
399
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
|
+
});
|
|
400
409
|
}
|
|
401
410
|
};
|
|
402
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
|
|
403
421
|
var RULE_NAME7 = "no-missing-iframe-sandbox";
|
|
404
|
-
var RULE_FEATURES7 = [
|
|
405
|
-
|
|
406
|
-
"",
|
|
407
|
-
"allow-downloads",
|
|
408
|
-
"allow-downloads-without-user-activation",
|
|
409
|
-
"allow-forms",
|
|
410
|
-
"allow-modals",
|
|
411
|
-
"allow-orientation-lock",
|
|
412
|
-
"allow-pointer-lock",
|
|
413
|
-
"allow-popups",
|
|
414
|
-
"allow-popups-to-escape-sandbox",
|
|
415
|
-
"allow-presentation",
|
|
416
|
-
"allow-same-origin",
|
|
417
|
-
"allow-scripts",
|
|
418
|
-
"allow-storage-access-by-user-activation",
|
|
419
|
-
"allow-top-navigation",
|
|
420
|
-
"allow-top-navigation-by-user-activation",
|
|
421
|
-
"allow-top-navigation-to-custom-protocols"
|
|
422
|
+
var RULE_FEATURES7 = [
|
|
423
|
+
"FIX"
|
|
422
424
|
];
|
|
423
|
-
function hasValidSandBox(value) {
|
|
424
|
-
return typeof value === "string" && value.split(" ").every((value2) => validTypes.some((valid) => valid === value2));
|
|
425
|
-
}
|
|
426
425
|
var no_missing_iframe_sandbox_default = createRule({
|
|
427
426
|
meta: {
|
|
428
427
|
type: "problem",
|
|
@@ -430,7 +429,10 @@ var no_missing_iframe_sandbox_default = createRule({
|
|
|
430
429
|
description: "Enforces explicit `sandbox` attribute for `iframe` elements.",
|
|
431
430
|
[Symbol.for("rule_features")]: RULE_FEATURES7
|
|
432
431
|
},
|
|
432
|
+
fixable: "code",
|
|
433
|
+
hasSuggestions: true,
|
|
433
434
|
messages: {
|
|
435
|
+
addIframeSandbox: "Add 'sandbox' attribute with value '{{value}}'.",
|
|
434
436
|
noMissingIframeSandbox: "Add missing 'sandbox' attribute on 'iframe' component."
|
|
435
437
|
},
|
|
436
438
|
schema: []
|
|
@@ -445,33 +447,34 @@ function create7(context) {
|
|
|
445
447
|
JSXElement(node) {
|
|
446
448
|
const { attributes, domElementType } = resolver.resolve(node);
|
|
447
449
|
if (domElementType !== "iframe") return;
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
context,
|
|
452
|
-
propNameOnJsx,
|
|
453
|
-
node.openingElement.attributes,
|
|
454
|
-
context.sourceCode.getScope(node)
|
|
455
|
-
);
|
|
456
|
-
if (attributeNode != null) {
|
|
457
|
-
const attributeValue = ER__namespace.getAttributeValue(
|
|
458
|
-
context,
|
|
459
|
-
attributeNode,
|
|
460
|
-
propNameOnJsx
|
|
461
|
-
);
|
|
462
|
-
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) {
|
|
463
453
|
context.report({
|
|
464
454
|
messageId: "noMissingIframeSandbox",
|
|
465
|
-
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
|
+
}]
|
|
466
463
|
});
|
|
467
464
|
return;
|
|
468
465
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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
|
+
});
|
|
475
478
|
}
|
|
476
479
|
};
|
|
477
480
|
}
|
|
@@ -496,7 +499,7 @@ var no_namespace_default = createRule({
|
|
|
496
499
|
function create8(context) {
|
|
497
500
|
return {
|
|
498
501
|
JSXElement(node) {
|
|
499
|
-
const name3 =
|
|
502
|
+
const name3 = ER.getElementType(context, node);
|
|
500
503
|
if (typeof name3 !== "string" || !name3.includes(":")) {
|
|
501
504
|
return;
|
|
502
505
|
}
|
|
@@ -533,21 +536,21 @@ var no_render_default = createRule({
|
|
|
533
536
|
});
|
|
534
537
|
function create9(context) {
|
|
535
538
|
if (!context.sourceCode.text.includes("render")) return {};
|
|
536
|
-
const settings2 =
|
|
537
|
-
if (
|
|
539
|
+
const settings2 = getSettingsFromContext(context);
|
|
540
|
+
if (compare(settings2.version, "18.0.0", "<")) return {};
|
|
538
541
|
const reactDomNames = /* @__PURE__ */ new Set(["ReactDOM", "ReactDom"]);
|
|
539
542
|
const renderNames = /* @__PURE__ */ new Set();
|
|
540
543
|
return {
|
|
541
544
|
CallExpression(node) {
|
|
542
545
|
switch (true) {
|
|
543
|
-
case (node.callee.type ===
|
|
546
|
+
case (node.callee.type === AST_NODE_TYPES.Identifier && renderNames.has(node.callee.name)):
|
|
544
547
|
context.report({
|
|
545
548
|
messageId: "noRender",
|
|
546
549
|
node,
|
|
547
550
|
fix: getFix2(context, node)
|
|
548
551
|
});
|
|
549
552
|
return;
|
|
550
|
-
case (node.callee.type ===
|
|
553
|
+
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.object.type === AST_NODE_TYPES.Identifier && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === "render" && reactDomNames.has(node.callee.object.name)):
|
|
551
554
|
context.report({
|
|
552
555
|
messageId: "noRender",
|
|
553
556
|
node,
|
|
@@ -561,14 +564,14 @@ function create9(context) {
|
|
|
561
564
|
if (baseSource !== "react-dom") return;
|
|
562
565
|
for (const specifier of node.specifiers) {
|
|
563
566
|
switch (specifier.type) {
|
|
564
|
-
case
|
|
565
|
-
if (specifier.imported.type !==
|
|
567
|
+
case AST_NODE_TYPES.ImportSpecifier:
|
|
568
|
+
if (specifier.imported.type !== AST_NODE_TYPES.Identifier) continue;
|
|
566
569
|
if (specifier.imported.name === "render") {
|
|
567
570
|
renderNames.add(specifier.local.name);
|
|
568
571
|
}
|
|
569
572
|
continue;
|
|
570
|
-
case
|
|
571
|
-
case
|
|
573
|
+
case AST_NODE_TYPES.ImportDefaultSpecifier:
|
|
574
|
+
case AST_NODE_TYPES.ImportNamespaceSpecifier:
|
|
572
575
|
reactDomNames.add(specifier.local.name);
|
|
573
576
|
continue;
|
|
574
577
|
}
|
|
@@ -590,11 +593,11 @@ function getFix2(context, node) {
|
|
|
590
593
|
var RULE_NAME10 = "no-render-return-value";
|
|
591
594
|
var RULE_FEATURES10 = [];
|
|
592
595
|
var banParentTypes = [
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
596
|
+
AST_NODE_TYPES.VariableDeclarator,
|
|
597
|
+
AST_NODE_TYPES.Property,
|
|
598
|
+
AST_NODE_TYPES.ReturnStatement,
|
|
599
|
+
AST_NODE_TYPES.ArrowFunctionExpression,
|
|
600
|
+
AST_NODE_TYPES.AssignmentExpression
|
|
598
601
|
];
|
|
599
602
|
var no_render_return_value_default = createRule({
|
|
600
603
|
meta: {
|
|
@@ -618,13 +621,13 @@ function create10(context) {
|
|
|
618
621
|
return {
|
|
619
622
|
CallExpression(node) {
|
|
620
623
|
switch (true) {
|
|
621
|
-
case (node.callee.type ===
|
|
624
|
+
case (node.callee.type === AST_NODE_TYPES.Identifier && renderNames.has(node.callee.name) && banParentTypes.includes(node.parent.type)):
|
|
622
625
|
context.report({
|
|
623
626
|
messageId: "noRenderReturnValue",
|
|
624
627
|
node
|
|
625
628
|
});
|
|
626
629
|
return;
|
|
627
|
-
case (node.callee.type ===
|
|
630
|
+
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.object.type === AST_NODE_TYPES.Identifier && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === "render" && reactDomNames.has(node.callee.object.name) && banParentTypes.includes(node.parent.type)):
|
|
628
631
|
context.report({
|
|
629
632
|
messageId: "noRenderReturnValue",
|
|
630
633
|
node
|
|
@@ -637,14 +640,14 @@ function create10(context) {
|
|
|
637
640
|
if (baseSource !== "react-dom") return;
|
|
638
641
|
for (const specifier of node.specifiers) {
|
|
639
642
|
switch (specifier.type) {
|
|
640
|
-
case
|
|
641
|
-
if (specifier.imported.type !==
|
|
643
|
+
case AST_NODE_TYPES.ImportSpecifier:
|
|
644
|
+
if (specifier.imported.type !== AST_NODE_TYPES.Identifier) continue;
|
|
642
645
|
if (specifier.imported.name === "render") {
|
|
643
646
|
renderNames.add(specifier.local.name);
|
|
644
647
|
}
|
|
645
648
|
continue;
|
|
646
|
-
case
|
|
647
|
-
case
|
|
649
|
+
case AST_NODE_TYPES.ImportDefaultSpecifier:
|
|
650
|
+
case AST_NODE_TYPES.ImportNamespaceSpecifier:
|
|
648
651
|
reactDomNames.add(specifier.local.name);
|
|
649
652
|
continue;
|
|
650
653
|
}
|
|
@@ -673,12 +676,12 @@ var no_script_url_default = createRule({
|
|
|
673
676
|
function create11(context) {
|
|
674
677
|
return {
|
|
675
678
|
JSXAttribute(node) {
|
|
676
|
-
if (node.name.type !==
|
|
679
|
+
if (node.name.type !== AST_NODE_TYPES.JSXIdentifier || node.value == null) {
|
|
677
680
|
return;
|
|
678
681
|
}
|
|
679
|
-
const attributeValue =
|
|
682
|
+
const attributeValue = ER.getAttributeValue(context, node, ER.getAttributeName(context, node));
|
|
680
683
|
if (attributeValue.kind === "none" || typeof attributeValue.value !== "string") return;
|
|
681
|
-
if (
|
|
684
|
+
if (RegExp.JAVASCRIPT_PROTOCOL.test(attributeValue.value)) {
|
|
682
685
|
context.report({
|
|
683
686
|
messageId: "noScriptUrl",
|
|
684
687
|
node: node.value
|
|
@@ -1655,7 +1658,7 @@ var no_unknown_property_default = createRule({
|
|
|
1655
1658
|
defaultOptions: []
|
|
1656
1659
|
});
|
|
1657
1660
|
function create12(context) {
|
|
1658
|
-
const report =
|
|
1661
|
+
const report = Reporter.make(context);
|
|
1659
1662
|
function getIgnoreConfig() {
|
|
1660
1663
|
return context.options[0]?.ignore || DEFAULTS.ignore;
|
|
1661
1664
|
}
|
|
@@ -1742,15 +1745,17 @@ function getText(context, node) {
|
|
|
1742
1745
|
return context.sourceCode.getText(node);
|
|
1743
1746
|
}
|
|
1744
1747
|
function testReactVersion(context, comparator, version2) {
|
|
1745
|
-
const { version: localVersion } =
|
|
1746
|
-
return
|
|
1748
|
+
const { version: localVersion } = getSettingsFromContext(context);
|
|
1749
|
+
return compare(localVersion, version2, comparator);
|
|
1747
1750
|
}
|
|
1751
|
+
|
|
1752
|
+
// src/rules/no-unsafe-iframe-sandbox.ts
|
|
1748
1753
|
var RULE_NAME13 = "no-unsafe-iframe-sandbox";
|
|
1749
1754
|
var RULE_FEATURES12 = [];
|
|
1750
1755
|
var unsafeSandboxValues = [
|
|
1751
1756
|
["allow-scripts", "allow-same-origin"]
|
|
1752
1757
|
];
|
|
1753
|
-
function
|
|
1758
|
+
function isSafeSandbox(value) {
|
|
1754
1759
|
if (typeof value !== "string") return false;
|
|
1755
1760
|
return !unsafeSandboxValues.some((values) => {
|
|
1756
1761
|
return values.every((v) => value.includes(v));
|
|
@@ -1778,40 +1783,22 @@ function create13(context) {
|
|
|
1778
1783
|
JSXElement(node) {
|
|
1779
1784
|
const { attributes, domElementType } = resolver.resolve(node);
|
|
1780
1785
|
if (domElementType !== "iframe") return;
|
|
1781
|
-
const
|
|
1782
|
-
|
|
1783
|
-
const attributeNode = ER__namespace.getAttribute(
|
|
1784
|
-
context,
|
|
1785
|
-
propNameOnJsx,
|
|
1786
|
-
node.openingElement.attributes,
|
|
1787
|
-
context.sourceCode.getScope(node)
|
|
1788
|
-
);
|
|
1789
|
-
if (attributeNode != null) {
|
|
1790
|
-
const attributeValue = ER__namespace.getAttributeValue(
|
|
1791
|
-
context,
|
|
1792
|
-
attributeNode,
|
|
1793
|
-
propNameOnJsx
|
|
1794
|
-
);
|
|
1795
|
-
if (attributeValue.kind === "some" && !hasSafeSandbox(attributeValue.value)) {
|
|
1796
|
-
context.report({
|
|
1797
|
-
messageId: "noUnsafeIframeSandbox",
|
|
1798
|
-
node: attributeNode
|
|
1799
|
-
});
|
|
1800
|
-
return;
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
if (customComponentProp?.defaultValue == null) return;
|
|
1804
|
-
if (!hasSafeSandbox(customComponentProp.defaultValue)) {
|
|
1786
|
+
const sandboxAttribute = resolveAttribute(context, attributes, node, "sandbox");
|
|
1787
|
+
if (!isSafeSandbox(sandboxAttribute.attributeValueString)) {
|
|
1805
1788
|
context.report({
|
|
1806
1789
|
messageId: "noUnsafeIframeSandbox",
|
|
1807
|
-
node
|
|
1790
|
+
node: sandboxAttribute.attributeValue?.node ?? sandboxAttribute.attribute ?? node
|
|
1808
1791
|
});
|
|
1809
1792
|
}
|
|
1810
1793
|
}
|
|
1811
1794
|
};
|
|
1812
1795
|
}
|
|
1796
|
+
|
|
1797
|
+
// src/rules/no-unsafe-target-blank.ts
|
|
1813
1798
|
var RULE_NAME14 = "no-unsafe-target-blank";
|
|
1814
|
-
var RULE_FEATURES13 = [
|
|
1799
|
+
var RULE_FEATURES13 = [
|
|
1800
|
+
"FIX"
|
|
1801
|
+
];
|
|
1815
1802
|
function isExternalLinkLike(value) {
|
|
1816
1803
|
if (value == null) return false;
|
|
1817
1804
|
return value.startsWith("https://") || /^(?:\w+:|\/\/)/u.test(value);
|
|
@@ -1827,7 +1814,10 @@ var no_unsafe_target_blank_default = createRule({
|
|
|
1827
1814
|
description: 'Disallow `target="_blank"` without `rel="noreferrer noopener"`.',
|
|
1828
1815
|
[Symbol.for("rule_features")]: RULE_FEATURES13
|
|
1829
1816
|
},
|
|
1817
|
+
fixable: "code",
|
|
1818
|
+
hasSuggestions: true,
|
|
1830
1819
|
messages: {
|
|
1820
|
+
addRelNoreferrerNoopener: `Add 'rel="noreferrer noopener"' to the link to prevent security risks.`,
|
|
1831
1821
|
noUnsafeTargetBlank: `Using 'target="_blank"' on an external link without 'rel="noreferrer noopener"' is a security risk.`
|
|
1832
1822
|
},
|
|
1833
1823
|
schema: []
|
|
@@ -1842,35 +1832,44 @@ function create14(context) {
|
|
|
1842
1832
|
JSXElement(node) {
|
|
1843
1833
|
const { attributes, domElementType } = resolver.resolve(node);
|
|
1844
1834
|
if (domElementType !== "a") return;
|
|
1845
|
-
const
|
|
1846
|
-
|
|
1847
|
-
const customComponentProp = findCustomComponentProp(name3, attributes);
|
|
1848
|
-
const propNameOnJsx = customComponentProp?.name ?? name3;
|
|
1849
|
-
const attributeNode = ER__namespace.getAttribute(
|
|
1850
|
-
context,
|
|
1851
|
-
propNameOnJsx,
|
|
1852
|
-
node.openingElement.attributes,
|
|
1853
|
-
elementScope
|
|
1854
|
-
);
|
|
1855
|
-
if (attributeNode == null) return customComponentProp?.defaultValue;
|
|
1856
|
-
const attributeValue = ER__namespace.getAttributeValue(context, attributeNode, propNameOnJsx);
|
|
1857
|
-
if (attributeValue.kind === "some" && typeof attributeValue.value === "string") {
|
|
1858
|
-
return attributeValue.value;
|
|
1859
|
-
}
|
|
1860
|
-
return eff.unit;
|
|
1861
|
-
};
|
|
1862
|
-
if (getAttributeStringValue("target") !== "_blank") {
|
|
1835
|
+
const targetAttribute = resolveAttribute(context, attributes, node, "target");
|
|
1836
|
+
if (targetAttribute.attributeValueString !== "_blank") {
|
|
1863
1837
|
return;
|
|
1864
1838
|
}
|
|
1865
|
-
|
|
1839
|
+
const hrefAttribute = resolveAttribute(context, attributes, node, "href");
|
|
1840
|
+
if (!isExternalLinkLike(hrefAttribute.attributeValueString)) {
|
|
1866
1841
|
return;
|
|
1867
1842
|
}
|
|
1868
|
-
|
|
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
|
+
});
|
|
1869
1861
|
return;
|
|
1870
1862
|
}
|
|
1871
1863
|
context.report({
|
|
1872
1864
|
messageId: "noUnsafeTargetBlank",
|
|
1873
|
-
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
|
+
}]
|
|
1874
1873
|
});
|
|
1875
1874
|
}
|
|
1876
1875
|
};
|
|
@@ -1898,21 +1897,21 @@ var no_use_form_state_default = createRule({
|
|
|
1898
1897
|
});
|
|
1899
1898
|
function create15(context) {
|
|
1900
1899
|
if (!context.sourceCode.text.includes("useFormState")) return {};
|
|
1901
|
-
const settings2 =
|
|
1902
|
-
if (
|
|
1900
|
+
const settings2 = getSettingsFromContext(context);
|
|
1901
|
+
if (compare(settings2.version, "19.0.0", "<")) return {};
|
|
1903
1902
|
const reactDomNames = /* @__PURE__ */ new Set();
|
|
1904
1903
|
const useFormStateNames = /* @__PURE__ */ new Set();
|
|
1905
1904
|
return {
|
|
1906
1905
|
CallExpression(node) {
|
|
1907
1906
|
switch (true) {
|
|
1908
|
-
case (node.callee.type ===
|
|
1907
|
+
case (node.callee.type === AST_NODE_TYPES.Identifier && useFormStateNames.has(node.callee.name)):
|
|
1909
1908
|
context.report({
|
|
1910
1909
|
messageId: "noUseFormState",
|
|
1911
1910
|
node,
|
|
1912
1911
|
fix: getFix3(context, node)
|
|
1913
1912
|
});
|
|
1914
1913
|
return;
|
|
1915
|
-
case (node.callee.type ===
|
|
1914
|
+
case (node.callee.type === AST_NODE_TYPES.MemberExpression && node.callee.object.type === AST_NODE_TYPES.Identifier && node.callee.property.type === AST_NODE_TYPES.Identifier && node.callee.property.name === "useFormState" && reactDomNames.has(node.callee.object.name)):
|
|
1916
1915
|
context.report({
|
|
1917
1916
|
messageId: "noUseFormState",
|
|
1918
1917
|
node,
|
|
@@ -1926,14 +1925,14 @@ function create15(context) {
|
|
|
1926
1925
|
if (baseSource !== "react-dom") return;
|
|
1927
1926
|
for (const specifier of node.specifiers) {
|
|
1928
1927
|
switch (specifier.type) {
|
|
1929
|
-
case
|
|
1930
|
-
if (specifier.imported.type !==
|
|
1928
|
+
case AST_NODE_TYPES.ImportSpecifier:
|
|
1929
|
+
if (specifier.imported.type !== AST_NODE_TYPES.Identifier) continue;
|
|
1931
1930
|
if (specifier.imported.name === "useFormState") {
|
|
1932
1931
|
useFormStateNames.add(specifier.local.name);
|
|
1933
1932
|
}
|
|
1934
1933
|
continue;
|
|
1935
|
-
case
|
|
1936
|
-
case
|
|
1934
|
+
case AST_NODE_TYPES.ImportDefaultSpecifier:
|
|
1935
|
+
case AST_NODE_TYPES.ImportNamespaceSpecifier:
|
|
1937
1936
|
reactDomNames.add(specifier.local.name);
|
|
1938
1937
|
continue;
|
|
1939
1938
|
}
|
|
@@ -1942,7 +1941,7 @@ function create15(context) {
|
|
|
1942
1941
|
};
|
|
1943
1942
|
}
|
|
1944
1943
|
function getFix3(context, node) {
|
|
1945
|
-
const { importSource } =
|
|
1944
|
+
const { importSource } = getSettingsFromContext(context);
|
|
1946
1945
|
return (fixer) => {
|
|
1947
1946
|
return [
|
|
1948
1947
|
fixer.insertTextBefore(context.sourceCode.ast, `import { useActionState } from "${importSource}";
|
|
@@ -2006,7 +2005,7 @@ function create16(context) {
|
|
|
2006
2005
|
}
|
|
2007
2006
|
const { attributes } = node.openingElement;
|
|
2008
2007
|
const initialScope = context.sourceCode.getScope(node);
|
|
2009
|
-
const hasAttribute3 = (name3) =>
|
|
2008
|
+
const hasAttribute3 = (name3) => ER.hasAttribute(context, name3, attributes, initialScope);
|
|
2010
2009
|
if (hasAttribute3("children") || hasAttribute3("dangerouslySetInnerHTML")) {
|
|
2011
2010
|
context.report({
|
|
2012
2011
|
messageId: "noVoidElementsWithChildren",
|
|
@@ -2042,10 +2041,7 @@ var plugin = {
|
|
|
2042
2041
|
"no-unsafe-iframe-sandbox": no_unsafe_iframe_sandbox_default,
|
|
2043
2042
|
"no-unsafe-target-blank": no_unsafe_target_blank_default,
|
|
2044
2043
|
"no-use-form-state": no_use_form_state_default,
|
|
2045
|
-
"no-void-elements-with-children": no_void_elements_with_children_default
|
|
2046
|
-
// Part: deprecated rules
|
|
2047
|
-
/** @deprecated Use `no-void-elements-with-children` instead */
|
|
2048
|
-
"no-children-in-void-dom-elements": no_void_elements_with_children_default
|
|
2044
|
+
"no-void-elements-with-children": no_void_elements_with_children_default
|
|
2049
2045
|
}
|
|
2050
2046
|
};
|
|
2051
2047
|
|
|
@@ -2072,4 +2068,4 @@ var index_default = {
|
|
|
2072
2068
|
}
|
|
2073
2069
|
};
|
|
2074
2070
|
|
|
2075
|
-
|
|
2071
|
+
export { index_default as default };
|