diff --git a/src/utilities/content-tree-enhancers.mjs b/src/utilities/content-tree-enhancers.mjs index f65ea262fa38..094b5ea91b5e 100644 --- a/src/utilities/content-tree-enhancers.mjs +++ b/src/utilities/content-tree-enhancers.mjs @@ -73,14 +73,16 @@ export const enhance = (tree, options) => { const isBlogItem = normalizedPath.includes("/blog/"); if (isBlogItem) { - const teaser = (body || "") + const teaserLines = (body || "") .split("\n") - .filter((line) => line.trim() && !line.trim().startsWith("#")) + .filter((line) => line.trim() && !line.trim().startsWith("#")); + const teaserText = teaserLines .slice(0, 3) .join(" ") - .replaceAll(/\[([^\]]+)\]\([^)]+\)/g, "$1") // Strip markdown links but keep text - .slice(0, 240); - tree.teaser = `${teaser}...`; + .replaceAll(/\[([^\]]+)\]\([^)]+\)/g, "$1"); // Strip markdown links but keep text + const teaser = teaserText.slice(0, 240); + const isTruncated = teaserLines.length > 3 || teaserText.length > 240; + tree.teaser = isTruncated ? `${teaser}...` : teaser; } Object.assign( diff --git a/src/utilities/content-tree-enhancers.test.mjs b/src/utilities/content-tree-enhancers.test.mjs index dfb7d12da696..e24eb28e7bb1 100644 --- a/src/utilities/content-tree-enhancers.test.mjs +++ b/src/utilities/content-tree-enhancers.test.mjs @@ -1,6 +1,9 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; // eslint-disable-next-line import/no-extraneous-dependencies import { describe, expect } from "@jest/globals"; -import { restructure } from "./content-tree-enhancers.mjs"; +import { enhance, restructure } from "./content-tree-enhancers.mjs"; describe("restructure", () => { it("applies filter result back to children array", () => { @@ -55,3 +58,41 @@ describe("restructure", () => { expect(root.children.map((item) => item.title)).toEqual(["API", "Guides"]); }); }); + +describe("enhance", () => { + const createBlogTree = (body) => { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "webpack-blog-")); + const blogDir = path.join(root, "blog"); + fs.mkdirSync(blogDir); + const filePath = path.join(blogDir, "example.mdx"); + fs.writeFileSync(filePath, `---\ntitle: Example\n---\n\n${body}`); + + return { + root, + tree: { + type: "file", + path: filePath, + extension: ".mdx", + name: "example.mdx", + }, + }; + }; + + it("does not append an ellipsis to an untruncated blog teaser", () => { + const { root, tree } = createBlogTree("Short body."); + + enhance(tree, { dir: root }); + + expect(tree.teaser).toBe("Short body."); + }); + + it("appends an ellipsis when the blog teaser is truncated", () => { + const { root, tree } = createBlogTree( + ["First line.", "Second line.", "Third line.", "Fourth line."].join("\n"), + ); + + enhance(tree, { dir: root }); + + expect(tree.teaser).toBe("First line. Second line. Third line...."); + }); +});