Skip to content

Commit

Permalink
fix(EmptyState): getChildrenText works on all kinds of children
Browse files Browse the repository at this point in the history
- previously the switch would unintentionally handle most cases under JSXText, as the first few whitespaces count as JSXText of children
  • Loading branch information
adamviktora committed Mar 5, 2024
1 parent 785f793 commit b86d424
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ ruleTester.run("emptyStateHeader-move-into-emptyState", rule, {
],
},
{
// without any EmptyStateHeader props but with children
// without any EmptyStateHeader props but with children as text
code: `import {
EmptyState,
EmptyStateHeader,
Expand Down Expand Up @@ -148,6 +148,112 @@ ruleTester.run("emptyStateHeader-move-into-emptyState", rule, {
},
],
},
{
// without any EmptyStateHeader props but with children as single JSXElement
code: `import {
EmptyState,
EmptyStateHeader,
} from "@patternfly/react-core";
export const EmptyStateHeaderMoveIntoEmptyStateInput = () => (
<EmptyState>
<EmptyStateHeader>
<h1>Foo bar</h1>
</EmptyStateHeader>
</EmptyState>
);
`,
output: `import {
EmptyState,
EmptyStateHeader,
} from "@patternfly/react-core";
export const EmptyStateHeaderMoveIntoEmptyStateInput = () => (
<EmptyState titleText={<h1>Foo bar</h1>}>
</EmptyState>
);
`,
errors: [
{
message: `EmptyStateHeader has been moved inside of the EmptyState component and is now only customizable using props, and the EmptyStateIcon component now wraps content passed to the icon prop automatically. Additionally, the titleText prop is now required on EmptyState.`,
type: "JSXElement",
},
],
},
{
// without any EmptyStateHeader props but with children as single JSXExpressionContainer
code: `import {
EmptyState,
EmptyStateHeader,
} from "@patternfly/react-core";
const title = "Some title";
export const EmptyStateHeaderMoveIntoEmptyStateInput = () => (
<EmptyState>
<EmptyStateHeader>
{title}
</EmptyStateHeader>
</EmptyState>
);
`,
output: `import {
EmptyState,
EmptyStateHeader,
} from "@patternfly/react-core";
const title = "Some title";
export const EmptyStateHeaderMoveIntoEmptyStateInput = () => (
<EmptyState titleText={title}>
</EmptyState>
);
`,
errors: [
{
message: `EmptyStateHeader has been moved inside of the EmptyState component and is now only customizable using props, and the EmptyStateIcon component now wraps content passed to the icon prop automatically. Additionally, the titleText prop is now required on EmptyState.`,
type: "JSXElement",
},
],
},
{
// without any EmptyStateHeader props but with children consisting of multiple elements
code: `import {
EmptyState,
EmptyStateHeader,
} from "@patternfly/react-core";
const title = "Some title";
export const EmptyStateHeaderMoveIntoEmptyStateInput = () => (
<EmptyState>
<EmptyStateHeader>
{title} followed by some text
</EmptyStateHeader>
</EmptyState>
);
`,
output: `import {
EmptyState,
EmptyStateHeader,
} from "@patternfly/react-core";
const title = "Some title";
export const EmptyStateHeaderMoveIntoEmptyStateInput = () => (
<EmptyState titleText={<>
{title} followed by some text
</>}>
</EmptyState>
);
`,
errors: [
{
message: `EmptyStateHeader has been moved inside of the EmptyState component and is now only customizable using props, and the EmptyStateIcon component now wraps content passed to the icon prop automatically. Additionally, the titleText prop is now required on EmptyState.`,
type: "JSXElement",
},
],
},
{
// without an EmptyStateHeader or titleText
code: `import { EmptyState } from "@patternfly/react-core";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,28 +101,33 @@ module.exports = {
.join("");
};

const getElementChildText = (children: JSXElement["children"]) => {
const getChildrenText = (children: JSXElement["children"]) => {
if (!children.length) {
return "";
}

switch (children[0].type) {
case "JSXText":
return (children as JSXText[]).map((child) => child.value).join("");
case "JSXExpressionContainer":
case "JSXSpreadChild":
return getNodesText(
children.map(
(child) =>
(child as JSXExpressionContainer | JSXSpreadChild).expression
)
if (children.length === 1 && children[0].type === "JSXText") {
return `"${children[0].value.trim()}"`;
}

const potentialSingleChild = children.filter(
(child) => !(child.type === "JSXText" && child.value.trim() === "")
);

if (potentialSingleChild.length === 1) {
const singleChild = potentialSingleChild[0];
const singleChildText = context
.getSourceCode()
.getText(
singleChild as JSXExpressionContainer | JSXElement | JSXFragment
);
case "JSXElement":
case "JSXFragment":
return getNodesText(children as JSXElement[] | JSXFragment[]);
default:
return "";

return singleChild.type === "JSXExpressionContainer"
? singleChildText
: `{${singleChildText}}`;
}

return `{<>${getNodesText(children as Node[])}</>}`;
};

return {
Expand Down Expand Up @@ -182,8 +187,7 @@ module.exports = {
const titleTextPropValue = getAttributeText(titleTextAttribute);

const titleText =
titleTextPropValue ||
`titleText="${getElementChildText(headerChildren)}"`;
titleTextPropValue || `titleText=${getChildrenText(headerChildren)}`;

const iconPropValue = getExpressionValue(headerIconAttribute?.value);

Expand Down

0 comments on commit b86d424

Please sign in to comment.