Skip to content

Commit b1a8028

Browse files
authored
feat: add 'settings["react-x"].additionalComponents' to support user-defined components that add the "rel" attribute internally, closes #641 (#653)
1 parent 7c5f399 commit b1a8028

25 files changed

+280
-103
lines changed

eslint.config.mts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,9 @@ const config: FlatConfig[] = [
165165
"title",
166166
"description",
167167
],
168+
alias: ["alias", "as"],
168169
},
169-
groups: ["id", "type", "meta", "unknown"],
170+
groups: ["id", "type", "meta", "alias", "unknown"],
170171
order: "asc",
171172
},
172173
],
@@ -183,8 +184,9 @@ const config: FlatConfig[] = [
183184
"title",
184185
"description",
185186
],
187+
alias: ["alias", "as"],
186188
},
187-
groups: ["id", "type", "meta", "unknown"],
189+
groups: ["id", "type", "meta", "alias", "unknown"],
188190
order: "asc",
189191
"partition-by-comment": "Part:**",
190192
},

packages/core/src/element/misc.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { NodeType } from "@eslint-react/ast";
2-
import { getESLintReactSettings } from "@eslint-react/shared";
2+
import { parseESLintSettings } from "@eslint-react/shared";
33
import type { RuleContext } from "@eslint-react/types";
44
import type { TSESTree } from "@typescript-eslint/types";
55

@@ -12,7 +12,7 @@ import { isInitializedFromReact } from "../internal";
1212
* @returns `true` if the node is a fragment element, `false` otherwise
1313
*/
1414
export function isFragmentElement(node: TSESTree.JSXElement, context: RuleContext) {
15-
const { jsxPragma = "React", jsxPragmaFrag = "Fragment" } = getESLintReactSettings(context.settings);
15+
const { jsxPragma = "React", jsxPragmaFrag = "Fragment" } = parseESLintSettings(context.settings)["react-x"] ?? {};
1616
const { name } = node.openingElement;
1717
// <Fragment>
1818
if (name.type === NodeType.JSXIdentifier && name.name === jsxPragmaFrag) return true;

packages/core/src/internal/is-from-react.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { is, isOneOf, NodeType } from "@eslint-react/ast";
2-
import { getESLintReactSettings } from "@eslint-react/shared";
2+
import { parseESLintSettings } from "@eslint-react/shared";
33
import { O, Pred } from "@eslint-react/tools";
44
import type { RuleContext } from "@eslint-react/types";
55
import { findVariable } from "@eslint-react/var";
@@ -18,7 +18,7 @@ export function isInitializedFromReact(
1818
if (O.isNone(maybeLatestDef)) return false;
1919
const latestDef = maybeLatestDef.value;
2020
const { node, parent } = latestDef;
21-
const settings = getESLintReactSettings(context.settings);
21+
const settings = parseESLintSettings(context.settings)["react-x"] ?? {};
2222
const importSource = settings.importSource ?? "react";
2323
if (node.type === NodeType.VariableDeclarator && node.init) {
2424
const { init } = node;

packages/plugins/eslint-plugin-react-dom/src/rules/no-children-in-void-dom-elements.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NodeType } from "@eslint-react/ast";
1+
import { isOneOf, NodeType } from "@eslint-react/ast";
22
import { isCreateElementCall } from "@eslint-react/core";
33
import { findPropInAttributes, findPropInProperties } from "@eslint-react/jsx";
44
import { O } from "@eslint-react/tools";
@@ -30,6 +30,7 @@ const voidElements = new Set([
3030
"wbr",
3131
]);
3232

33+
// TODO: Use the information in `settings["react-x"].additionalComponents` to add support for user-defined components that use the void element internally
3334
export default createRule<[], MessageID>({
3435
meta: {
3536
type: "problem",
@@ -45,12 +46,7 @@ export default createRule<[], MessageID>({
4546
create(context) {
4647
return {
4748
CallExpression(node) {
48-
if (
49-
node.callee.type !== NodeType.MemberExpression
50-
&& node.callee.type !== NodeType.Identifier
51-
) {
52-
return;
53-
}
49+
if (!isOneOf([NodeType.MemberExpression, NodeType.Identifier])(node.callee)) return;
5450
const initialScope = context.sourceCode.getScope(node);
5551
if (!isCreateElementCall(node, context)) return;
5652
const args = node.arguments;
@@ -103,9 +99,8 @@ export default createRule<[], MessageID>({
10399
}
104100
const { attributes } = node.openingElement;
105101
const initialScope = context.sourceCode.getScope(node);
106-
const findAttr = findPropInAttributes(attributes, context, initialScope);
107-
const hasChildrenOrDangerAttr = O.isSome(findAttr("children"))
108-
|| O.isSome(findAttr("dangerouslySetInnerHTML"));
102+
const hasAttr = (name: string) => O.isSome(findPropInAttributes(attributes, context, initialScope)(name));
103+
const hasChildrenOrDangerAttr = hasAttr("children") || hasAttr("dangerouslySetInnerHTML");
109104
if (hasChildrenOrDangerAttr) {
110105
// e.g. <br children="Foo" />
111106
context.report({

packages/plugins/eslint-plugin-react-dom/src/rules/no-dangerously-set-innerhtml-with-children.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ function firstChildIsText(node: TSESTree.JSXElement) {
2121
&& !isLineBreak(firstChild);
2222
}
2323

24+
// TODO: Use the information in `settings["react-x"].additionalComponents` to add support for user-defined components that use different properties to receive HTML and set them internally.
2425
export default createRule<[], MessageID>({
2526
meta: {
2627
type: "problem",

packages/plugins/eslint-plugin-react-dom/src/rules/no-dangerously-set-innerhtml.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const RULE_NAME = "no-dangerously-set-innerhtml";
1313

1414
export type MessageID = ConstantCase<typeof RULE_NAME>;
1515

16+
// TODO: Use the information in `settings["react-x"].additionalComponents` to add support for user-defined components that use different properties to receive HTML and set them internally.
1617
export default createRule<[], MessageID>({
1718
meta: {
1819
type: "problem",

packages/plugins/eslint-plugin-react-dom/src/rules/no-missing-button-type.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,30 @@ ruleTester.run(RULE_NAME, rule, {
8686
return <button {...props}>Click me</button>;
8787
}
8888
`,
89+
// TODO: implement this
90+
// {
91+
// code: /* tsx */ `
92+
// function App() {
93+
// return <Button>Click me</Button>;
94+
// }
95+
// `,
96+
// settings: {
97+
// "react-x": {
98+
// additionalComponents: [
99+
// {
100+
// name: "Button",
101+
// as: "button",
102+
// attributes: [
103+
// {
104+
// name: "type",
105+
// as: "type",
106+
// defaultValue: "button",
107+
// },
108+
// ],
109+
// },
110+
// ],
111+
// },
112+
// },
113+
// },
89114
],
90115
});

packages/plugins/eslint-plugin-react-dom/src/rules/no-missing-button-type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const RULE_NAME = "no-missing-button-type";
1212

1313
export type MessageID = ConstantCase<typeof RULE_NAME>;
1414

15+
// TODO: Use the information in `settings["react-x"].additionalComponents` to add support for user-defined components
1516
export default createRule<[], MessageID>({
1617
meta: {
1718
type: "problem",

packages/plugins/eslint-plugin-react-dom/src/rules/no-missing-iframe-sandbox.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const validTypes = [
3030
"allow-top-navigation-to-custom-protocols",
3131
] as const;
3232

33+
// TODO: Use the information in `settings["react-x"].additionalComponents` to add support for user-defined components that add the 'sandbox' attribute internally.
3334
export default createRule<[], MessageID>({
3435
meta: {
3536
type: "problem",

packages/plugins/eslint-plugin-react-dom/src/rules/no-unsafe-iframe-sandbox.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const unsafeCombinations = [
1717
// ...
1818
] as const;
1919

20+
// TODO: Use the information in `settings["react-x"].additionalComponents` to add support for user-defined components that add the 'sandbox' attribute internally.
2021
export default createRule<[], MessageID>({
2122
meta: {
2223
type: "problem",

0 commit comments

Comments
 (0)