diff --git a/src/components/Utils/utils.test.ts b/src/components/Utils/utils.test.ts new file mode 100644 index 0000000..8861a92 --- /dev/null +++ b/src/components/Utils/utils.test.ts @@ -0,0 +1,43 @@ +import { parseLinks } from "./utils"; + +describe("Parsing lines with links", () => { + it("should be able to parse links wrapped in parentheses.", () => { + const lines = [ + { + text: "(https://example.com)", + }, + ]; + const links = parseLinks(lines); + expect(links.length).toBe(4); + expect(links[0]?.text).toBeFalsy(); + expect(links[1]?.text).toBe("("); + expect(links[2]?.text?.endsWith(")")).toBeFalsy(); + expect(links[3]?.text).toBe(")"); + }); + + it("should be able to parse links starting with a parenthesis.", () => { + const lines = [ + { + text: "(https://example.com", + }, + ]; + const links = parseLinks(lines); + expect(links.length).toBe(3); + expect(links[0]?.text).toBeFalsy(); + expect(links[1]?.text).toBe("("); + expect(links[2]?.text?.endsWith(")")).toBeFalsy(); + }); + + it("should be able to parse links with a trailing parenthesis.", () => { + const lines = [ + { + text: "https://example.com)", + }, + ]; + const links = parseLinks(lines); + expect(links.length).toBe(3); + expect(links[0]?.text).toBeFalsy(); + expect(links[1]?.text?.endsWith(")")).toBeFalsy(); + expect(links[2]?.text).toBe(")"); + }); +}); diff --git a/src/components/Utils/utils.ts b/src/components/Utils/utils.ts index f52256f..460422d 100644 --- a/src/components/Utils/utils.ts +++ b/src/components/Utils/utils.ts @@ -262,57 +262,46 @@ export const parseLinks = (lines: any[]): LinePartCss[] => { lines.forEach((line) => { // Split line into words - const arr = line.text.split(" "); + const tokens = line.text.split(" "); let found = false; // Tracks if any links were found let partial = ""; // Accumulates non-link text - arr.forEach((text: string) => { + tokens.forEach((token: string) => { // Check if text matches URL pattern - if (text.search(strictUrlRegex) > -1) { + if (token.search(strictUrlRegex) > -1) { // Push accumulated non-link text if any result.push({ text: partial.trimEnd() }); partial = ""; found = true; // Check if text is an email address - if (text.search(emailRegex) > -1) { - result.push({ text, email: true }); + if (token.search(emailRegex) > -1) { + result.push({ token, email: true }); return; } // Add https:// prefix if protocol is missing - if (text.search(protocolClause) === -1) { - result.push({ text: `https://${text}`, link: true }); + if (token.search(protocolClause) === -1) { + result.push({ text: `https://${token}`, link: true }); return; } // Split text into protocol and non-protocol parts - const parts = text.split(new RegExp(`(${protocolClause}.*)`)); - if (parts.length > 1) { - // Push non-link part if it exists - if (parts[0]) { - result.push({ - text: parts[0], - }); + const parts = token.split(new RegExp(/(\()*([^\)]+)(\))*/)).filter(Boolean); + parts.forEach((part) => { + if (part.search(protocolClause) > -1) { + result.push({ text: part, link: true }); + } else { + result.push({ text: part }); } - // Push link part - result.push({ - text: parts[1], - link: true, - }); - } else { - result.push({ - text, - link: true, - }); - } + }); return; } // Accumulate non-link text - partial += text + " "; + partial += token + " "; }); // If no links found, push the entire line