Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions lib/util/hasTextContentChild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { TSESTree } from "@typescript-eslint/types";

/**
* hasTextContentChild - determines if a component has text content as a child e.g. <Button>Hello</Button>
* hasTextContentChild - determines if a component has text content as a child, e.g., <Button>Hello</Button>, <Button>{'Hello'}</Button>, <Button>{myFunc()}</Button>, or <Button>{myVar}</Button>
* @param {*} node JSXElement
* @returns boolean
*/
Expand All @@ -14,12 +14,28 @@ const hasTextContentChild = (node?: TSESTree.JSXElement) => {
return false;
}

if (node.children == null || node.children == undefined || node.children.length === 0) {
if (!node.children || node.children.length === 0) {
return false;
}

const result = node.children.filter(element => {
return element.type === "JSXText" && element.value.trim().length > 0;
// Check for JSXText with non-whitespace content
if (element.type === "JSXText" && element.value.trim().length > 0) {
return true;
}

// Check for JSXExpressionContainer with valid expression content
if (
element.type === "JSXExpressionContainer" &&
element.expression &&
((element.expression.type === "Literal" && String(element.expression.value).trim().length > 0) ||
element.expression.type === "CallExpression" ||
element.expression.type === "Identifier")
) {
return true;
}

return false;
});

return result.length !== 0;
Expand Down
30 changes: 29 additions & 1 deletion tests/lib/rules/utils/hasTextContentChild.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe("hasTextContentChild", () => {
expect(hasTextContentChild(node)).toBe(false);
});

it("should return false when node.children has no JSXText elements with non-whitespace content", () => {
it("should return false when node.children has no JSXText or relevant JSXExpressionContainer content", () => {
const node: TSESTree.JSXElement = {
children: [{ type: "JSXElement" }, { type: "JSXExpressionContainer" }]
} as any;
Expand All @@ -42,4 +42,32 @@ describe("hasTextContentChild", () => {
} as any;
expect(hasTextContentChild(node)).toBe(false);
});

it("should return true when node.children has JSXExpressionContainer with a literal string", () => {
const node: TSESTree.JSXElement = {
children: [{ type: "JSXExpressionContainer", expression: { type: "Literal", value: "Hello" } }]
} as any;
expect(hasTextContentChild(node)).toBe(true);
});

it("should return true when node.children has JSXExpressionContainer with a function call", () => {
const node: TSESTree.JSXElement = {
children: [{ type: "JSXExpressionContainer", expression: { type: "CallExpression", callee: { name: "myFunc" } } }]
} as any;
expect(hasTextContentChild(node)).toBe(true);
});

it("should return true when node.children has JSXExpressionContainer with an identifier (variable)", () => {
const node: TSESTree.JSXElement = {
children: [{ type: "JSXExpressionContainer", expression: { type: "Identifier", name: "myVar" } }]
} as any;
expect(hasTextContentChild(node)).toBe(true);
});

it("should return false when node.children has JSXExpressionContainer with an empty string literal", () => {
const node: TSESTree.JSXElement = {
children: [{ type: "JSXExpressionContainer", expression: { type: "Literal", value: "" } }]
} as any;
expect(hasTextContentChild(node)).toBe(false);
});
});
Loading